diff --git a/README-zh.md b/README-zh.md index 5305b0d04ec7b222d1b9e6a475c163d1d81460e1..7d8e55fe4a5839db183f4a0701afa00b4a8f127c 100644 --- a/README-zh.md +++ b/README-zh.md @@ -73,18 +73,78 @@ ```bash # 克隆项目 git clone https://github.com/iflytek/astron-agent.git -cd astron-agent -# 启动 Casdoor 身份认证服务 -cd docker/casdoor -docker-compose up -d +# 进入 astronAgent 目录 +cd docker/astronAgent -# 启动 AstronAgent 核心服务 -cd ../astronAgent -docker compose up -d +# 复制环境变量配置 +cp .env.example .env + +# 编辑环境变量配置 +vim .env +``` + +#### 配置 讯飞开放平台 相关 APP_ID API_KEY 等信息 + +获取文档详见:https://www.xfyun.cn/doc/platform/quickguide.html + +创建应用完成后可能需要购买或领取相应能力的API授权服务量 +- 星火大模型API: https://xinghuo.xfyun.cn/sparkapi + (对于大模型API会有额外的SPARK_API_PASSWORD需要在页面上获取) + (指令型助手对应的文本AI生成/优化功能需要开通Spark Ultra能力,页面地址为https://console.xfyun.cn/services/bm4) +- 实时语音转写API: https://console.xfyun.cn/services/rta +- 图片生成API: https://www.xfyun.cn/services/wtop + +编辑 docker/astronAgent/.env 文件,更新相关环境变量: +```env +PLATFORM_APP_ID=your-app-id +PLATFORM_API_KEY=your-api-key +PLATFORM_API_SECRET=your-api-secret + +SPARK_API_PASSWORD=your-api-password +SPARK_RTASR_API_KEY=your-rtasr-api-key +``` + +#### 配置服务主机地址 + +编辑 docker/astronAgent/.env 文件,配置 AstronAgent 服务的主机地址: + +```env +HOST_BASE_ADDRESS=http://localhost ``` -访问平台:http://localhost/ +**说明:** +- 如果您使用域名访问,请将 `localhost` 替换为您的域名 +- 确保 nginx 和 minio 的端口已正确开放 + +#### 启动项目 + +```bash +# 进入 astronAgent 目录 +cd docker/astronAgent + +# 启动所有服务(包含 Casdoor) +docker compose -f docker-compose-with-auth.yaml up -d + +# 查看服务状态 +docker compose ps + +# 查看服务日志 +docker compose logs -f +``` + +#### 📊 服务访问地址 + +启动完成后,您可以通过以下地址访问各项服务: + +**认证服务** +- **Casdoor 管理界面**:http://localhost:8000 + +**AstronAgent** +- **应用前端(nginx代理)**:http://localhost/ + +**说明** +- Casdoor默认的登录账户名:`admin`,密码:`123` ### 方式二:Helm(适用于 Kubernetes 环境) diff --git a/console/backend/commons/src/main/java/com/iflytek/astron/console/commons/dto/workflow/MaasApi.java b/console/backend/commons/src/main/java/com/iflytek/astron/console/commons/dto/workflow/MaasApi.java index 8e0e0d2db7e87ab2bba945ddd8cd365811befd7e..cb74ac18490f562978f7c673dd09261e53aa6953 100644 --- a/console/backend/commons/src/main/java/com/iflytek/astron/console/commons/dto/workflow/MaasApi.java +++ b/console/backend/commons/src/main/java/com/iflytek/astron/console/commons/dto/workflow/MaasApi.java @@ -30,7 +30,7 @@ public class MaasApi { this.flow_id = flow_id; this.app_id = app_id; this.release_status = 1; - this.plat = 2; + this.plat = 1; } public MaasApi(String flow_id, String app_id, String version) { @@ -38,7 +38,7 @@ public class MaasApi { this.app_id = app_id; this.version = version; this.release_status = 1; - this.plat = 2; + this.plat = 1; } public MaasApi(String flow_id, String app_id, String version, JSONObject data) { @@ -46,7 +46,7 @@ public class MaasApi { this.app_id = app_id; this.version = version; this.release_status = 1; - this.plat = 2; + this.plat = 1; this.data = data; } } diff --git a/console/backend/commons/src/main/java/com/iflytek/astron/console/commons/util/MaasUtil.java b/console/backend/commons/src/main/java/com/iflytek/astron/console/commons/util/MaasUtil.java index 361108d63990b039e581b1c5ac328ee57fc90efd..e6cf2b8046d8e59a0ee7b97145b02797bb2dd21e 100644 --- a/console/backend/commons/src/main/java/com/iflytek/astron/console/commons/util/MaasUtil.java +++ b/console/backend/commons/src/main/java/com/iflytek/astron/console/commons/util/MaasUtil.java @@ -398,7 +398,8 @@ public class MaasUtil { */ private JSONObject createApiInternal(String flowId, String appid, String version, JSONObject data) { log.info("----- Publishing maas workflow flowId: {}", flowId); - MaasApi maasApi = new MaasApi(flowId, appid, version, data); + // Create MaasApi without data parameter for publish request + MaasApi maasApi = new MaasApi(flowId, appid, version); // Execute publish request String publishResponse = executeRequest(publishApi, maasApi); diff --git a/console/backend/commons/src/main/java/com/iflytek/astron/console/commons/util/S3ClientUtil.java b/console/backend/commons/src/main/java/com/iflytek/astron/console/commons/util/S3ClientUtil.java index 40c96b018fb8b8046d7a7e68e8691a5c8e813df4..0473faa2c5f6edbfd247f8687215e348441e5e38 100644 --- a/console/backend/commons/src/main/java/com/iflytek/astron/console/commons/util/S3ClientUtil.java +++ b/console/backend/commons/src/main/java/com/iflytek/astron/console/commons/util/S3ClientUtil.java @@ -36,6 +36,9 @@ public class S3ClientUtil { @Value("${s3.endpoint}") private String endpoint; + @Value("${s3.remoteEndpoint}") + private String remoteEndpoint; + @Value("${s3.accessKey}") private String accessKey; @@ -59,6 +62,9 @@ public class S3ClientUtil { public void init() { this.minioClient = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build(); + log.info("Minio config - endpoint: {}, remoteEndpoint: {}, defaultBucket: {}, presignExpirySeconds: {}, enablePublicRead: {}", + endpoint, remoteEndpoint, defaultBucket, presignExpirySeconds, enablePublicRead); + // Check if default bucket exists, create if not try { boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(defaultBucket).build()); @@ -151,7 +157,21 @@ public class S3ClientUtil { * @return full object URL */ private String buildObjectUrl(String bucketName, String objectKey) { - return String.format("%s/%s/%s", endpoint, bucketName, objectKey); + return String.format("%s/%s/%s", remoteEndpoint, bucketName, objectKey); + } + + /** + * Replace endpoint with remoteEndpoint in presigned URL. MinIO client generates URLs using the + * internal endpoint, but we need to return URLs with the public remoteEndpoint. + * + * @param presignedUrl presigned URL generated by MinIO client + * @return presigned URL with remoteEndpoint + */ + private String replaceEndpointInPresignedUrl(String presignedUrl) { + if (presignedUrl != null && presignedUrl.startsWith(endpoint)) { + return remoteEndpoint + presignedUrl.substring(endpoint.length()); + } + return presignedUrl; } /** @@ -235,7 +255,8 @@ public class S3ClientUtil { */ public String generatePresignedPutUrl(String bucketName, String objectKey, int expirySeconds) { try { - return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.PUT).bucket(bucketName).object(objectKey).expiry(expirySeconds).build()); + String presignedUrl = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.PUT).bucket(bucketName).object(objectKey).expiry(expirySeconds).build()); + return replaceEndpointInPresignedUrl(presignedUrl); } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | XmlParserException | ServerException e) { log.error("S3 error on presign PUT for bucket '{}', object '{}': {}", bucketName, objectKey, e.getMessage(), e); throw new BusinessException(ResponseEnum.S3_PRESIGN_ERROR); @@ -262,13 +283,14 @@ public class S3ClientUtil { */ public String generatePresignedGetUrl(String bucketName, String objectKey, int expirySeconds) { try { - return minioClient.getPresignedObjectUrl( + String presignedUrl = minioClient.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() .method(Method.GET) .bucket(bucketName) .object(objectKey) .expiry(expirySeconds) .build()); + return replaceEndpointInPresignedUrl(presignedUrl); } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | XmlParserException | ServerException e) { log.error("S3 error on presign GET for bucket '{}', object '{}': {}", bucketName, objectKey, e.getMessage(), e); throw new BusinessException(ResponseEnum.S3_PRESIGN_ERROR); diff --git a/console/backend/commons/src/test/java/com/iflytek/astron/console/commons/util/S3ClientUtilTest.java b/console/backend/commons/src/test/java/com/iflytek/astron/console/commons/util/S3ClientUtilTest.java index c19835d8ac58155a44e4290f36d5f0646a694285..3f15fe68b786b8b879cf64da9300bbd3085578c3 100644 --- a/console/backend/commons/src/test/java/com/iflytek/astron/console/commons/util/S3ClientUtilTest.java +++ b/console/backend/commons/src/test/java/com/iflytek/astron/console/commons/util/S3ClientUtilTest.java @@ -25,7 +25,8 @@ import org.springframework.test.util.ReflectionTestUtils; * * Test configuration: - MinIO connection details configurable via environment variables Environment * variables: - MINIO_TEST_ENDPOINT: MinIO server endpoint (default: http://localhost:9000) - - * MINIO_TEST_ACCESS_KEY: Access key for authentication (default: minioadmin) - + * MINIO_TEST_REMOTE_ENDPOINT: Remote endpoint for external access (default: http://localhost:9000) + * - MINIO_TEST_ACCESS_KEY: Access key for authentication (default: minioadmin) - * MINIO_TEST_SECRET_KEY: Secret key for authentication (default: minioadmin) - MINIO_TEST_BUCKET: * Bucket name for testing (default: astron-project) - MINIO_INVALID_ACCESS_KEY: Invalid access key * for negative testing (default: invalid-user) - MINIO_INVALID_SECRET_KEY: Invalid secret key for @@ -38,7 +39,9 @@ class S3ClientUtilTest { private S3ClientUtil s3ClientUtil; // MinIO test environment configuration - from environment variables + // Use different values for endpoint and remoteEndpoint to test URL replacement logic private static final String TEST_ENDPOINT = System.getenv().getOrDefault("MINIO_TEST_ENDPOINT", "http://localhost:9000"); + private static final String TEST_REMOTE_ENDPOINT = System.getenv().getOrDefault("MINIO_TEST_REMOTE_ENDPOINT", "http://external-minio.example.com:9000"); private static final String TEST_ACCESS_KEY = System.getenv().getOrDefault("MINIO_TEST_ACCESS_KEY", "minioadmin"); private static final String TEST_SECRET_KEY = System.getenv().getOrDefault("MINIO_TEST_SECRET_KEY", "minioadmin"); private static final String TEST_BUCKET = System.getenv().getOrDefault("MINIO_TEST_BUCKET", "astron-project"); @@ -77,6 +80,7 @@ class S3ClientUtilTest { // Use real MinIO test environment configuration ReflectionTestUtils.setField(s3ClientUtil, "endpoint", TEST_ENDPOINT); + ReflectionTestUtils.setField(s3ClientUtil, "remoteEndpoint", TEST_REMOTE_ENDPOINT); ReflectionTestUtils.setField(s3ClientUtil, "accessKey", TEST_ACCESS_KEY); ReflectionTestUtils.setField(s3ClientUtil, "secretKey", TEST_SECRET_KEY); ReflectionTestUtils.setField(s3ClientUtil, "defaultBucket", TEST_BUCKET); @@ -143,7 +147,7 @@ class S3ClientUtilTest { String result = s3ClientUtil.uploadObject(TEST_BUCKET, objectKey, contentType, inputStream, testContent.length, -1); // Verify returned URL format is correct - String expectedUrl = TEST_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; + String expectedUrl = TEST_REMOTE_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; Assertions.assertEquals(expectedUrl, result); } @@ -159,7 +163,7 @@ class S3ClientUtilTest { String result = s3ClientUtil.uploadObject(TEST_BUCKET, objectKey, null, inputStream, testContent.length, -1); // Verify returned URL - String expectedUrl = TEST_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; + String expectedUrl = TEST_REMOTE_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; Assertions.assertEquals(expectedUrl, result); } @@ -175,7 +179,7 @@ class S3ClientUtilTest { String result = s3ClientUtil.uploadObject(TEST_BUCKET, objectKey, "", inputStream, testContent.length, -1); // Verify returned URL - String expectedUrl = TEST_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; + String expectedUrl = TEST_REMOTE_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; Assertions.assertEquals(expectedUrl, result); } @@ -185,6 +189,7 @@ class S3ClientUtilTest { // Create an S3ClientUtil using invalid credentials S3ClientUtil invalidS3ClientUtil = new S3ClientUtil(); ReflectionTestUtils.setField(invalidS3ClientUtil, "endpoint", TEST_ENDPOINT); + ReflectionTestUtils.setField(invalidS3ClientUtil, "remoteEndpoint", TEST_REMOTE_ENDPOINT); ReflectionTestUtils.setField(invalidS3ClientUtil, "accessKey", INVALID_ACCESS_KEY); ReflectionTestUtils.setField(invalidS3ClientUtil, "secretKey", INVALID_SECRET_KEY); ReflectionTestUtils.setField(invalidS3ClientUtil, "defaultBucket", TEST_BUCKET); @@ -221,7 +226,7 @@ class S3ClientUtilTest { // Verify result contains necessary components Assertions.assertNotNull(actualUrl); - Assertions.assertTrue(actualUrl.startsWith(TEST_ENDPOINT)); + Assertions.assertTrue(actualUrl.startsWith(TEST_REMOTE_ENDPOINT)); Assertions.assertTrue(actualUrl.contains(TEST_BUCKET)); Assertions.assertTrue(actualUrl.contains(objectKey)); Assertions.assertTrue(actualUrl.contains("X-Amz-Algorithm=AWS4-HMAC-SHA256")); @@ -233,6 +238,7 @@ class S3ClientUtilTest { // Create an S3ClientUtil using invalid credentials S3ClientUtil invalidS3ClientUtil = new S3ClientUtil(); ReflectionTestUtils.setField(invalidS3ClientUtil, "endpoint", TEST_ENDPOINT); + ReflectionTestUtils.setField(invalidS3ClientUtil, "remoteEndpoint", TEST_REMOTE_ENDPOINT); ReflectionTestUtils.setField(invalidS3ClientUtil, "accessKey", INVALID_ACCESS_KEY); ReflectionTestUtils.setField(invalidS3ClientUtil, "secretKey", INVALID_SECRET_KEY); ReflectionTestUtils.setField(invalidS3ClientUtil, "defaultBucket", TEST_BUCKET); @@ -289,7 +295,7 @@ class S3ClientUtilTest { String result = s3ClientUtil.uploadObject(objectKey, contentType, inputStream, testContent.length, -1); // Verify returned URL - String expectedUrl = TEST_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; + String expectedUrl = TEST_REMOTE_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; Assertions.assertEquals(expectedUrl, result); } @@ -304,7 +310,7 @@ class S3ClientUtilTest { // Verify result Assertions.assertNotNull(actualUrl); - Assertions.assertTrue(actualUrl.startsWith(TEST_ENDPOINT)); + Assertions.assertTrue(actualUrl.startsWith(TEST_REMOTE_ENDPOINT)); Assertions.assertTrue(actualUrl.contains(TEST_BUCKET)); Assertions.assertTrue(actualUrl.contains(objectKey)); Assertions.assertTrue(actualUrl.contains("X-Amz-Algorithm=AWS4-HMAC-SHA256")); @@ -322,7 +328,7 @@ class S3ClientUtilTest { String result = s3ClientUtil.uploadObject(TEST_BUCKET, objectKey, contentType, data); // Verify returned URL - String expectedUrl = TEST_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; + String expectedUrl = TEST_REMOTE_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; Assertions.assertEquals(expectedUrl, result); } @@ -338,7 +344,7 @@ class S3ClientUtilTest { String result = s3ClientUtil.uploadObject(TEST_BUCKET, objectKey, contentType, inputStream); // Verify returned URL - String expectedUrl = TEST_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; + String expectedUrl = TEST_REMOTE_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; Assertions.assertEquals(expectedUrl, result); } @@ -354,7 +360,7 @@ class S3ClientUtilTest { String result = s3ClientUtil.uploadObject(objectKey, contentType, data); // Verify returned URL - String expectedUrl = TEST_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; + String expectedUrl = TEST_REMOTE_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; Assertions.assertEquals(expectedUrl, result); } @@ -370,7 +376,7 @@ class S3ClientUtilTest { String result = s3ClientUtil.uploadObject(objectKey, contentType, inputStream); // Verify returned URL - String expectedUrl = TEST_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; + String expectedUrl = TEST_REMOTE_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; Assertions.assertEquals(expectedUrl, result); } @@ -417,17 +423,20 @@ class S3ClientUtilTest { // Execute upload String generatedUrl = s3ClientUtil.uploadObject(TEST_BUCKET, objectKey, contentType, inputStream, testContentBytes.length, -1); - // Verify URL format - String expectedUrl = TEST_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; + // Verify URL format (should be remote endpoint) + String expectedUrl = TEST_REMOTE_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; Assertions.assertEquals(expectedUrl, generatedUrl); + // For testing actual access, use internal endpoint if remote endpoint is not accessible + String accessUrl = TEST_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; + // Verify if URL is accessible - Assertions.assertTrue(isUrlAccessible(generatedUrl), - "Generated URL should be accessible: " + generatedUrl); + Assertions.assertTrue(isUrlAccessible(accessUrl), + "Generated URL should be accessible: " + accessUrl); // Verify correct content can be read through URL try { - String downloadedContent = readFromUrl(generatedUrl); + String downloadedContent = readFromUrl(accessUrl); Assertions.assertEquals(testContent, downloadedContent, "Content downloaded via URL should match uploaded content"); } catch (IOException e) { @@ -447,17 +456,20 @@ class S3ClientUtilTest { // Execute test String generatedUrl = s3ClientUtil.uploadObject(TEST_BUCKET, objectKey, contentType, data); - // Verify URL format - String expectedUrl = TEST_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; + // Verify URL format (should be remote endpoint) + String expectedUrl = TEST_REMOTE_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; Assertions.assertEquals(expectedUrl, generatedUrl); + // For testing actual access, use internal endpoint if remote endpoint is not accessible + String accessUrl = TEST_ENDPOINT + "/" + TEST_BUCKET + "/" + objectKey; + // Verify if URL is accessible - Assertions.assertTrue(isUrlAccessible(generatedUrl), - "Generated URL should be accessible: " + generatedUrl); + Assertions.assertTrue(isUrlAccessible(accessUrl), + "Generated URL should be accessible: " + accessUrl); // Verify correct content can be read through URL try { - String downloadedContent = readFromUrl(generatedUrl); + String downloadedContent = readFromUrl(accessUrl); Assertions.assertEquals(testContent, downloadedContent, "Content downloaded via URL should match uploaded content"); } catch (IOException e) { @@ -476,15 +488,20 @@ class S3ClientUtilTest { // Generate presigned URL String presignedUrl = s3ClientUtil.generatePresignedPutUrl(TEST_BUCKET, objectKey, 600); - // Verify presigned URL format + // Verify presigned URL format (should use TEST_REMOTE_ENDPOINT) Assertions.assertNotNull(presignedUrl); - Assertions.assertTrue(presignedUrl.startsWith(TEST_ENDPOINT)); + Assertions.assertTrue(presignedUrl.startsWith(TEST_REMOTE_ENDPOINT)); Assertions.assertTrue(presignedUrl.contains(TEST_BUCKET)); Assertions.assertTrue(presignedUrl.contains(objectKey)); Assertions.assertTrue(presignedUrl.contains("X-Amz-Algorithm=AWS4-HMAC-SHA256")); + // For actual upload testing, replace remote endpoint with internal endpoint + // This simulates the scenario where the remote endpoint is public-facing + // but we're testing from internal network + String actualUploadUrl = presignedUrl.replace(TEST_REMOTE_ENDPOINT, TEST_ENDPOINT); + // Upload file using presigned URL - URL url = new URL(presignedUrl); + URL url = new URL(actualUploadUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("PUT"); connection.setDoOutput(true); @@ -519,7 +536,7 @@ class S3ClientUtilTest { @Test @DisabledIf("isMinioUnavailable") void uploadObject_invalidUrl_shouldNotBeAccessible() { - // Construct a non-existent URL + // Construct a non-existent URL (using internal endpoint for actual access test) String invalidUrl = TEST_ENDPOINT + "/" + TEST_BUCKET + "/nonexistent/file_" + System.currentTimeMillis() + ".txt"; // Verify non-existent URL is not accessible @@ -542,16 +559,19 @@ class S3ClientUtilTest { int expirySeconds = 3600; String presignedGetUrl = s3ClientUtil.generatePresignedGetUrl(TEST_BUCKET, objectKey, expirySeconds); - // Verify presigned GET URL format + // Verify presigned GET URL format (should use TEST_REMOTE_ENDPOINT) Assertions.assertNotNull(presignedGetUrl); - Assertions.assertTrue(presignedGetUrl.startsWith(TEST_ENDPOINT)); + Assertions.assertTrue(presignedGetUrl.startsWith(TEST_REMOTE_ENDPOINT)); Assertions.assertTrue(presignedGetUrl.contains(TEST_BUCKET)); Assertions.assertTrue(presignedGetUrl.contains(objectKey)); Assertions.assertTrue(presignedGetUrl.contains("X-Amz-Algorithm=AWS4-HMAC-SHA256")); + // For actual download testing, replace remote endpoint with internal endpoint + String actualDownloadUrl = presignedGetUrl.replace(TEST_REMOTE_ENDPOINT, TEST_ENDPOINT); + // Verify can read content via presigned GET URL try { - String downloadedContent = readFromUrl(presignedGetUrl); + String downloadedContent = readFromUrl(actualDownloadUrl); Assertions.assertEquals(testContent, downloadedContent, "Content downloaded via presigned GET URL should match uploaded content"); } catch (IOException e) { @@ -573,16 +593,19 @@ class S3ClientUtilTest { // Generate presigned GET URL using default bucket and expiry String presignedGetUrl = s3ClientUtil.generatePresignedGetUrl(objectKey); - // Verify presigned GET URL format + // Verify presigned GET URL format (should use TEST_REMOTE_ENDPOINT) Assertions.assertNotNull(presignedGetUrl); - Assertions.assertTrue(presignedGetUrl.startsWith(TEST_ENDPOINT)); + Assertions.assertTrue(presignedGetUrl.startsWith(TEST_REMOTE_ENDPOINT)); Assertions.assertTrue(presignedGetUrl.contains(TEST_BUCKET)); Assertions.assertTrue(presignedGetUrl.contains(objectKey)); Assertions.assertTrue(presignedGetUrl.contains("X-Amz-Algorithm=AWS4-HMAC-SHA256")); + // For actual download testing, replace remote endpoint with internal endpoint + String actualDownloadUrl = presignedGetUrl.replace(TEST_REMOTE_ENDPOINT, TEST_ENDPOINT); + // Verify can read content via presigned GET URL try { - String downloadedContent = readFromUrl(presignedGetUrl); + String downloadedContent = readFromUrl(actualDownloadUrl); Assertions.assertEquals(testContent, downloadedContent, "Content downloaded via presigned GET URL should match uploaded content"); } catch (IOException e) { @@ -596,6 +619,7 @@ class S3ClientUtilTest { // Create an S3ClientUtil using invalid credentials S3ClientUtil invalidS3ClientUtil = new S3ClientUtil(); ReflectionTestUtils.setField(invalidS3ClientUtil, "endpoint", TEST_ENDPOINT); + ReflectionTestUtils.setField(invalidS3ClientUtil, "remoteEndpoint", TEST_REMOTE_ENDPOINT); ReflectionTestUtils.setField(invalidS3ClientUtil, "accessKey", INVALID_ACCESS_KEY); ReflectionTestUtils.setField(invalidS3ClientUtil, "secretKey", INVALID_SECRET_KEY); ReflectionTestUtils.setField(invalidS3ClientUtil, "defaultBucket", TEST_BUCKET); diff --git a/console/backend/docker/schema.sql b/console/backend/docker/schema.sql deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/console/backend/hub/Dockerfile b/console/backend/hub/Dockerfile index 59fff43a39d9795bcb6615e407cea9a565526756..e8c9017c67a9fd2494e8448a95e1da3b4f7bed9b 100644 --- a/console/backend/hub/Dockerfile +++ b/console/backend/hub/Dockerfile @@ -29,4 +29,11 @@ ENV LC_ALL=zh_CN.UTF-8 COPY --from=build /backend/hub/target/hub-server.jar /app/app.jar EXPOSE 8080 -ENTRYPOINT ["java","-XX:+UseContainerSupport","-XX:MaxRAMPercentage=75.0","-jar","/app/app.jar"] + +# Optimized JVM parameters for reduced memory usage: +ENTRYPOINT ["java", \ + "-XX:+UseContainerSupport", \ + "-XX:MaxRAMPercentage=75.0", \ + "-XX:+UseG1GC", \ + "-XX:+UseStringDeduplication", \ + "-jar", "/app/app.jar"] diff --git a/console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/publish/impl/BotPublishServiceImpl.java b/console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/publish/impl/BotPublishServiceImpl.java index 125b94c9b928f36fdd126baaaff31638d7b97238..a87b54bc5ff61fb9524fb8c3e4f3a51f663c84ba 100644 --- a/console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/publish/impl/BotPublishServiceImpl.java +++ b/console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/publish/impl/BotPublishServiceImpl.java @@ -288,6 +288,7 @@ public class BotPublishServiceImpl implements BotPublishService { } } catch (Exception e) { log.error("Record conversation statistics exception: chatId={}", chatId, e); + // Do not throw exception to avoid affecting main business flow } } diff --git a/console/backend/hub/src/main/resources/application.yml b/console/backend/hub/src/main/resources/application.yml index bfc6f4ac985bf765d59e6a1e0d0775939958c7ea..87fd565d31cdf47f4db8b33cb663c0723ddbb0c6 100644 --- a/console/backend/hub/src/main/resources/application.yml +++ b/console/backend/hub/src/main/resources/application.yml @@ -15,11 +15,40 @@ spring: driver-class-name: com.mysql.cj.jdbc.Driver username: ${MYSQL_USER:astron} password: ${MYSQL_PASSWORD:astron-dev-env-db} + # HikariCP connection pool configuration + hikari: + # Maximum pool size + maximum-pool-size: 10 + # Minimum idle connections + minimum-idle: 2 + # Connection timeout (ms) + connection-timeout: 30000 + # Idle timeout (ms) + idle-timeout: 600000 + # Max connection lifetime (ms) + max-lifetime: 1800000 + # Validation timeout (ms) + validation-timeout: 5000 + # Connection test query + connection-test-query: SELECT 1 + # Pool name + pool-name: AstronHikariCP + # Auto commit + auto-commit: true + # Leak detection threshold (ms) + leak-detection-threshold: 60000 data: redis: host: ${REDIS_HOST:redis} port: ${REDIS_PORT:6379} database: ${REDIS_DATABASE_CONSOLE:0} + # Lettuce connection pool configuration for reduced memory usage + lettuce: + pool: + max-active: 8 # Maximum number of active connections + max-idle: 4 # Maximum number of idle connections + min-idle: 1 # Minimum number of idle connections + max-wait: 3000ms # Maximum wait time when pool is exhausted security: oauth2: resourceserver: @@ -67,7 +96,8 @@ mybatis-plus: # S3(MinIO) basic configuration s3: - endpoint: ${OSS_REMOTE_ENDPOINT:http://minio:9000} + endpoint: ${OSS_ENDPOINT:http://minio:9000} + remoteEndpoint: ${OSS_REMOTE_ENDPOINT:http://your-host-domain:9000} accessKey: ${OSS_ACCESS_KEY_ID:astron-uploader} secretKey: ${OSS_ACCESS_KEY_SECRET:astron-uploader-secret} bucket: ${OSS_BUCKET_CONSOLE:astron-agent} diff --git a/console/backend/hub/src/test/java/com/iflytek/astron/console/hub/controller/homepage/AgentSquareControllerTest.java b/console/backend/hub/src/test/java/com/iflytek/astron/console/hub/controller/homepage/AgentSquareControllerTest.java deleted file mode 100644 index 27617a6ad5320b94ef20ba67d10283e8e67affbf..0000000000000000000000000000000000000000 --- a/console/backend/hub/src/test/java/com/iflytek/astron/console/hub/controller/homepage/AgentSquareControllerTest.java +++ /dev/null @@ -1,175 +0,0 @@ -// package com.iflytek.astron.console.hub.controller.homepage; -// -// import com.iflytek.astron.console.commons.response.ApiResult; -// import com.iflytek.astron.console.hub.dto.homepage.BotInfoDto; -// import com.iflytek.astron.console.hub.dto.homepage.BotListPageDto; -// import com.iflytek.astron.console.hub.dto.homepage.BotTypeDto; -// import com.iflytek.astron.console.hub.service.homepage.AgentSquareService; -// import org.junit.jupiter.api.Assertions; -// import org.junit.jupiter.api.BeforeEach; -// import org.junit.jupiter.api.Test; -// import org.mockito.InjectMocks; -// import org.mockito.Mock; -// import org.mockito.MockitoAnnotations; -// import org.springframework.boot.test.context.SpringBootTest; -// -// import java.util.ArrayList; -// import java.util.Arrays; -// import java.util.Collections; -// import java.util.List; -// -// import static org.mockito.ArgumentMatchers.*; -// import static org.mockito.Mockito.when; -// -// @SpringBootTest -// public class AgentSquareControllerTest { -// @Mock -// AgentSquareService agentSquareService; -// @InjectMocks -// AgentSquareController agentSquareController; -// -// @BeforeEach -// void setUp() { -// MockitoAnnotations.openMocks(this); -// } -// -// /** -// * Test getting the robot type list successfully, expecting a non-empty robot type list to be -// returned. -// * Input: None -// * Output: -// * {"code":0,"message":"Success","data": -// * -// [{"typeKey":1,"typeName":"Chatbot","icon":"http://example.com/icon1.png","typeNameEn":"Chatbot"}, -// * -// {"typeKey":2,"typeName":"InfoPushBot","icon":"http://example.com/icon2.png","typeNameEn":"InfoPushBot"}] -// * } -// */ -// @Test -// public void testGetBotTypeListSuccess() { -// List mockData = Arrays.asList( -// createBotTypeDto(1, "Chat Bot", "http://example.com/icon1.png"), -// createBotTypeDto(2, "Info Push Bot", "http://example.com/icon2.png") -// ); -// when(agentSquareService.getBotTypeList()).thenReturn(mockData); -// -// ApiResult> result = agentSquareController.getBotTypeList(); -// -// Assertions.assertEquals(0, result.code()); -// Assertions.assertEquals("Success", result.message()); -// Assertions.assertEquals(mockData, result.data()); -// } -// -// /** -// * Test under normal circumstances, passing valid type and pageSize, page parameters, expecting to -// return correct paginated data. -// * Input: search = test -// * pageSize = 20 -// * page = 1 -// * type = 1 -// * Output: -// * {"code":0,"message":"Success","data": -// * -// {"pageData":[{"botId":1,"chatId":1001,"botName":"TestBot","botType":1,"botCoverUrl":"http://example.com/cover.jpg","prompt":"Hello","botDesc":"A -// test -// bot","isFavorite":true,"creator":"Tester"}],"totalCount":1,"pageSize":20,"page":1,"totalPages":1}} -// */ -// @Test -// public void testGetBotPageByTypeHappyPath() { -// BotListPageDto mockPage = new BotListPageDto(); -// mockPage.setTotalPages(1); -// mockPage.setPageSize(20); -// mockPage.setPage(1); -// mockPage.setTotalCount(1); -// mockPage.setPageData(Collections.singletonList(createBotInfoDto())); -// -// when(agentSquareService.getBotPageByType(eq(1), eq("test"), eq(20), eq(1))).thenReturn(mockPage); -// -// ApiResult result = agentSquareController.getBotPageByType(1, "test", 20, 1); -// -// Assertions.assertNotNull(result); -// Assertions.assertEquals(0, result.code()); -// Assertions.assertEquals("Success", result.message()); -// Assertions.assertEquals(mockPage, result.data()); -// } -// -// /** -// * Test boundary case, when the search parameter is an empty string, expecting to return correct -// paginated data. -// * Input: search = null -// * pageSize = 20 -// * page = 1 -// * type = 1 -// * Output: -// * -// {"code":0,"message":"Success","data":{"pageData":[],"totalCount":0,"pageSize":20,"page":1,"totalPages":0}} -// */ -// @Test -// public void testGetBotPageByTypeEdgeCaseEmptySearch() { -// BotListPageDto mockPage = new BotListPageDto(); -// mockPage.setTotalPages(0); -// mockPage.setPageSize(20); -// mockPage.setPage(1); -// mockPage.setTotalCount(0); -// mockPage.setPageData(new ArrayList<>()); -// -// when(agentSquareService.getBotPageByType(eq(1), isNull(), eq(20), eq(1))).thenReturn(mockPage); -// -// ApiResult result = agentSquareController.getBotPageByType(1, null, 20, 1); -// -// Assertions.assertNotNull(result); -// Assertions.assertEquals(0, result.code()); -// Assertions.assertEquals("Success", result.message()); -// Assertions.assertEquals(mockPage, result.data()); -// } -// -// /** -// * Test boundary case, when the type parameter is an invalid value (such as a negative number), -// expecting to return an error message. -// * Input: search = test -// * pageSize = 20 -// * page = 1 -// * type = -1 -// * Output: -// * {"code":400,"message":"Invalid type parameter."} -// */ -// @Test -// public void testGetBotPageByTypeEdgeCaseInvalidType() { -// ApiResult expectedError = new ApiResult<>(400, "Invalid type parameter.", null, -// null); -// -// when(agentSquareService.getBotPageByType(eq(-1), anyString(), anyInt(), -// anyInt())).thenReturn(null); -// -// ApiResult result = agentSquareController.getBotPageByType(-1, "test", 20, 1); -// -// Assertions.assertEquals(expectedError.code(), result.code()); -// Assertions.assertEquals(expectedError.message(), result.message()); -// Assertions.assertNull(result.data()); -// } -// -// private BotTypeDto createBotTypeDto(int typeKey, String typeName, String iconUrl) { -// BotTypeDto dto = new BotTypeDto(); -// dto.setTypeKey(typeKey); -// dto.setTypeName(typeName); -// dto.setTypeNameEn(typeName); -// dto.setIcon(iconUrl); -// return dto; -// } -// -// private BotInfoDto createBotInfoDto() { -// BotInfoDto dto = new BotInfoDto(); -// dto.setBotId(1); -// dto.setChatId(1001L); -// dto.setBotName("TestBot"); -// dto.setBotType(1); -// dto.setBotCoverUrl("http://example.com/cover.jpg"); -// dto.setPrompt("Hello"); -// dto.setBotDesc("A test bot"); -// dto.setIsFavorite(true); -// dto.setCreator("Tester"); -// return dto; -// } -// } -// -// diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/config/properties/ApiUrl.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/config/properties/ApiUrl.java index 8db381b5576c78b4449d22e478b5b7a4b25b02ae..7c02b366cdb2364982081c503f155e20da55e784 100644 --- a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/config/properties/ApiUrl.java +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/config/properties/ApiUrl.java @@ -18,6 +18,7 @@ public class ApiUrl { String knowledgeUrl; String streamChatUrl; String toolUrl; + String toolRpaUrl; String appUrl; String apiKey; String apiSecret; diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/controller/open/OpenApiController.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/controller/open/OpenApiController.java new file mode 100644 index 0000000000000000000000000000000000000000..7d54f8d3080373fae3f73b2f25eec7a3eb098d1a --- /dev/null +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/controller/open/OpenApiController.java @@ -0,0 +1,66 @@ +package com.iflytek.astron.console.toolkit.controller.open; + +import com.alibaba.fastjson2.JSONObject; +import com.iflytek.astron.console.commons.constant.ResponseEnum; +import com.iflytek.astron.console.commons.response.ApiResult; +import com.iflytek.astron.console.toolkit.common.anno.ResponseResultBody; +import com.iflytek.astron.console.toolkit.entity.dto.openapi.WorkflowIoTransRequest; +import com.iflytek.astron.console.toolkit.service.openapi.OpenApiService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * Open API Controller for external service integration + */ +@RestController +@RequestMapping("/open-api") +@Slf4j +@ResponseResultBody +@Tag(name = "Open API interface") +public class OpenApiController { + + @Autowired + private OpenApiService openApiService; + + private static final String AUTHORIZATION_PREFIX = "Bearer "; + + /** + * Get workflow IO transformation data by API key + * + * @param authorization Authorization header in format "Bearer apiKey:apiSecret" + * @return List of IO transformation data + */ + @GetMapping("/workflow-io-info-list") + @Operation(summary = "Get workflow IO transformations", + description = "Retrieve workflow IO transformation data using API key authentication") + public ApiResult> getWorkflowIoInfoList( + @RequestHeader("authorization") String authorization) { + + // Parse authorization header + if (!StringUtils.hasText(authorization) || !authorization.startsWith("Bearer ")) { + return ApiResult.error(ResponseEnum.UNAUTHORIZED); + } + + String credentials = authorization.substring(AUTHORIZATION_PREFIX.length()); + String[] parts = credentials.split(":"); + if (parts.length != 2) { + return ApiResult.error(ResponseEnum.UNAUTHORIZED); + } + + // Build request DTO + WorkflowIoTransRequest request = new WorkflowIoTransRequest(); + request.setApiKey(parts[0]); + request.setApiSecret(parts[1]); + + // Call service layer + List result = openApiService.getWorkflowIoTransformations(request); + + return ApiResult.success(result); + } +} diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/controller/tool/RpaController.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/controller/tool/RpaController.java index b17687c920498b7cbdbca6b53fa2031848114caf..57484f64f9c913d7196535d7bb4b8b60e95a71b7 100644 --- a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/controller/tool/RpaController.java +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/controller/tool/RpaController.java @@ -2,19 +2,21 @@ package com.iflytek.astron.console.toolkit.controller.tool; import com.iflytek.astron.console.commons.response.ApiResult; import com.iflytek.astron.console.toolkit.common.anno.ResponseResultBody; +import com.iflytek.astron.console.toolkit.entity.dto.rpa.StartReq; import com.iflytek.astron.console.toolkit.entity.table.tool.RpaInfo; import com.iflytek.astron.console.toolkit.entity.table.tool.RpaUserAssistant; import com.iflytek.astron.console.toolkit.entity.tool.CreateRpaAssistantReq; import com.iflytek.astron.console.toolkit.entity.tool.RpaAssistantResp; import com.iflytek.astron.console.toolkit.entity.tool.UpdateRpaAssistantReq; import com.iflytek.astron.console.toolkit.handler.UserInfoManagerHandler; -import com.iflytek.astron.console.toolkit.service.tool.RpaAssistantService; -import com.iflytek.astron.console.toolkit.service.tool.RpaInfoService; +import com.iflytek.astron.console.toolkit.service.tool.*; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.util.List; @@ -124,4 +126,13 @@ public class RpaController { String userId = UserInfoManagerHandler.getUserId(); rpaAssistantService.delete(userId, id); } + + /** + * 调试RPA机器人 + */ + @PostMapping(value = "/debug", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public SseEmitter stream(@RequestBody StartReq req, + @RequestHeader(value = "X-RPA-Token") String apiToken) { + return rpaAssistantService.debug(req, apiToken); + } } diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/dto/external/AppInfoResponse.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/dto/external/AppInfoResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..3d1f19dcc31931ace8df82c57acb05511cefddc1 --- /dev/null +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/dto/external/AppInfoResponse.java @@ -0,0 +1,24 @@ +package com.iflytek.astron.console.toolkit.entity.dto.external; + +import lombok.Data; + +/** + * Response DTO for third-party API app info query + */ +@Data +public class AppInfoResponse { + + private String sid; + private Integer code; + private String message; + private AppInfoData data; + + @Data + public static class AppInfoData { + private String appid; + private String name; + private String source; + private String desc; + private String createTime; + } +} diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/dto/openapi/WorkflowIoTransRequest.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/dto/openapi/WorkflowIoTransRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..dc7c411558f543066fe4742a447668b409f8fc1b --- /dev/null +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/dto/openapi/WorkflowIoTransRequest.java @@ -0,0 +1,20 @@ +package com.iflytek.astron.console.toolkit.entity.dto.openapi; + +import lombok.Data; + +/** + * Request DTO for workflow IO transformation query + */ +@Data +public class WorkflowIoTransRequest { + + /** + * API Key extracted from authorization header + */ + private String apiKey; + + /** + * API Secret extracted from authorization header + */ + private String apiSecret; +} diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/dto/rpa/StartReq.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/dto/rpa/StartReq.java new file mode 100644 index 0000000000000000000000000000000000000000..5e55b0956189a48eb10a9a7eddce3bd2d22c541c --- /dev/null +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/dto/rpa/StartReq.java @@ -0,0 +1,16 @@ +package com.iflytek.astron.console.toolkit.entity.dto.rpa; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +import java.util.Map; + +@Data +public class StartReq { + @NotBlank + private String projectId; + private String execPosition = "EXECUTOR"; + // 可空,默认 RPA 当前启用版本 + private Integer version; + private Map params = Map.of(); +} diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/enumVo/DebugStatus.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/enumVo/DebugStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..9c7cdc6cb93402702bd625e4114ae5c507580c41 --- /dev/null +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/enumVo/DebugStatus.java @@ -0,0 +1,23 @@ +package com.iflytek.astron.console.toolkit.entity.enumVo; + +/** + * RPA调试任务状态 + */ +public enum DebugStatus { + // 本地创建 + CREATED, + // 已拿到 executionId + SUBMITTED, + // RPA PENDING(运行中) + RUNNING, + // RPA COMPLETED + SUCCEEDED, + // RPA FAILED 或本地失败 + FAILED, + // (预留,如后续支持取消) + CANCELED, + // 查询失败后重试 + RETRYING, + // 超时 + TIMEOUT +} diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/vo/openapi/WorkflowIoTransVo.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/vo/openapi/WorkflowIoTransVo.java new file mode 100644 index 0000000000000000000000000000000000000000..d98f8199ad92710dade853733ed5c3a25c91e890 --- /dev/null +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/vo/openapi/WorkflowIoTransVo.java @@ -0,0 +1,28 @@ +package com.iflytek.astron.console.toolkit.entity.vo.openapi; + +import com.alibaba.fastjson2.JSONObject; +import lombok.Data; + +import java.util.List; + +/** + * Response VO for workflow IO transformation query + */ +@Data +public class WorkflowIoTransVo { + + /** + * List of workflow IO transformation data + */ + private List transformations; + + /** + * Total count of transformations found + */ + private Integer count; + + /** + * Application ID that was queried + */ + private String appId; +} diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/vo/rpa/DebugSession.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/vo/rpa/DebugSession.java new file mode 100644 index 0000000000000000000000000000000000000000..8edb41e672ad462473df5d18680597bd05f47f8f --- /dev/null +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/entity/vo/rpa/DebugSession.java @@ -0,0 +1,140 @@ +package com.iflytek.astron.console.toolkit.entity.vo.rpa; + +import com.iflytek.astron.console.toolkit.entity.enumVo.DebugStatus; + +import java.time.Instant; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +public class DebugSession { + private final String debugId = UUID.randomUUID().toString(); + + private final String projectId; + private final Integer version; + private final String execPosition; + private final Map params; + + + private volatile String apiToken; + // RPA 返回 + private volatile String executionId; + private volatile DebugStatus status = DebugStatus.CREATED; + // 错误或提示信息 + private volatile String message; + // 若第三方不提供,保持 0 + private volatile int progress = 0; + private volatile Instant createdAt = Instant.now(); + private volatile Instant updatedAt = Instant.now(); + // 生命周期(ms) + private final long expireAtEpochMilli; + private final AtomicInteger retries = new AtomicInteger(0); + // 当前轮询间隔(ms) + private volatile long nextPollMs; + + public DebugSession(String projectId, Integer version, String execPosition, Map params, String apiToken, long timeoutSeconds, long initialPollMs) { + this.projectId = projectId; + this.version = version; + this.execPosition = (execPosition == null || execPosition.isBlank()) ? "EXECUTOR" : execPosition; + this.apiToken = apiToken; + this.params = params; + this.expireAtEpochMilli = System.currentTimeMillis() + timeoutSeconds * 1000; + this.nextPollMs = initialPollMs; + } + + public String getDebugId() { + return debugId; + } + + public String getProjectId() { + return projectId; + } + + public Integer getVersion() { + return version; + } + + public String getExecPosition() { + return execPosition; + } + + public Map getParams() { + return params; + } + + public String getExecutionId() { + return executionId; + } + + public void setExecutionId(String executionId) { + this.executionId = executionId; + touch(); + } + + public DebugStatus getStatus() { + return status; + } + + public void setStatus(DebugStatus status) { + this.status = status; + touch(); + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + touch(); + } + + public int getProgress() { + return progress; + } + + public void setProgress(int progress) { + this.progress = progress; + touch(); + } + + public Instant getCreatedAt() { + return createdAt; + } + + public Instant getUpdatedAt() { + return updatedAt; + } + + public void touch() { + this.updatedAt = Instant.now(); + } + + public boolean isExpired() { + return System.currentTimeMillis() > expireAtEpochMilli; + } + + public int incRetries() { + return retries.incrementAndGet(); + } + + public int getRetries() { + return retries.get(); + } + + public long getNextPollMs() { + return nextPollMs; + } + + public void setNextPollMs(long nextPollMs) { + this.nextPollMs = nextPollMs; + } + + public String getApiToken() { + return apiToken; + } + + public void setApiToken(String apiToken) { + this.apiToken = apiToken; + } +} diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/mapper/knowledge/KnowledgeMapper.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/mapper/knowledge/KnowledgeMapper.java index f428ca46d9f7e94289eec1f53de660a66bb25d35..a084e3f35562e34ade2dfee7280bedfaf121d7f4 100644 --- a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/mapper/knowledge/KnowledgeMapper.java +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/mapper/knowledge/KnowledgeMapper.java @@ -79,4 +79,14 @@ public interface KnowledgeMapper extends BaseMapper { * Count knowledge entries by fileId and enabled status */ Long countByFileIdAndEnabled(@Param("fileId") String fileId, @Param("enabled") Integer enabled); + + /** + * Count knowledge entries by fileId list and content like (fuzzy query) + */ + Long countByFileIdInAndContentLike(@Param("fileIds") List fileIds, @Param("query") String query); + + /** + * Count knowledge entries by fileId list and audit type + */ + Long countByFileIdInAndAuditType(@Param("fileIds") List fileIds, @Param("auditType") Integer auditType); } diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/external/ExternalApiService.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/external/ExternalApiService.java new file mode 100644 index 0000000000000000000000000000000000000000..b920694c10bd63ff1d34ae3f8184e319d927fcdc --- /dev/null +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/external/ExternalApiService.java @@ -0,0 +1,77 @@ +package com.iflytek.astron.console.toolkit.service.external; + +import com.alibaba.fastjson2.JSON; +import com.iflytek.astron.console.toolkit.entity.dto.external.AppInfoResponse; +import com.iflytek.astron.console.toolkit.util.OkHttpUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** + * Service for calling external third-party APIs + */ +@Service +@Slf4j +public class ExternalApiService { + @Value("${api.url.appIdQryUrl}") + private String appIdQryUrl; + + + /** + * Query app info by API key + * + * @param apiKey API key + * @return AppInfoResponse + */ + public AppInfoResponse getAppInfoByApiKey(String apiKey) { + String url = appIdQryUrl + "/v2/app/key/api_key/" + apiKey; + log.debug("Calling external API: {}", url); + + try { + String response = OkHttpUtil.get(url); + log.debug("External API response: {}", response); + + // Check if response is valid JSON format + if (response == null || response.trim().isEmpty()) { + log.error("Empty response from external API for apiKey: {}", apiKey); + return createMockResponse(apiKey); + } + + // Check for common error responses + if (response.contains("404") || response.contains("not found") || + response.contains("error") || !response.trim().startsWith("{")) { + log.warn("External API not available (response: {}), using mock data for apiKey: {}", + response.trim(), apiKey); + return createMockResponse(apiKey); + } + + return JSON.parseObject(response, AppInfoResponse.class); + } catch (Exception e) { + log.warn("Failed to query external API ({}), using mock data for apiKey: {}", + e.getMessage(), apiKey); + return createMockResponse(apiKey); + } + } + + /** + * Create mock response when external API is not available TODO: Remove this when external API is + * fixed + */ + private AppInfoResponse createMockResponse(String apiKey) { + AppInfoResponse response = new AppInfoResponse(); + response.setCode(0); + response.setMessage("Success (Mock Data)"); + + AppInfoResponse.AppInfoData data = new AppInfoResponse.AppInfoData(); + // Use a deterministic appId based on apiKey for consistency + data.setAppid("mock-app-" + apiKey.substring(0, Math.min(8, apiKey.length()))); + data.setName("Mock Application"); + data.setSource("mock"); + data.setDesc("Mock application for testing"); + + response.setData(data); + + log.info("Generated mock response for apiKey: {}, appId: {}", apiKey, data.getAppid()); + return response; + } +} diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/openapi/OpenApiService.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/openapi/OpenApiService.java new file mode 100644 index 0000000000000000000000000000000000000000..fec577f7f43c4d8a393ba8b2133fc514a82891fa --- /dev/null +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/openapi/OpenApiService.java @@ -0,0 +1,20 @@ +package com.iflytek.astron.console.toolkit.service.openapi; + +import com.alibaba.fastjson2.JSONObject; +import com.iflytek.astron.console.toolkit.entity.dto.openapi.WorkflowIoTransRequest; + +import java.util.List; + +/** + * Open API Service Interface + */ +public interface OpenApiService { + + /** + * Get workflow IO transformations by API key + * + * @param request Request containing API key and secret + * @return Workflow IO transformation data + */ + List getWorkflowIoTransformations(WorkflowIoTransRequest request); +} diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/openapi/impl/OpenApiServiceImpl.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/openapi/impl/OpenApiServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..9ff821dff6f2774cda3394b0e592afb1b5019075 --- /dev/null +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/openapi/impl/OpenApiServiceImpl.java @@ -0,0 +1,178 @@ +package com.iflytek.astron.console.toolkit.service.openapi.impl; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.iflytek.astron.console.commons.constant.ResponseEnum; +import com.iflytek.astron.console.commons.dto.bot.ChatBotApi; +import com.iflytek.astron.console.commons.entity.workflow.Workflow; +import com.iflytek.astron.console.commons.exception.BusinessException; +import com.iflytek.astron.console.commons.mapper.bot.ChatBotApiMapper; +import com.iflytek.astron.console.toolkit.entity.biz.workflow.BizWorkflowData; +import com.iflytek.astron.console.toolkit.entity.dto.external.AppInfoResponse; +import com.iflytek.astron.console.toolkit.entity.dto.openapi.WorkflowIoTransRequest; +import com.iflytek.astron.console.toolkit.service.external.ExternalApiService; +import com.iflytek.astron.console.toolkit.service.openapi.OpenApiService; +import com.iflytek.astron.console.toolkit.service.workflow.WorkflowService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * Open API Service Implementation + */ +@Service +@Slf4j +public class OpenApiServiceImpl implements OpenApiService { + + @Autowired + private ExternalApiService externalApiService; + + @Autowired + private WorkflowService workflowService; + + @Autowired + private ChatBotApiMapper chatBotApiMapper; + + @Override + public List getWorkflowIoTransformations(WorkflowIoTransRequest request) { + try { + String appId = getAppIdByApiKey(request.getApiKey()); + + if (!StringUtils.hasText(appId)) { + log.error("appId is empty, apiKey:{}", request.getApiKey()); + throw new BusinessException(ResponseEnum.UNAUTHORIZED); + } + + // String appId = "663777f0"; + + List chatBotApiList = getChatBotApiByAppId(appId); + + if (chatBotApiList.isEmpty()) { + log.info("No ChatBotApi records found for appId: {}", appId); + return null; + } + + return processWorkflowTransformations(chatBotApiList); + + } catch (BusinessException e) { + log.error("Business error in getWorkflowIoTransformations: {}", e.getMessage()); + throw e; + } catch (Exception e) { + log.error("Unexpected error in getWorkflowIoTransformations", e); + throw new BusinessException(ResponseEnum.INTERNAL_SERVER_ERROR); + } + } + + private List getChatBotApiByAppId(String appId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ChatBotApi::getAppId, appId); + return chatBotApiMapper.selectList(queryWrapper); + } + + /** + * Get appId by calling external API with apiKey + */ + private String getAppIdByApiKey(String apiKey) { + AppInfoResponse appInfoResponse = externalApiService.getAppInfoByApiKey(apiKey); + if (appInfoResponse.getCode() != 0 || appInfoResponse.getData() == null) { + log.error("Failed to get app info from external API: code={}, message={}", + appInfoResponse.getCode(), appInfoResponse.getMessage()); + throw new BusinessException(ResponseEnum.DATA_NOT_FOUND); + } + + String appId = appInfoResponse.getData().getAppid(); + log.info("Successfully retrieved appId: {} for apiKey: {}", appId, apiKey); + return appId; + } + + /** + * Process workflow transformations for all ChatBotApi records + */ + private List processWorkflowTransformations(List chatBotApiList) { + + List workflowIds = chatBotApiList.stream() + .map(ChatBotApi::getAssistantId) + .filter(StringUtils::hasText) + .toList(); + + if (workflowIds.isEmpty()) { + return new ArrayList<>(); + } + + List workflowList = getWorkflowsById(workflowIds); + + return processWorkflowList(workflowList); + } + + /** + * + */ + private List getWorkflowsById(List workflowIds) { + LambdaQueryWrapper workflowQueryWrapper = new LambdaQueryWrapper<>(); + workflowQueryWrapper.in(Workflow::getFlowId, workflowIds) + .eq(Workflow::getDeleted, false); + + return workflowService.list(workflowQueryWrapper); + } + + /** + * Process a list of workflows to extract IO transformations + */ + private List processWorkflowList(List workflows) { + List results = new ArrayList<>(); + + for (Workflow workflow : workflows) { + JSONObject transformation = processSingleWorkflow(workflow); + if (transformation != null) { + results.add(transformation); + } + } + + return results; + } + + /** + * Process a single workflow to extract IO transformation + */ + private JSONObject processSingleWorkflow(Workflow workflow) { + if (!StringUtils.hasText(workflow.getData())) { + return null; + } + + try { + BizWorkflowData bizWorkflowData = JSON.parseObject(workflow.getData(), BizWorkflowData.class); + if (bizWorkflowData == null || bizWorkflowData.getNodes() == null) { + return null; + } + + JSONObject ioTransformation = workflowService.getIoTrans(bizWorkflowData.getNodes()); + if (ioTransformation != null) { + enrichTransformationWithMetadata(ioTransformation, workflow); + } + + return ioTransformation; + } catch (Exception e) { + log.error("Error processing workflow data for workflow id: {}", workflow.getId(), e); + return null; + } + } + + /** + * Add workflow metadata to transformation object + */ + private void enrichTransformationWithMetadata(JSONObject transformation, Workflow workflow) { + transformation.put("workflowId", workflow.getId()); + transformation.put("workflowName", workflow.getName()); + transformation.put("workDescription", workflow.getDescription()); + transformation.put("uid", workflow.getUid()); + transformation.put("spaceId", workflow.getSpaceId()); + transformation.put("createTime", workflow.getCreateTime()); + transformation.put("updateTime", workflow.getUpdateTime()); + } + +} diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/repo/FileInfoV2Service.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/repo/FileInfoV2Service.java index 2660bce0ec9b7670e85493259992c8f3752b8276..b6296ddd90ddb62635d7b530cbdcfe5b1662c41f 100644 --- a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/repo/FileInfoV2Service.java +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/repo/FileInfoV2Service.java @@ -60,6 +60,7 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.io.*; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import okhttp3.HttpUrl; import java.sql.Timestamp; import java.time.LocalDateTime; import java.util.*; @@ -918,7 +919,19 @@ public class FileInfoV2Service extends ServiceImpl knowledges = knowledgeMapper.findByFileIdInAndAuditType(fileUuIds, auditType); } - long count = knowledgeMapper.countByFileIdIn(fileUuIds); + // Fix totalCount calculation to match filtering logic + long count; + if (auditType != null && auditType == 1) { + // Count filtered by audit type + count = knowledgeMapper.countByFileIdInAndAuditType(fileUuIds, auditType); + } else if (!StringUtils.isEmpty(queryContent)) { + // Count filtered by content query + count = knowledgeMapper.countByFileIdInAndContentLike(fileUuIds, queryContent); + } else { + // Count all records for the file IDs + count = knowledgeMapper.countByFileIdIn(fileUuIds); + } + long auditBlockCount = knowledgeMapper.findByFileIdInAndAuditType(fileUuIds, 1).size(); Map extMap = new HashMap<>(); extMap.put("auditBlockCount", auditBlockCount); @@ -938,24 +951,7 @@ public class FileInfoV2Service extends ServiceImpl FileInfoV2 fileInfoV2 = this.getOnly(new QueryWrapper().eq("uuid", fileId)); String source = fileInfoV2.getSource(); MysqlKnowledge knowledgeTemp = new MysqlKnowledge(); - if (ProjectContent.isCbgRagCompatible(source)) { - BeanUtils.copyProperties(knowledge, knowledgeTemp); - ChunkInfo chunkInfo = knowledgeTemp.getContent().toJavaObject(ChunkInfo.class); - JSONObject references = chunkInfo.getReferences(); - Set referenceUnusedSet = new HashSet<>(); - if (!CollectionUtils.isEmpty(references)) { - referenceUnusedSet = references.keySet(); - } - if (!CollectionUtils.isEmpty(referenceUnusedSet)) { - JSONObject newReference = new JSONObject(); - for (String referenceUnused : referenceUnusedSet) { - buildNewMode(referenceUnused, references, newReference); - } - chunkInfo.setReferences(newReference); - JSONObject updatedContent = (JSONObject) JSON.toJSON(chunkInfo); - knowledgeTemp.setContent(updatedContent); - } - } + checkSourceFixed(knowledge, source, knowledgeTemp); KnowledgeDto knowledgeDto = new KnowledgeDto(); knowledgeDtoList.add(knowledgeDto); if (ProjectContent.isCbgRagCompatible(source)) { @@ -978,6 +974,27 @@ public class FileInfoV2Service extends ServiceImpl return pageData; } + private static void checkSourceFixed(MysqlKnowledge knowledge, String source, MysqlKnowledge knowledgeTemp) { + if (ProjectContent.isCbgRagCompatible(source)) { + BeanUtils.copyProperties(knowledge, knowledgeTemp); + ChunkInfo chunkInfo = knowledgeTemp.getContent().toJavaObject(ChunkInfo.class); + JSONObject references = chunkInfo.getReferences(); + Set referenceUnusedSet = new HashSet<>(); + if (!CollectionUtils.isEmpty(references)) { + referenceUnusedSet = references.keySet(); + } + if (!CollectionUtils.isEmpty(referenceUnusedSet)) { + JSONObject newReference = new JSONObject(); + for (String referenceUnused : referenceUnusedSet) { + buildNewMode(referenceUnused, references, newReference); + } + chunkInfo.setReferences(newReference); + JSONObject updatedContent = (JSONObject) JSON.toJSON(chunkInfo); + knowledgeTemp.setContent(updatedContent); + } + } + } + private static void buildNewMode(String referenceUnused, JSONObject references, JSONObject newReference) { String link = references.getString(referenceUnused); JSONObject newReferenceV = new JSONObject(); @@ -1947,26 +1964,39 @@ public class FileInfoV2Service extends ServiceImpl /* ======================== Spark Branch ======================== */ private void streamSparkSearch(SseEmitter emitter, Long repoId, String fileName, HttpServletRequest request) throws IOException { - // Encode user input to prevent SSRF attacks - String encodedFileName; + // Use HttpUrl.Builder to construct URL safely and prevent SSRF attacks + HttpUrl url; try { - encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8); - } catch (Exception e) { - log.error("Failed to encode fileName", e); - encodedFileName = fileName; + HttpUrl base = HttpUrl.parse(apiUrl.getDatasetFileUrl()); + if (base == null) { + log.error("Failed to parse base URL: {}", apiUrl.getDatasetFileUrl()); + throw new IOException("Invalid base URL configuration"); + } + + url = base.newBuilder() + .addQueryParameter("datasetId", repoId.toString()) + .addQueryParameter("searchValue", fileName) + .build(); + + // Validate that the constructed URL has the same host as the base URL + String expectedHost = base.host(); + if (!url.host().equals(expectedHost)) { + log.error("Refusing to send request to unexpected host: {}", url.host()); + throw new IOException("Refusing to send request to untrusted host"); + } + + log.info("searchFile request url: {}", url); + } catch (IllegalArgumentException e) { + log.error("Invalid URL format", e); + throw new IOException("Invalid URL format", e); } - String url = apiUrl.getDatasetFileUrl() + "?datasetId=" - .concat(repoId.toString()) - .concat("&searchValue=") - .concat(encodedFileName); - log.info("searchFile request url: {}", url); Map header = new HashMap<>(); String authorization = request.getHeader("Authorization"); if (StringUtils.isNotBlank(authorization)) { header.put("Authorization", authorization); } - String resp = OkHttpUtil.get(url, header); + String resp = OkHttpUtil.get(url.toString(), header); JSONObject obj = JSON.parseObject(resp); log.info("searchFile response data: {}", resp); diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/tool/RpaAssistantService.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/tool/RpaAssistantService.java index e51bfb9741af0f6a08df63e14e5257b88c5cc36e..fa6f00064d960ccf6422240fb606052bf0b4ca97 100644 --- a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/tool/RpaAssistantService.java +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/tool/RpaAssistantService.java @@ -10,9 +10,12 @@ import com.iflytek.astron.console.commons.constant.ResponseEnum; import com.iflytek.astron.console.commons.entity.user.UserInfo; import com.iflytek.astron.console.commons.entity.workflow.Workflow; import com.iflytek.astron.console.commons.exception.BusinessException; +import com.iflytek.astron.console.commons.util.SseEmitterUtil; import com.iflytek.astron.console.commons.util.space.SpaceInfoUtil; +import com.iflytek.astron.console.toolkit.config.properties.ApiUrl; import com.iflytek.astron.console.toolkit.entity.biz.workflow.BizWorkflowData; import com.iflytek.astron.console.toolkit.entity.biz.workflow.BizWorkflowNode; +import com.iflytek.astron.console.toolkit.entity.dto.rpa.StartReq; import com.iflytek.astron.console.toolkit.entity.table.ConfigInfo; import com.iflytek.astron.console.toolkit.entity.table.tool.*; import com.iflytek.astron.console.toolkit.entity.tool.*; @@ -21,11 +24,17 @@ import com.iflytek.astron.console.toolkit.handler.UserInfoManagerHandler; import com.iflytek.astron.console.toolkit.mapper.ConfigInfoMapper; import com.iflytek.astron.console.toolkit.mapper.tool.*; import com.iflytek.astron.console.toolkit.service.workflow.WorkflowService; +import com.iflytek.astron.console.toolkit.util.JacksonUtil; +import com.iflytek.astron.console.toolkit.util.OkHttpUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import okhttp3.sse.EventSource; +import okhttp3.sse.EventSourceListener; import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.time.LocalDateTime; import java.util.*; @@ -49,6 +58,7 @@ public class RpaAssistantService { private final WorkflowService workflowService; private final ObjectMapper objectMapper = new ObjectMapper(); private final ConfigInfoMapper configInfoMapper; + private final ApiUrl apiUrl; /** * Create an RPA assistant with plaintext credentials. @@ -496,4 +506,87 @@ public class RpaAssistantService { .like(StringUtils.isNoneBlank(name), RpaUserAssistant::getAssistantName, name) .orderByDesc(RpaUserAssistant::getUpdateTime)); } + + public SseEmitter debug(StartReq startReq, String apiToken) { + try { + String url = apiUrl.getToolRpaUrl() + "/rpa/v1/exec"; + Map headerMap = new HashMap<>(); + headerMap.put(HttpHeaders.AUTHORIZATION, apiToken); + + String sseId = UserInfoManagerHandler.getUserId(); + if (StringUtils.isBlank(startReq.getProjectId())) { + return SseEmitterUtil.newSseAndSendMessageClose("project_id is required"); + } + + SseEmitter emitter = SseEmitterUtil.create(sseId, 1_800_000L); + Map body = new HashMap<>(); + body.put("project_id", startReq.getProjectId()); + body.put("exec_position", + (startReq.getExecPosition() == null || startReq.getExecPosition().isBlank()) ? "EXECUTOR" : startReq.getExecPosition()); + body.put("params", startReq.getParams() == null ? Map.of() : startReq.getParams()); + String reqBody = JacksonUtil.toJSONString(body, JacksonUtil.NON_NULL_OBJECT_MAPPER); + log.info("[SSE] rpa debug url={}, headers={}, reqBody={}", url, headerMap, reqBody); + + EventSourceListener listener = new EventSourceListener() { + @Override + public void onOpen(EventSource es, okhttp3.Response response) { + log.info("[SSE][{}] open, code={}", sseId, response.code()); + SseEmitterUtil.EVENTSOURCE_MAP.put(sseId, es); + try { + emitter.send(SseEmitter.event().name("open").data("ok")); + } catch (Exception e) { + log.warn("[SSE][{}] send open event failed: {}", sseId, e.getMessage(), e); + SseEmitterUtil.completeWithError(emitter, "send open event failed: " + e.getMessage()); + if (es != null) { + es.cancel(); + } + SseEmitterUtil.EVENTSOURCE_MAP.remove(sseId); + } + } + + @Override + public void onEvent(EventSource es, String id, String type, String data) { + try { + String event = (type == null || type.isBlank()) ? "data" : type; + if ("data".equals(event)) { + emitter.send(SseEmitter.event().name("data").data(data)); + } else if ("ping".equals(event)) { + emitter.send(SseEmitter.event().name("ping").data(data)); + } else if ("finish".equals(event)) { + emitter.send(SseEmitter.event().name("finish").data(data)); + SseEmitterUtil.sendEndAndComplete(emitter); + } else { + emitter.send(SseEmitter.event().name("data").data(data)); + } + } catch (Exception e) { + log.warn("[SSE][{}] forward event failed: {}", sseId, e.getMessage(), e); + } + } + + @Override + public void onClosed(EventSource es) { + log.info("[SSE][{}] downstream closed", sseId); + SseEmitterUtil.sendEndAndComplete(emitter); + SseEmitterUtil.EVENTSOURCE_MAP.remove(sseId); + } + + @Override + public void onFailure(EventSource es, Throwable t, okhttp3.Response resp) { + String msg = (t != null) ? t.getMessage() : (resp != null ? ("http " + resp.code()) : "unknown"); + log.error("[SSE][{}] downstream failure: {}", sseId, msg, t); + SseEmitterUtil.completeWithError(emitter, msg); + if (es != null) + es.cancel(); + SseEmitterUtil.EVENTSOURCE_MAP.remove(sseId); + } + }; + + EventSource es = OkHttpUtil.connectRealEventSourceReturn(url, headerMap, reqBody, listener); + SseEmitterUtil.EVENTSOURCE_MAP.put(sseId, es); + return emitter; + } catch (Exception e) { + log.error("SSE debug error: {}", e.getMessage(), e); + return SseEmitterUtil.newSseAndSendMessageClose(e.getMessage()); + } + } } diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/tool/ToolBoxService.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/tool/ToolBoxService.java index a949b11b4272538ba37781996810fcaf85e41e1b..1a0023eb1f93666a6f012457149f853ac8ff1ee9 100644 --- a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/tool/ToolBoxService.java +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/tool/ToolBoxService.java @@ -1110,6 +1110,7 @@ public class ToolBoxService extends ServiceImpl { toolBoxVo.setName(mcp.getName()); toolBoxVo.setDescription(mcp.getBrief()); toolBoxVo.setAddress(mcp.getLogoUrl()); + toolBoxVo.setIcon(mcp.getLogoUrl()); toolBoxVo.setHeatValue(0L); toolBoxVo.setIsFavorite(false); toolBoxVo.setMcpTooId(mcp.getId()); diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/workflow/WorkflowService.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/workflow/WorkflowService.java index ec3fdd2bfb21a7caf0f96dac7b5ef30fbbf5bcc9..5343d2dcf4b4af9e9877362646b3ea9a27430387 100644 --- a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/workflow/WorkflowService.java +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/workflow/WorkflowService.java @@ -2593,7 +2593,7 @@ public class WorkflowService extends ServiceImpl { return vo; } - private JSONObject getIoTrans(List nodes) { + public JSONObject getIoTrans(List nodes) { if (nodes.isEmpty()) { return null; } diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/util/OkHttpUtil.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/util/OkHttpUtil.java index f48e4a263600dd794cb4a64162649ea5f1f355c8..12e347dc0b1d9cc1b49854914a5f2ed547bdf2dd 100644 --- a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/util/OkHttpUtil.java +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/util/OkHttpUtil.java @@ -5,7 +5,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.Cookie; import okhttp3.*; import okhttp3.internal.sse.RealEventSource; -import okhttp3.sse.EventSourceListener; +import okhttp3.sse.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.multipart.MultipartFile; @@ -878,6 +878,30 @@ public class OkHttpUtil { realEventSource.connect(HTTP_CLIENT); // The actual start of the request } + public static EventSource connectRealEventSourceReturn( + String url, + Map headers, + String jsonBody, + EventSourceListener listener) { + + RequestBody body = RequestBody.create(jsonBody == null ? "{}" : jsonBody, MediaType.get("application/json; charset=utf-8")); + Request.Builder rb = new Request.Builder() + .url(url) + .addHeader("Accept", "text/event-stream") + .addHeader("Content-Type", "application/json"); + + if (headers != null) + headers.forEach((k, v) -> { + if (v != null) + rb.addHeader(k, v); + }); + + Request req = rb.post(body).build(); + EventSource.Factory factory = EventSources.createFactory(HTTP_CLIENT); + return factory.newEventSource(req, listener); + } + + /** * Establish an SSE (Server-Sent Events) connection using a prepared {@link RequestBody}. * diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/util/RedisUtil.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/util/RedisUtil.java index 9591b177489ca59aec13e919f502d4ede46f4f7a..9c20e9e4b302ebe863a5492bed416ce6b911e164 100644 --- a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/util/RedisUtil.java +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/util/RedisUtil.java @@ -2,9 +2,7 @@ package com.iflytek.astron.console.toolkit.util; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.redis.core.Cursor; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.ScanOptions; +import org.springframework.data.redis.core.*; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; @@ -43,6 +41,8 @@ public class RedisUtil { @Resource private RedisTemplate redisTemplate; + @Resource + private StringRedisTemplate stringRedisTemplate; /* ========================= Constants & Precompiled Scripts ========================= */ @@ -84,11 +84,13 @@ public class RedisUtil { requireKey(key); long ttl = Math.max(1, ttlSeconds); String val = token != null ? token : UUID.randomUUID().toString(); - Boolean ok = redisTemplate.opsForValue().setIfAbsent(key, val, ttl, TimeUnit.SECONDS); + Boolean ok = stringRedisTemplate.opsForValue() + .setIfAbsent(key, val, ttl, TimeUnit.SECONDS); log.debug("redis.tryLock key={}, ttl={}s, token={}, ok={}", key, ttl, safe(val), ok); return Boolean.TRUE.equals(ok); } + /** * Acquire a distributed lock (with token). * @@ -116,11 +118,12 @@ public class RedisUtil { public boolean renew(String key, long ttlSeconds, String token) { requireKey(key); Objects.requireNonNull(token, "token must not be null"); - long pttl = Math.max(1, ttlSeconds) * 1000L; - Long ret = redisTemplate.execute(LUA_RENEW, + String pttl = String.valueOf(Math.max(1, ttlSeconds) * 1000L); + Long ret = stringRedisTemplate.execute( + LUA_RENEW, Collections.singletonList(key), - token, - pttl); + token, pttl // ——全部是字符串 + ); boolean ok = ret != null && ret > 0; log.debug("redis.renew key={}, ttl={}s, token={}, ok={}", key, ttlSeconds, safe(token), ok); return ok; @@ -152,7 +155,10 @@ public class RedisUtil { public boolean unlock(String key, String token) { requireKey(key); Objects.requireNonNull(token, "token must not be null"); - Long ret = redisTemplate.execute(LUA_UNLOCK, Collections.singletonList(key), token); + Long ret = stringRedisTemplate.execute( + LUA_UNLOCK, + Collections.singletonList(key), + token); boolean ok = ret != null && ret > 0; log.debug("redis.unlock key={}, token={}, ok={}", key, safe(token), ok); return ok; diff --git a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/util/S3Util.java b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/util/S3Util.java index 9e2a365d2e995b8e94dae75ca7ac29f5927f3693..9602b55a8e3a30753af7ef351ab24a7bb4ba810a 100644 --- a/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/util/S3Util.java +++ b/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/util/S3Util.java @@ -55,6 +55,9 @@ public class S3Util { @Value("${s3.endpoint}") private String endpoint; + @Value("${s3.remoteEndpoint}") + private String remoteEndpoint; + @Value("${s3.accessKey}") private String accessKey; @@ -281,7 +284,7 @@ public class S3Util { * @return direct URL string */ public String getS3Url(String key) { - String base = (hostname == null || hostname.isEmpty()) ? endpoint : ("https://" + hostname); + String base = (hostname == null || hostname.isEmpty()) ? remoteEndpoint : ("https://" + hostname); String url = base + "/" + bucketName; try { for (String p : key.split("/")) { @@ -300,7 +303,7 @@ public class S3Util { * @return URL prefix ending with "/" */ public String getS3Prefix() { - String base = (hostname == null || hostname.isEmpty()) ? endpoint : ("https://" + hostname); + String base = (hostname == null || hostname.isEmpty()) ? remoteEndpoint : ("https://" + hostname); return base + "/" + bucketName + "/"; } @@ -311,7 +314,7 @@ public class S3Util { * @return direct URL string */ public String getS3UrlForKnowledge(String key) { - String base = (hostname == null || hostname.isEmpty()) ? endpoint : ("http://" + hostname); + String base = (hostname == null || hostname.isEmpty()) ? remoteEndpoint : ("http://" + hostname); return base + "/" + bucketName + "/" + key; } @@ -326,6 +329,9 @@ public class S3Util { * @return presigned URL string * @throws BusinessException when presign generation fails */ + // Deprecated: use com.iflytek.astron.console.commons.util.S3ClientUtil.generatePresignedPutUrl() + // instead + @Deprecated(forRemoval = true) public String generatePresignedPutUrl(String objectKey, Integer expirySeconds) { try { int exp = (expirySeconds != null && expirySeconds > 0) ? expirySeconds : presignExpirySeconds; diff --git a/console/backend/toolkit/src/main/resources/application-toolkit.yml b/console/backend/toolkit/src/main/resources/application-toolkit.yml index 1d71da09336afc1642641f81c3fd35765ca23285..39353cb9208e171ee77d58ff3d1592c749b16f26 100644 --- a/console/backend/toolkit/src/main/resources/application-toolkit.yml +++ b/console/backend/toolkit/src/main/resources/application-toolkit.yml @@ -23,6 +23,7 @@ api: tenantKey: ${TENANT_KEY:tenantKey} tenantSecret: ${TENANT_SECRET:tenantSecret} toolUrl: ${TOOL_URL:http://127.0.0.1:18888} + toolRpaUrl: ${TOOL_RPA_URL:http://127.0.0.1:17198} workflow: ${WORKFLOW_URL:http://127.0.0.1:7880} sparkDB: ${SPARK_DB_URL:http://127.0.0.1:7990} sparkDocUrl: https://chatdoc.xfyun.cn @@ -34,6 +35,7 @@ api: deleteXinghuoDatasetFileUrl: http://127.0.0.1:8080/dataset/deleteXinghuoDatasetFile deleteXinghuoDatasetUrl: http://127.0.0.1:8080/dataset/deleteXinghuoDataset rpaUrl: ${RPA_URL:https://newapi.iflyrpa.com} + appIdQryUrl: http://10.1.87.65:5052 # Business-specific configuration biz: @@ -70,10 +72,11 @@ task: wait-for-tasks-to-complete-on-shutdown: true executor: - core-pool-size: 8 - max-pool-size: 16 - queue-capacity: 2000 - keep-alive-seconds: 60 + # Optimized thread pool configuration for reduced memory usage + core-pool-size: 4 + max-pool-size: 10 + queue-capacity: 1000 + keep-alive-seconds: 30 allow-core-thread-timeout: false thread-name-prefix: app-async- await-termination-seconds: 20 diff --git a/console/backend/toolkit/src/main/resources/mybatis/mapper/mysql/KnowledgeMapper.xml b/console/backend/toolkit/src/main/resources/mybatis/mapper/mysql/KnowledgeMapper.xml index 5641fc1b41f5ac853000ef08a89a1e0a77cf426c..48b052a2712849895833c45ce1589cf00da38e91 100644 --- a/console/backend/toolkit/src/main/resources/mybatis/mapper/mysql/KnowledgeMapper.xml +++ b/console/backend/toolkit/src/main/resources/mybatis/mapper/mysql/KnowledgeMapper.xml @@ -162,4 +162,33 @@ SELECT COUNT(*) FROM knowledge WHERE file_id = #{fileId} AND enabled = #{enabled} + + + + + + \ No newline at end of file diff --git a/console/backend/toolkit/src/test/java/com/iflytek/astron/console/toolkit/controller/knowledge/FileControllerTest.java b/console/backend/toolkit/src/test/java/com/iflytek/astron/console/toolkit/controller/knowledge/FileControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6dde5c51812388977cdb6a4bcb095f3dbf09b42b --- /dev/null +++ b/console/backend/toolkit/src/test/java/com/iflytek/astron/console/toolkit/controller/knowledge/FileControllerTest.java @@ -0,0 +1,1274 @@ +package com.iflytek.astron.console.toolkit.controller.knowledge; + +import com.iflytek.astron.console.commons.constant.ResponseEnum; +import com.iflytek.astron.console.commons.exception.BusinessException; +import com.iflytek.astron.console.commons.response.ApiResult; +import com.iflytek.astron.console.toolkit.common.Result; +import com.iflytek.astron.console.toolkit.entity.common.PageData; +import com.iflytek.astron.console.toolkit.entity.dto.FileInfoV2Dto; +import com.iflytek.astron.console.toolkit.entity.dto.KnowledgeDto; +import com.iflytek.astron.console.toolkit.entity.pojo.FileSummary; +import com.iflytek.astron.console.toolkit.entity.pojo.SliceConfig; +import com.iflytek.astron.console.toolkit.entity.table.repo.FileDirectoryTree; +import com.iflytek.astron.console.toolkit.entity.table.repo.FileInfoV2; +import com.iflytek.astron.console.toolkit.entity.vo.HtmlFileVO; +import com.iflytek.astron.console.toolkit.entity.vo.repo.CreateFolderVO; +import com.iflytek.astron.console.toolkit.entity.vo.repo.DealFileVO; +import com.iflytek.astron.console.toolkit.entity.vo.repo.KnowledgeQueryVO; +import com.iflytek.astron.console.toolkit.service.repo.FileInfoV2Service; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +/** + * Unit tests for FileController + * + * Technology Stack: JUnit5 + Mockito + AssertJ Coverage Requirements: - JaCoCo Statement Coverage + * >= 80% - JaCoCo Branch Coverage >= 90% - High PIT Mutation Test Score - Covers normal flows, edge + * cases, and exceptions + * + * @author AI Assistant + */ +@ExtendWith(MockitoExtension.class) +@DisplayName("FileController Unit Tests") +class FileControllerTest { + + @Mock + private FileInfoV2Service fileInfoV2Service; + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + @Mock + private MultipartFile multipartFile; + + @InjectMocks + private FileController fileController; + + private FileInfoV2 mockFileInfo; + private DealFileVO dealFileVO; + private CreateFolderVO createFolderVO; + private HtmlFileVO htmlFileVO; + private KnowledgeQueryVO knowledgeQueryVO; + + /** + * Set up test fixtures before each test Initializes common test data including mock file info, VO + * objects, and query parameters + */ + @BeforeEach + void setUp() { + // Initialize common test data + mockFileInfo = new FileInfoV2(); + mockFileInfo.setId(1L); + mockFileInfo.setName("test-file.txt"); + mockFileInfo.setRepoId(100L); + + dealFileVO = new DealFileVO(); + dealFileVO.setRepoId(100L); + dealFileVO.setFileIds(Arrays.asList("1", "2", "3")); + SliceConfig sliceConfig = new SliceConfig(); + sliceConfig.setSeperator(Collections.singletonList("\\n")); + dealFileVO.setSliceConfig(sliceConfig); + + createFolderVO = new CreateFolderVO(); + createFolderVO.setId(1L); + createFolderVO.setRepoId(100L); + createFolderVO.setName("test-folder"); + createFolderVO.setParentId(0L); + + htmlFileVO = new HtmlFileVO(); + htmlFileVO.setRepoId(100L); + htmlFileVO.setParentId(0L); + htmlFileVO.setHtmlAddressList(Arrays.asList("http://example.com/page1.html")); + + knowledgeQueryVO = new KnowledgeQueryVO(); + knowledgeQueryVO.setPageNo(1); + knowledgeQueryVO.setPageSize(10); + knowledgeQueryVO.setTag("test-tag"); + } + + /** + * Test cases for file upload operations + */ + @Nested + @DisplayName("File Upload Tests") + class FileUploadTests { + + /** + * Test successful file upload Verifies that a file can be uploaded successfully and returns correct + * result + */ + @Test + @DisplayName("Upload file successfully") + void uploadFile_Success() { + // Given + Long parentId = 0L; + Long repoId = 100L; + String tag = "test-tag"; + when(fileInfoV2Service.uploadFile(multipartFile, parentId, repoId, tag, request)) + .thenReturn(mockFileInfo); + + // When + ApiResult result = fileController.uploadFile(multipartFile, parentId, repoId, tag, request); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isEqualTo(mockFileInfo); + verify(fileInfoV2Service, times(1)).uploadFile(multipartFile, parentId, repoId, tag, request); + } + + /** + * Test file upload with empty file name Verifies that uploading a file with empty name throws + * BusinessException + */ + @Test + @DisplayName("Upload file - Empty file name") + void uploadFile_EmptyFileName() { + // Given + Long parentId = 0L; + Long repoId = 100L; + String tag = "test-tag"; + when(fileInfoV2Service.uploadFile(multipartFile, parentId, repoId, tag, request)) + .thenThrow(new BusinessException(ResponseEnum.REPO_FILE_NAME_CANNOT_EMPTY)); + + // When & Then + assertThatThrownBy(() -> fileController.uploadFile(multipartFile, parentId, repoId, tag, request)) + .isInstanceOf(BusinessException.class); + verify(fileInfoV2Service, times(1)).uploadFile(multipartFile, parentId, repoId, tag, request); + } + + /** + * Test successful HTML file creation Verifies that HTML files can be created from URL addresses + */ + @Test + @DisplayName("Create HTML file successfully") + void createHtmlFile_Success() { + // Given + List expectedFiles = Arrays.asList(mockFileInfo); + when(fileInfoV2Service.createHtmlFile(htmlFileVO)).thenReturn(expectedFiles); + + // When + ApiResult> result = fileController.createHtmlFile(htmlFileVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).hasSize(1); + assertThat(result.data().get(0)).isEqualTo(mockFileInfo); + verify(fileInfoV2Service, times(1)).createHtmlFile(htmlFileVO); + } + + /** + * Test HTML file creation with empty address list Verifies that creating HTML files with empty + * address list returns empty result + */ + @Test + @DisplayName("Create HTML file - Empty address list") + void createHtmlFile_EmptyAddressList() { + // Given + htmlFileVO.setHtmlAddressList(Collections.emptyList()); + when(fileInfoV2Service.createHtmlFile(htmlFileVO)).thenReturn(Collections.emptyList()); + + // When + ApiResult> result = fileController.createHtmlFile(htmlFileVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isEmpty(); + verify(fileInfoV2Service, times(1)).createHtmlFile(htmlFileVO); + } + } + + /** + * Test cases for file slicing operations + */ + @Nested + @DisplayName("File Slice Tests") + class FileSliceTests { + + /** + * Test successful file slicing with normal separator Verifies that files can be sliced successfully + * with provided separator + * + * @throws InterruptedException if the operation is interrupted + * @throws ExecutionException if the operation fails during execution + */ + @Test + @DisplayName("Slice files successfully - With separator") + void sliceFiles_Success_WithSeparator() throws InterruptedException, ExecutionException { + // Given + @SuppressWarnings("unchecked") + Result successResult = mock(Result.class); + when(successResult.noError()).thenReturn(true); + when(successResult.getData()).thenReturn(true); + when(fileInfoV2Service.sliceFiles(dealFileVO)).thenReturn(successResult); + + // When + ApiResult result = fileController.sliceFiles(dealFileVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isTrue(); + verify(fileInfoV2Service, times(1)).sliceFiles(dealFileVO); + } + + /** + * Test successful file slicing with empty separator defaults to newline Verifies that empty + * separator is automatically replaced with default newline separator + * + * @throws InterruptedException if the operation is interrupted + * @throws ExecutionException if the operation fails during execution + */ + @Test + @DisplayName("Slice files successfully - Empty separator defaults to newline") + void sliceFiles_Success_EmptySeparatorDefaultsToNewline() throws InterruptedException, ExecutionException { + // Given + dealFileVO.getSliceConfig().setSeperator(Collections.singletonList("")); + @SuppressWarnings("unchecked") + Result successResult = mock(Result.class); + when(successResult.noError()).thenReturn(true); + when(successResult.getData()).thenReturn(true); + when(fileInfoV2Service.sliceFiles(dealFileVO)).thenReturn(successResult); + + // When + ApiResult result = fileController.sliceFiles(dealFileVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isTrue(); + assertThat(dealFileVO.getSliceConfig().getSeperator()).containsExactly("\n"); + verify(fileInfoV2Service, times(1)).sliceFiles(dealFileVO); + } + + /** + * Test successful file slicing with null separator defaults to newline Verifies that null separator + * is automatically replaced with default newline separator + * + * @throws InterruptedException if the operation is interrupted + * @throws ExecutionException if the operation fails during execution + */ + @Test + @DisplayName("Slice files successfully - Null separator defaults to newline") + void sliceFiles_Success_NullSeparatorDefaultsToNewline() throws InterruptedException, ExecutionException { + // Given + dealFileVO.getSliceConfig().setSeperator(Collections.singletonList(null)); + @SuppressWarnings("unchecked") + Result successResult = mock(Result.class); + when(successResult.noError()).thenReturn(true); + when(successResult.getData()).thenReturn(true); + when(fileInfoV2Service.sliceFiles(dealFileVO)).thenReturn(successResult); + + // When + ApiResult result = fileController.sliceFiles(dealFileVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(dealFileVO.getSliceConfig().getSeperator()).containsExactly("\n"); + verify(fileInfoV2Service, times(1)).sliceFiles(dealFileVO); + } + + /** + * Test file slicing failure with error message returned Verifies that slicing failure returns + * appropriate error code and message + * + * @throws InterruptedException if the operation is interrupted + * @throws ExecutionException if the operation fails during execution + */ + @Test + @DisplayName("Slice files failure - Returns error") + void sliceFiles_Failure_ReturnsError() throws InterruptedException, ExecutionException { + // Given + @SuppressWarnings("unchecked") + Result failureResult = mock(Result.class); + when(failureResult.noError()).thenReturn(false); + when(failureResult.getCode()).thenReturn(500); + when(failureResult.getMessage()).thenReturn("Slice failed"); + when(fileInfoV2Service.sliceFiles(dealFileVO)).thenReturn(failureResult); + + // When + ApiResult result = fileController.sliceFiles(dealFileVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(500); + assertThat(result.message()).isEqualTo("Slice failed"); + verify(fileInfoV2Service, times(1)).sliceFiles(dealFileVO); + } + + /** + * Test file slicing throws InterruptedException + * Verifies that InterruptedException is properly propagated when thread is interrupted + * + * @throws InterruptedException if the operation is interrupted + * @throws ExecutionException if the operation fails during execution + */ + @Test + @DisplayName("Slice files - Throws InterruptedException") + void sliceFiles_ThrowsInterruptedException() throws InterruptedException, ExecutionException { + // Given + when(fileInfoV2Service.sliceFiles(dealFileVO)).thenThrow(new InterruptedException("Thread interrupted")); + + // When & Then + assertThatThrownBy(() -> fileController.sliceFiles(dealFileVO)) + .isInstanceOf(InterruptedException.class) + .hasMessage("Thread interrupted"); + verify(fileInfoV2Service, times(1)).sliceFiles(dealFileVO); + } + } + + /** + * Test cases for file embedding operations + */ + @Nested + @DisplayName("File Embedding Tests") + class FileEmbeddingTests { + + /** + * Test successful file embedding Verifies that files can be embedded successfully without errors + * + * @throws ExecutionException if the operation fails during execution + * @throws InterruptedException if the operation is interrupted + */ + @Test + @DisplayName("Embedding files successfully") + void embeddingFiles_Success() throws ExecutionException, InterruptedException { + // Given + doNothing().when(fileInfoV2Service).embeddingFiles(dealFileVO, request); + + // When + ApiResult result = fileController.embeddingFiles(dealFileVO, request); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + verify(fileInfoV2Service, times(1)).embeddingFiles(dealFileVO, request); + } + + /** + * Test file embedding throws RuntimeException Verifies that RuntimeException is properly thrown + * when embedding fails + * + * @throws ExecutionException if the operation fails during execution + * @throws InterruptedException if the operation is interrupted + */ + @Test + @DisplayName("Embedding files - Throws RuntimeException") + void embeddingFiles_ThrowsRuntimeException() throws ExecutionException, InterruptedException { + // Given + doThrow(new RuntimeException("Embedding failed")) + .when(fileInfoV2Service) + .embeddingFiles(dealFileVO, request); + + // When & Then + assertThatThrownBy(() -> fileController.embeddingFiles(dealFileVO, request)) + .isInstanceOf(RuntimeException.class) + .hasMessage("Embedding failed"); + verify(fileInfoV2Service, times(1)).embeddingFiles(dealFileVO, request); + } + + /** + * Test successful background file embedding Verifies that files can be embedded in background + * successfully + * + * @throws ExecutionException if the operation fails during execution + * @throws InterruptedException if the operation is interrupted + */ + @Test + @DisplayName("Background embedding successfully") + void embeddingBack_Success() throws ExecutionException, InterruptedException { + // Given + doNothing().when(fileInfoV2Service).embeddingBack(dealFileVO, request); + + // When + ApiResult result = fileController.embeddingBack(dealFileVO, request); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + verify(fileInfoV2Service, times(1)).embeddingBack(dealFileVO, request); + } + + /** + * Test retry failed files Verifies that failed files can be retried successfully + * + * @throws ExecutionException if the operation fails during execution + * @throws InterruptedException if the operation is interrupted + */ + @Test + @DisplayName("Retry failed files") + void retry_Success() throws ExecutionException, InterruptedException { + // Given + doNothing().when(fileInfoV2Service).retry(dealFileVO, request); + + // When + ApiResult result = fileController.retry(dealFileVO, request); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + verify(fileInfoV2Service, times(1)).retry(dealFileVO, request); + } + } + + /** + * Test cases for file status query operations + */ + @Nested + @DisplayName("File Status Query Tests") + class FileStatusTests { + + /** + * Test get file indexing status Verifies that file indexing status can be retrieved successfully + */ + @Test + @DisplayName("Get file indexing status") + void getIndexingStatus_Success() { + // Given + List expectedStatus = Arrays.asList(new FileInfoV2Dto(), new FileInfoV2Dto()); + when(fileInfoV2Service.getIndexingStatus(dealFileVO)).thenReturn(expectedStatus); + + // When + ApiResult> result = fileController.getIndexingStatus(dealFileVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).hasSize(2); + verify(fileInfoV2Service, times(1)).getIndexingStatus(dealFileVO); + } + + /** + * Test get file summary information Verifies that file summary information can be retrieved + * successfully + */ + @Test + @DisplayName("Get file summary information") + void getFileSummary_Success() { + // Given + FileSummary expectedSummary = new FileSummary(); + when(fileInfoV2Service.getFileSummary(dealFileVO, request)).thenReturn(expectedSummary); + + // When + ApiResult result = fileController.getFileSummary(dealFileVO, request); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isEqualTo(expectedSummary); + verify(fileInfoV2Service, times(1)).getFileSummary(dealFileVO, request); + } + + /** + * Test get file info by sourceId Verifies that file information can be retrieved by sourceId + * successfully + */ + @Test + @DisplayName("Get file info by sourceId") + void getFileInfoV2BySourceId_Success() { + // Given + String sourceId = "source-123"; + when(fileInfoV2Service.getFileInfoV2BySourceId(sourceId)).thenReturn(mockFileInfo); + + // When + ApiResult result = fileController.getFileInfoV2BySourceId(sourceId); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isEqualTo(mockFileInfo); + verify(fileInfoV2Service, times(1)).getFileInfoV2BySourceId(sourceId); + } + } + + /** + * Test cases for knowledge base operations + */ + @Nested + @DisplayName("Knowledge Base Tests") + class KnowledgeTests { + + /** + * Test list preview knowledge by page Verifies that preview knowledge can be queried with + * pagination successfully + */ + @Test + @DisplayName("List preview knowledge by page") + void listPreviewKnowledgeByPage_Success() { + // Given + Object expectedResult = new Object(); + when(fileInfoV2Service.listPreviewKnowledgeByPage(knowledgeQueryVO)).thenReturn(expectedResult); + + // When + Object result = fileController.listPreviewKnowledgeByPage(knowledgeQueryVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result).isEqualTo(expectedResult); + verify(fileInfoV2Service, times(1)).listPreviewKnowledgeByPage(knowledgeQueryVO); + } + + /** + * Test list knowledge by page Verifies that knowledge can be queried with pagination successfully + */ + @Test + @DisplayName("List knowledge by page") + void listKnowledgeByPage_Success() { + // Given + PageData expectedPage = new PageData<>(); + expectedPage.setTotalCount(10L); + when(fileInfoV2Service.listKnowledgeByPage(knowledgeQueryVO)).thenReturn(expectedPage); + + // When + ApiResult> result = fileController.listKnowledgeByPage(knowledgeQueryVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data().getTotalCount()).isEqualTo(10L); + verify(fileInfoV2Service, times(1)).listKnowledgeByPage(knowledgeQueryVO); + } + + /** + * Test download knowledge by violation Verifies that knowledge marked as violation can be + * downloaded successfully + */ + @Test + @DisplayName("Download knowledge by violation") + void downloadKnowledgeByViolation_Success() { + // Given + doNothing().when(fileInfoV2Service).downloadKnowledgeByViolation(response, knowledgeQueryVO); + + // When + fileController.downloadKnowledgeByViolation(response, knowledgeQueryVO); + + // Then + verify(fileInfoV2Service, times(1)).downloadKnowledgeByViolation(response, knowledgeQueryVO); + } + } + + /** + * Test cases for file list query operations + */ + @Nested + @DisplayName("File List Query Tests") + class FileQueryTests { + + /** + * Test query file list with default parameters Verifies that file list can be queried with default + * pagination parameters + */ + @Test + @DisplayName("Query file list - With defaults") + void queryFileList_WithDefaults() { + // Given + Long repoId = 100L; + Object expectedResult = new Object(); + when(fileInfoV2Service.queryFileList(repoId, -1L, 1, 10, "", request, 1)) + .thenReturn(expectedResult); + + // When + Object result = fileController.queryFileList(repoId, -1L, 1, 10, "", 1, request); + + // Then + assertThat(result).isNotNull(); + assertThat(result).isEqualTo(expectedResult); + verify(fileInfoV2Service, times(1)).queryFileList(repoId, -1L, 1, 10, "", request, 1); + } + + /** + * Test query file list with custom parameters Verifies that file list can be queried with custom + * pagination and filter parameters + */ + @Test + @DisplayName("Query file list - With custom params") + void queryFileList_WithCustomParams() { + // Given + Long repoId = 100L; + Long parentId = 50L; + Integer pageNo = 2; + Integer pageSize = 20; + String tag = "custom-tag"; + Integer isRepoPage = 0; + Object expectedResult = new Object(); + when(fileInfoV2Service.queryFileList(repoId, parentId, pageNo, pageSize, tag, request, isRepoPage)) + .thenReturn(expectedResult); + + // When + Object result = fileController.queryFileList(repoId, parentId, pageNo, pageSize, tag, isRepoPage, request); + + // Then + assertThat(result).isNotNull(); + verify(fileInfoV2Service, times(1)).queryFileList(repoId, parentId, pageNo, pageSize, tag, request, isRepoPage); + } + + /** + * Test search file Verifies that files can be searched with specified criteria and returns SSE + * emitter + */ + @Test + @DisplayName("Search file") + void searchFile_Success() { + // Given + Long repoId = 100L; + String fileName = "test"; + Integer isFile = 1; + Long pid = 50L; + String tag = "tag"; + Integer isRepoPage = 1; + SseEmitter expectedEmitter = new SseEmitter(); + when(fileInfoV2Service.searchFile(repoId, fileName, isFile, pid, tag, isRepoPage, request)) + .thenReturn(expectedEmitter); + + // When + SseEmitter result = fileController.searchFile(repoId, fileName, isFile, pid, tag, isRepoPage, response, request); + + // Then + assertThat(result).isNotNull(); + assertThat(result).isEqualTo(expectedEmitter); + verify(response, times(1)).addHeader("X-Accel-Buffering", "no"); + verify(fileInfoV2Service, times(1)).searchFile(repoId, fileName, isFile, pid, tag, isRepoPage, request); + } + + /** + * Test search file with null parameters Verifies that file search can handle null parameters + * gracefully + */ + @Test + @DisplayName("Search file - With null params") + void searchFile_WithNullParams() { + // Given + Long repoId = 100L; + SseEmitter expectedEmitter = new SseEmitter(); + when(fileInfoV2Service.searchFile(repoId, null, null, null, null, 1, request)) + .thenReturn(expectedEmitter); + + // When + SseEmitter result = fileController.searchFile(repoId, null, null, null, null, 1, response, request); + + // Then + assertThat(result).isNotNull(); + verify(response, times(1)).addHeader("X-Accel-Buffering", "no"); + verify(fileInfoV2Service, times(1)).searchFile(repoId, null, null, null, null, 1, request); + } + } + + /** + * Test cases for folder operations + */ + @Nested + @DisplayName("Folder Operations Tests") + class FolderOperationsTests { + + /** + * Test create folder successfully without tags Verifies that a folder can be created without any + * tags + */ + @Test + @DisplayName("Create folder successfully - No tags") + void createFolder_Success_NoTags() { + // Given + createFolderVO.setTags(null); + doNothing().when(fileInfoV2Service).createFolder(createFolderVO); + + // When + ApiResult result = fileController.createFolder(createFolderVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + verify(fileInfoV2Service, times(1)).createFolder(createFolderVO); + } + + /** + * Test create folder successfully with valid tags Verifies that a folder can be created with tags + * of normal length + */ + @Test + @DisplayName("Create folder successfully - With valid tags") + void createFolder_Success_WithValidTags() { + // Given + createFolderVO.setTags(Arrays.asList("tag1", "tag2", "tag3")); + doNothing().when(fileInfoV2Service).createFolder(createFolderVO); + + // When + ApiResult result = fileController.createFolder(createFolderVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + verify(fileInfoV2Service, times(1)).createFolder(createFolderVO); + } + + /** + * Test create folder successfully with max length tag Verifies that a folder can be created with + * tag exactly 30 characters long + */ + @Test + @DisplayName("Create folder successfully - With max length tag") + void createFolder_Success_WithMaxLengthTag() { + // Given + String maxLengthTag = "a".repeat(30); + createFolderVO.setTags(Collections.singletonList(maxLengthTag)); + doNothing().when(fileInfoV2Service).createFolder(createFolderVO); + + // When + ApiResult result = fileController.createFolder(createFolderVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + verify(fileInfoV2Service, times(1)).createFolder(createFolderVO); + } + + /** + * Test create folder failure when tag is too long Verifies that folder creation fails when tag + * exceeds 30 characters + */ + @Test + @DisplayName("Create folder failure - Tag too long") + void createFolder_Failure_TagTooLong() { + // Given + String tooLongTag = "a".repeat(31); + createFolderVO.setTags(Collections.singletonList(tooLongTag)); + + // When & Then + assertThatThrownBy(() -> fileController.createFolder(createFolderVO)) + .isInstanceOf(BusinessException.class) + .hasFieldOrPropertyWithValue("responseEnum", ResponseEnum.REPO_KNOWLEDGE_TAG_TOO_LONG); + verify(fileInfoV2Service, never()).createFolder(any()); + } + + /** + * Test create folder failure when one of many tags is too long Verifies that folder creation fails + * when at least one tag exceeds length limit + */ + @Test + @DisplayName("Create folder failure - One of many tags too long") + void createFolder_Failure_OneOfManyTagsTooLong() { + // Given + createFolderVO.setTags(Arrays.asList("tag1", "tag2", "a".repeat(31))); + + // When & Then + assertThatThrownBy(() -> fileController.createFolder(createFolderVO)) + .isInstanceOf(BusinessException.class); + verify(fileInfoV2Service, never()).createFolder(any()); + } + + /** + * Test create folder successfully with empty tag list Verifies that a folder can be created with an + * empty tag list + */ + @Test + @DisplayName("Create folder successfully - Empty tag list") + void createFolder_Success_EmptyTagList() { + // Given + createFolderVO.setTags(Collections.emptyList()); + doNothing().when(fileInfoV2Service).createFolder(createFolderVO); + + // When + ApiResult result = fileController.createFolder(createFolderVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + verify(fileInfoV2Service, times(1)).createFolder(createFolderVO); + } + + /** + * Test update folder successfully Verifies that a folder can be updated successfully + */ + @Test + @DisplayName("Update folder successfully") + void updateFolder_Success() { + // Given + doNothing().when(fileInfoV2Service).updateFolder(createFolderVO); + + // When + ApiResult result = fileController.updateFolder(createFolderVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + verify(fileInfoV2Service, times(1)).updateFolder(createFolderVO); + } + + /** + * Test delete folder successfully Verifies that a folder can be deleted successfully + */ + @Test + @DisplayName("Delete folder successfully") + void deleteFolder_Success() { + // Given + Long folderId = 123L; + doNothing().when(fileInfoV2Service).deleteFolder(folderId); + + // When + ApiResult result = fileController.deleteFolder(folderId); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + verify(fileInfoV2Service, times(1)).deleteFolder(folderId); + } + } + + /** + * Test cases for file operations + */ + @Nested + @DisplayName("File Operations Tests") + class FileOperationsTests { + + /** + * Test update file successfully Verifies that a file can be updated successfully + */ + @Test + @DisplayName("Update file successfully") + void updateFile_Success() { + // Given + doNothing().when(fileInfoV2Service).updateFile(createFolderVO); + + // When + ApiResult result = fileController.updateFile(createFolderVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + verify(fileInfoV2Service, times(1)).updateFile(createFolderVO); + } + + /** + * Test delete file successfully Verifies that a file can be deleted successfully + */ + @Test + @DisplayName("Delete file successfully") + void deleteFile_Success() { + // Given + String fileId = "file-123"; + String tag = "test-tag"; + Long repoId = 100L; + doNothing().when(fileInfoV2Service).deleteFileDirectoryTree(fileId, tag, repoId, request); + + // When + ApiResult result = fileController.deleteFile(fileId, tag, repoId, request); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + verify(fileInfoV2Service, times(1)).deleteFileDirectoryTree(fileId, tag, repoId, request); + } + + /** + * Test enable file Verifies that a file can be enabled successfully + */ + @Test + @DisplayName("Enable file") + void enableFile_Enable() { + // Given + Long fileId = 123L; + Integer enabled = 1; + doNothing().when(fileInfoV2Service).enableFile(fileId, enabled); + + // When + ApiResult result = fileController.enableFile(fileId, enabled); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + verify(fileInfoV2Service, times(1)).enableFile(fileId, enabled); + } + + /** + * Test disable file Verifies that a file can be disabled successfully + */ + @Test + @DisplayName("Disable file") + void enableFile_Disable() { + // Given + Long fileId = 123L; + Integer enabled = 0; + doNothing().when(fileInfoV2Service).enableFile(fileId, enabled); + + // When + ApiResult result = fileController.enableFile(fileId, enabled); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + verify(fileInfoV2Service, times(1)).enableFile(fileId, enabled); + } + + /** + * Test get file directory tree Verifies that file directory tree can be retrieved successfully + */ + @Test + @DisplayName("Get file directory tree") + void listFileDirectoryTree_Success() { + // Given + Long fileId = 123L; + List expectedTree = Arrays.asList( + new FileDirectoryTree(), + new FileDirectoryTree()); + when(fileInfoV2Service.listFileDirectoryTree(fileId)).thenReturn(expectedTree); + + // When + ApiResult> result = fileController.listFileDirectoryTree(fileId); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).hasSize(2); + verify(fileInfoV2Service, times(1)).listFileDirectoryTree(fileId); + } + + /** + * Test get file directory tree with empty result Verifies that empty result is handled correctly + * when file has no directory tree + */ + @Test + @DisplayName("Get file directory tree - Empty result") + void listFileDirectoryTree_EmptyResult() { + // Given + Long fileId = 999L; + when(fileInfoV2Service.listFileDirectoryTree(fileId)).thenReturn(Collections.emptyList()); + + // When + ApiResult> result = fileController.listFileDirectoryTree(fileId); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isEmpty(); + verify(fileInfoV2Service, times(1)).listFileDirectoryTree(fileId); + } + } + + /** + * Test cases for edge conditions + */ + @Nested + @DisplayName("Edge Case Tests") + class EdgeCaseTests { + + /** + * Test sliceFiles with empty separator list Verifies that empty separator list causes + * IndexOutOfBoundsException + * + * @throws InterruptedException if the operation is interrupted + * @throws ExecutionException if the operation fails during execution + */ + @Test + @DisplayName("sliceFiles - Empty separator list") + void sliceFiles_EmptySeparatorList() throws InterruptedException, ExecutionException { + // Given + dealFileVO.getSliceConfig().setSeperator(Collections.emptyList()); + + // When & Then - Verify edge condition + assertThatThrownBy(() -> fileController.sliceFiles(dealFileVO)) + .isInstanceOf(IndexOutOfBoundsException.class); + } + + /** + * Test queryFileList with large page number Verifies that query works correctly with maximum + * integer page number + */ + @Test + @DisplayName("queryFileList - Large page number") + void queryFileList_LargePageNumber() { + // Given + Long repoId = 100L; + Integer largePageNo = Integer.MAX_VALUE; + Object expectedResult = new Object(); + when(fileInfoV2Service.queryFileList(repoId, -1L, largePageNo, 10, "", request, 1)) + .thenReturn(expectedResult); + + // When + Object result = fileController.queryFileList(repoId, -1L, largePageNo, 10, "", 1, request); + + // Then + assertThat(result).isNotNull(); + verify(fileInfoV2Service, times(1)).queryFileList(repoId, -1L, largePageNo, 10, "", request, 1); + } + + /** + * Test queryFileList with large page size Verifies that query works correctly with large page size + * value + */ + @Test + @DisplayName("queryFileList - Large page size") + void queryFileList_LargePageSize() { + // Given + Long repoId = 100L; + Integer largePageSize = 1000; + Object expectedResult = new Object(); + when(fileInfoV2Service.queryFileList(repoId, -1L, 1, largePageSize, "", request, 1)) + .thenReturn(expectedResult); + + // When + Object result = fileController.queryFileList(repoId, -1L, 1, largePageSize, "", 1, request); + + // Then + assertThat(result).isNotNull(); + verify(fileInfoV2Service, times(1)).queryFileList(repoId, -1L, 1, largePageSize, "", request, 1); + } + + /** + * Test deleteFile with empty string ID Verifies that file deletion works with empty string ID + */ + @Test + @DisplayName("deleteFile - Empty string ID") + void deleteFile_EmptyStringId() { + // Given + String emptyId = ""; + String tag = "test-tag"; + Long repoId = 100L; + doNothing().when(fileInfoV2Service).deleteFileDirectoryTree(emptyId, tag, repoId, request); + + // When + ApiResult result = fileController.deleteFile(emptyId, tag, repoId, request); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + verify(fileInfoV2Service, times(1)).deleteFileDirectoryTree(emptyId, tag, repoId, request); + } + + /** + * Test createFolder with tag at boundary value Verifies that folder creation works correctly with + * tags at length boundary (29, 30 characters) + */ + @Test + @DisplayName("createFolder - Tag at boundary") + void createFolder_TagAtBoundary() { + // Given - Test with 29, 30, 31 characters + String tag29 = "a".repeat(29); + String tag30 = "a".repeat(30); + + // 29 characters should succeed + createFolderVO.setTags(Collections.singletonList(tag29)); + doNothing().when(fileInfoV2Service).createFolder(createFolderVO); + + ApiResult result1 = fileController.createFolder(createFolderVO); + assertThat(result1.code()).isEqualTo(0); + + // 30 characters should succeed + createFolderVO.setTags(Collections.singletonList(tag30)); + ApiResult result2 = fileController.createFolder(createFolderVO); + assertThat(result2.code()).isEqualTo(0); + + verify(fileInfoV2Service, times(2)).createFolder(createFolderVO); + } + } + + /** + * Test cases for exception scenarios + */ + @Nested + @DisplayName("Exception Tests") + class ExceptionTests { + + /** + * Test uploadFile when service throws exception + * Verifies that BusinessException is properly thrown when upload fails + */ + @Test + @DisplayName("uploadFile - Service throws exception") + void uploadFile_ServiceThrowsException() { + // Given + when(fileInfoV2Service.uploadFile(any(), anyLong(), anyLong(), anyString(), any())) + .thenThrow(new BusinessException(ResponseEnum.REPO_FILE_UPLOAD_FAILED)); + + // When & Then + assertThatThrownBy(() -> fileController.uploadFile(multipartFile, 0L, 100L, "tag", request)) + .isInstanceOf(BusinessException.class); + } + + /** + * Test embeddingFiles throws BusinessException Verifies that BusinessException is properly thrown + * when embedding fails + * + * @throws ExecutionException if the operation fails during execution + * @throws InterruptedException if the operation is interrupted + */ + @Test + @DisplayName("embeddingFiles - BusinessException") + void embeddingFiles_BusinessException() throws ExecutionException, InterruptedException { + // Given + doThrow(new BusinessException(ResponseEnum.REPO_FILE_EMBEDDING_FAILED)) + .when(fileInfoV2Service) + .embeddingFiles(dealFileVO, request); + + // When & Then + assertThatThrownBy(() -> fileController.embeddingFiles(dealFileVO, request)) + .isInstanceOf(BusinessException.class); + } + + /** + * Test deleteFolder when service throws exception Verifies that BusinessException is properly + * thrown when folder doesn't exist + */ + @Test + @DisplayName("deleteFolder - Service throws exception") + void deleteFolder_ServiceThrowsException() { + // Given + Long folderId = 123L; + doThrow(new BusinessException(ResponseEnum.REPO_FOLDER_NOT_EXIST)) + .when(fileInfoV2Service) + .deleteFolder(folderId); + + // When & Then + assertThatThrownBy(() -> fileController.deleteFolder(folderId)) + .isInstanceOf(BusinessException.class); + } + + /** + * Test getFileInfoV2BySourceId when file doesn't exist Verifies that BusinessException is properly + * thrown when file is not found + */ + @Test + @DisplayName("getFileInfoV2BySourceId - File not found") + void getFileInfoV2BySourceId_FileNotFound() { + // Given + String sourceId = "non-existent-id"; + when(fileInfoV2Service.getFileInfoV2BySourceId(sourceId)) + .thenThrow(new BusinessException(ResponseEnum.REPO_FILE_NOT_EXIST)); + + // When & Then + assertThatThrownBy(() -> fileController.getFileInfoV2BySourceId(sourceId)) + .isInstanceOf(BusinessException.class); + } + + /** + * Test sliceFiles throws RuntimeException + * Verifies that RuntimeException is properly thrown when slice processing fails + * + * @throws InterruptedException if the operation is interrupted + * @throws ExecutionException if the operation fails during execution + */ + @Test + @DisplayName("sliceFiles - RuntimeException") + void sliceFiles_RuntimeException() throws InterruptedException, ExecutionException { + // Given + when(fileInfoV2Service.sliceFiles(dealFileVO)) + .thenThrow(new RuntimeException("Slice processing failed")); + + // When & Then + assertThatThrownBy(() -> fileController.sliceFiles(dealFileVO)) + .isInstanceOf(RuntimeException.class) + .hasMessage("Slice processing failed"); + } + + /** + * Test createHtmlFile when service throws exception + * Verifies that BusinessException is properly thrown when HTML file creation fails + */ + @Test + @DisplayName("createHtmlFile - Service throws exception") + void createHtmlFile_ServiceThrowsException() { + // Given + when(fileInfoV2Service.createHtmlFile(htmlFileVO)) + .thenThrow(new BusinessException(ResponseEnum.REPO_FILE_UPLOAD_FAILED)); + + // When & Then + assertThatThrownBy(() -> fileController.createHtmlFile(htmlFileVO)) + .isInstanceOf(BusinessException.class); + } + } + + /** + * Test cases for multi-scenario integration + */ + @Nested + @DisplayName("Integration Tests") + class IntegrationTests { + + /** + * Test complete file processing flow including upload, slice, and embedding + * Verifies that the entire file processing workflow works correctly from start to finish + * + * @throws ExecutionException if the operation fails during execution + * @throws InterruptedException if the operation is interrupted + */ + @Test + @DisplayName("Complete file processing flow - Upload, slice, embedding") + void completeFileProcessingFlow() throws ExecutionException, InterruptedException { + // Given + when(fileInfoV2Service.uploadFile(multipartFile, 0L, 100L, "tag", request)) + .thenReturn(mockFileInfo); + @SuppressWarnings("unchecked") + Result sliceResult = mock(Result.class); + when(sliceResult.noError()).thenReturn(true); + when(sliceResult.getData()).thenReturn(true); + when(fileInfoV2Service.sliceFiles(dealFileVO)).thenReturn(sliceResult); + doNothing().when(fileInfoV2Service).embeddingFiles(dealFileVO, request); + + // When + ApiResult uploadResult = fileController.uploadFile(multipartFile, 0L, 100L, "tag", request); + ApiResult sliceResultApi = fileController.sliceFiles(dealFileVO); + ApiResult embeddingResult = fileController.embeddingFiles(dealFileVO, request); + + // Then + assertThat(uploadResult.code()).isEqualTo(0); + assertThat(sliceResultApi.code()).isEqualTo(0); + assertThat(embeddingResult.code()).isEqualTo(0); + + verify(fileInfoV2Service, times(1)).uploadFile(multipartFile, 0L, 100L, "tag", request); + verify(fileInfoV2Service, times(1)).sliceFiles(dealFileVO); + verify(fileInfoV2Service, times(1)).embeddingFiles(dealFileVO, request); + } + + /** + * Test folder operations flow including create, update, and delete Verifies that folder operations + * can be performed sequentially without errors + */ + @Test + @DisplayName("Folder operations flow - Create, update, delete") + void folderOperationsFlow() { + // Given + doNothing().when(fileInfoV2Service).createFolder(createFolderVO); + doNothing().when(fileInfoV2Service).updateFolder(createFolderVO); + doNothing().when(fileInfoV2Service).deleteFolder(anyLong()); + + // When + ApiResult createResult = fileController.createFolder(createFolderVO); + ApiResult updateResult = fileController.updateFolder(createFolderVO); + ApiResult deleteResult = fileController.deleteFolder(1L); + + // Then + assertThat(createResult.code()).isEqualTo(0); + assertThat(updateResult.code()).isEqualTo(0); + assertThat(deleteResult.code()).isEqualTo(0); + + verify(fileInfoV2Service, times(1)).createFolder(createFolderVO); + verify(fileInfoV2Service, times(1)).updateFolder(createFolderVO); + verify(fileInfoV2Service, times(1)).deleteFolder(1L); + } + } +} diff --git a/console/backend/toolkit/src/test/java/com/iflytek/astron/console/toolkit/controller/knowledge/KnowledgeControllerTest.java b/console/backend/toolkit/src/test/java/com/iflytek/astron/console/toolkit/controller/knowledge/KnowledgeControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2f12b56b063b7f3c746d35e6d269cd84ecfd5ddc --- /dev/null +++ b/console/backend/toolkit/src/test/java/com/iflytek/astron/console/toolkit/controller/knowledge/KnowledgeControllerTest.java @@ -0,0 +1,1154 @@ +package com.iflytek.astron.console.toolkit.controller.knowledge; + +import com.iflytek.astron.console.commons.constant.ResponseEnum; +import com.iflytek.astron.console.commons.exception.BusinessException; +import com.iflytek.astron.console.commons.response.ApiResult; +import com.iflytek.astron.console.toolkit.entity.mongo.Knowledge; +import com.iflytek.astron.console.toolkit.entity.vo.repo.KnowledgeVO; +import com.iflytek.astron.console.toolkit.service.repo.KnowledgeService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +/** + * Unit tests for KnowledgeController + * + *

+ * Technology Stack: JUnit5 + Mockito + AssertJ + *

+ * + *

+ * Coverage Requirements: + *

+ *
    + *
  • JaCoCo Statement Coverage >= 80%
  • + *
  • JaCoCo Branch Coverage >= 90%
  • + *
  • High PIT Mutation Test Score
  • + *
  • Covers normal flows, edge cases, and exceptions
  • + *
+ * + * @author AI Assistant + */ +@ExtendWith(MockitoExtension.class) +@DisplayName("KnowledgeController Unit Tests") +class KnowledgeControllerTest { + + @Mock + private KnowledgeService knowledgeService; + + @InjectMocks + private KnowledgeController knowledgeController; + + private Knowledge mockKnowledge; + private KnowledgeVO knowledgeVO; + + /** + * Set up test fixtures before each test method. Initializes common test data including mock + * Knowledge entity and KnowledgeVO. + */ + @BeforeEach + void setUp() { + // Initialize common test data + mockKnowledge = Knowledge.builder() + .id("knowledge-001") + .fileId("file-001") + .charCount(1000L) + .enabled(1) + .source(0) + .testHitCount(0L) + .dialogHitCount(0L) + .coreRepoName("test-repo") + .build(); + + knowledgeVO = new KnowledgeVO(); + knowledgeVO.setId("knowledge-001"); + knowledgeVO.setFileId(1L); + knowledgeVO.setContent("Test knowledge content"); + } + + /** + * Test cases for the createKnowledge method. Validates knowledge creation functionality including + * success scenarios and error handling. + */ + @Nested + @DisplayName("createKnowledge Tests") + class CreateKnowledgeTests { + + /** + * Test successful knowledge creation with valid input. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Create knowledge successfully with valid input") + void testCreateKnowledge_Success() throws ExecutionException, InterruptedException { + // Given + when(knowledgeService.createKnowledge(any(KnowledgeVO.class))).thenReturn(mockKnowledge); + + // When + ApiResult result = knowledgeController.createKnowledge(knowledgeVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isNotNull(); + assertThat(result.data().getId()).isEqualTo("knowledge-001"); + assertThat(result.data().getFileId()).isEqualTo("file-001"); + assertThat(result.data().getCharCount()).isEqualTo(1000L); + + verify(knowledgeService, times(1)).createKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge creation with empty VO object. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Create knowledge with empty VO object") + void testCreateKnowledge_EmptyVO() throws ExecutionException, InterruptedException { + // Given + KnowledgeVO emptyVO = new KnowledgeVO(); + Knowledge emptyKnowledge = Knowledge.builder().build(); + when(knowledgeService.createKnowledge(any(KnowledgeVO.class))).thenReturn(emptyKnowledge); + + // When + ApiResult result = knowledgeController.createKnowledge(emptyVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isNotNull(); + + verify(knowledgeService, times(1)).createKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge creation when service throws RuntimeException. + */ + @Test + @DisplayName("Create knowledge - service throws RuntimeException") + void testCreateKnowledge_ServiceThrowsRuntimeException() { + // Given + when(knowledgeService.createKnowledge(any(KnowledgeVO.class))) + .thenThrow(new RuntimeException("Service error")); + + // When & Then + assertThatThrownBy(() -> knowledgeController.createKnowledge(knowledgeVO)) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("Service error"); + + verify(knowledgeService, times(1)).createKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge creation when service throws BusinessException. + */ + @Test + @DisplayName("Create knowledge - service throws BusinessException") + void testCreateKnowledge_ServiceThrowsBusinessException() { + // Given + when(knowledgeService.createKnowledge(any(KnowledgeVO.class))) + .thenThrow(new BusinessException(ResponseEnum.DATA_NOT_FOUND)); + + // When & Then + assertThatThrownBy(() -> knowledgeController.createKnowledge(knowledgeVO)) + .isInstanceOf(BusinessException.class) + .extracting("responseEnum") + .isEqualTo(ResponseEnum.DATA_NOT_FOUND); + + verify(knowledgeService, times(1)).createKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge creation when service returns null. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Create knowledge - service returns null") + void testCreateKnowledge_ServiceReturnsNull() throws ExecutionException, InterruptedException { + // Given + when(knowledgeService.createKnowledge(any(KnowledgeVO.class))).thenReturn(null); + + // When + ApiResult result = knowledgeController.createKnowledge(knowledgeVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isNull(); + + verify(knowledgeService, times(1)).createKnowledge(any(KnowledgeVO.class)); + } + } + + /** + * Test cases for the updateKnowledge method. Validates knowledge update functionality including tag + * validation and error handling. + */ + @Nested + @DisplayName("updateKnowledge Tests") + class UpdateKnowledgeTests { + + /** + * Test successful knowledge update without tags. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Update knowledge successfully without tags") + void testUpdateKnowledge_NoTags_Success() throws ExecutionException, InterruptedException { + // Given + knowledgeVO.setTags(null); + when(knowledgeService.updateKnowledge(any(KnowledgeVO.class))).thenReturn(mockKnowledge); + + // When + ApiResult result = knowledgeController.updateKnowledge(knowledgeVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isNotNull(); + assertThat(result.data().getId()).isEqualTo("knowledge-001"); + + verify(knowledgeService, times(1)).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test successful knowledge update with empty tags list. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Update knowledge successfully with empty tags list") + void testUpdateKnowledge_EmptyTags_Success() throws ExecutionException, InterruptedException { + // Given + knowledgeVO.setTags(Collections.emptyList()); + when(knowledgeService.updateKnowledge(any(KnowledgeVO.class))).thenReturn(mockKnowledge); + + // When + ApiResult result = knowledgeController.updateKnowledge(knowledgeVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isNotNull(); + + verify(knowledgeService, times(1)).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test successful knowledge update with valid tags. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Update knowledge successfully with valid tags") + void testUpdateKnowledge_ValidTags_Success() throws ExecutionException, InterruptedException { + // Given + List tags = Arrays.asList("tag1", "tag2", "tag3"); + knowledgeVO.setTags(tags); + when(knowledgeService.updateKnowledge(any(KnowledgeVO.class))).thenReturn(mockKnowledge); + + // When + ApiResult result = knowledgeController.updateKnowledge(knowledgeVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isNotNull(); + + verify(knowledgeService, times(1)).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge update with tag length equal to 30 (boundary value). + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Update knowledge - tag length equals 30 (boundary value)") + void testUpdateKnowledge_TagLengthEquals30_Success() throws ExecutionException, InterruptedException { + // Given - Tag with exactly 30 characters + String tag30Chars = "123456789012345678901234567890"; // 30 characters + knowledgeVO.setTags(Collections.singletonList(tag30Chars)); + when(knowledgeService.updateKnowledge(any(KnowledgeVO.class))).thenReturn(mockKnowledge); + + // When + ApiResult result = knowledgeController.updateKnowledge(knowledgeVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isNotNull(); + + verify(knowledgeService, times(1)).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge update with tag length equal to 29 (boundary value). + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Update knowledge - tag length equals 29 (boundary value)") + void testUpdateKnowledge_TagLengthEquals29_Success() throws ExecutionException, InterruptedException { + // Given - Tag with 29 characters + String tag29Chars = "12345678901234567890123456789"; // 29 characters + knowledgeVO.setTags(Collections.singletonList(tag29Chars)); + when(knowledgeService.updateKnowledge(any(KnowledgeVO.class))).thenReturn(mockKnowledge); + + // When + ApiResult result = knowledgeController.updateKnowledge(knowledgeVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + + verify(knowledgeService, times(1)).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge update with tag length exceeding 30 (throws exception). + */ + @Test + @DisplayName("Update knowledge - tag length exceeds 30 (throws exception)") + void testUpdateKnowledge_TagLengthExceeds30_ThrowsException() { + // Given - Tag with 31 characters + String tag31Chars = "1234567890123456789012345678901"; // 31 characters + knowledgeVO.setTags(Collections.singletonList(tag31Chars)); + + // When & Then + assertThatThrownBy(() -> knowledgeController.updateKnowledge(knowledgeVO)) + .isInstanceOf(BusinessException.class) + .extracting("responseEnum") + .isEqualTo(ResponseEnum.REPO_KNOWLEDGE_TAG_TOO_LONG); + + verify(knowledgeService, never()).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge update with multiple tags where one exceeds limit. + */ + @Test + @DisplayName("Update knowledge - multiple tags with one exceeding limit") + void testUpdateKnowledge_MultipleTagsOneExceedsLimit_ThrowsException() { + // Given + List tags = Arrays.asList( + "validTag1", + "validTag2", + "1234567890123456789012345678901" // 31 characters, too long + ); + knowledgeVO.setTags(tags); + + // When & Then + assertThatThrownBy(() -> knowledgeController.updateKnowledge(knowledgeVO)) + .isInstanceOf(BusinessException.class) + .extracting("responseEnum") + .isEqualTo(ResponseEnum.REPO_KNOWLEDGE_TAG_TOO_LONG); + + verify(knowledgeService, never()).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge update with first tag exceeding limit. + */ + @Test + @DisplayName("Update knowledge - first tag exceeds limit") + void testUpdateKnowledge_FirstTagExceedsLimit_ThrowsException() { + // Given + List tags = Arrays.asList( + "1234567890123456789012345678901", // 31 characters, too long + "validTag"); + knowledgeVO.setTags(tags); + + // When & Then + assertThatThrownBy(() -> knowledgeController.updateKnowledge(knowledgeVO)) + .isInstanceOf(BusinessException.class) + .extracting("responseEnum") + .isEqualTo(ResponseEnum.REPO_KNOWLEDGE_TAG_TOO_LONG); + + verify(knowledgeService, never()).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge update with tags containing empty string. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Update knowledge - tags contain empty string") + void testUpdateKnowledge_TagsContainEmptyString_Success() throws ExecutionException, InterruptedException { + // Given + List tags = Arrays.asList("tag1", "", "tag3"); + knowledgeVO.setTags(tags); + when(knowledgeService.updateKnowledge(any(KnowledgeVO.class))).thenReturn(mockKnowledge); + + // When + ApiResult result = knowledgeController.updateKnowledge(knowledgeVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + + verify(knowledgeService, times(1)).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge update with tags containing single character. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Update knowledge - tags contain single character") + void testUpdateKnowledge_TagsContainSingleChar_Success() throws ExecutionException, InterruptedException { + // Given + List tags = Collections.singletonList("x"); + knowledgeVO.setTags(tags); + when(knowledgeService.updateKnowledge(any(KnowledgeVO.class))).thenReturn(mockKnowledge); + + // When + ApiResult result = knowledgeController.updateKnowledge(knowledgeVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + + verify(knowledgeService, times(1)).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge update when service throws RuntimeException. + */ + @Test + @DisplayName("Update knowledge - service throws RuntimeException") + void testUpdateKnowledge_ServiceThrowsRuntimeException() { + // Given + knowledgeVO.setTags(Collections.singletonList("validTag")); + when(knowledgeService.updateKnowledge(any(KnowledgeVO.class))) + .thenThrow(new RuntimeException("Update failed")); + + // When & Then + assertThatThrownBy(() -> knowledgeController.updateKnowledge(knowledgeVO)) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("Update failed"); + + verify(knowledgeService, times(1)).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge update when service throws BusinessException. + */ + @Test + @DisplayName("Update knowledge - service throws BusinessException") + void testUpdateKnowledge_ServiceThrowsBusinessException() { + // Given + knowledgeVO.setTags(Collections.singletonList("validTag")); + when(knowledgeService.updateKnowledge(any(KnowledgeVO.class))) + .thenThrow(new BusinessException(ResponseEnum.REPO_KNOWLEDGE_NOT_EXIST)); + + // When & Then + assertThatThrownBy(() -> knowledgeController.updateKnowledge(knowledgeVO)) + .isInstanceOf(BusinessException.class) + .extracting("responseEnum") + .isEqualTo(ResponseEnum.REPO_KNOWLEDGE_NOT_EXIST); + + verify(knowledgeService, times(1)).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge update with tag too long and service not called. + */ + @Test + @DisplayName("Update knowledge - tag too long and service not called") + void testUpdateKnowledge_TagTooLong_ServiceNotCalled() { + // Given + String longTag = "x".repeat(31); // 31 characters + knowledgeVO.setTags(Collections.singletonList(longTag)); + + // When & Then + assertThatThrownBy(() -> knowledgeController.updateKnowledge(knowledgeVO)) + .isInstanceOf(BusinessException.class); + + // Verify service method was not called + verify(knowledgeService, never()).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge update with valid Chinese tags. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Update knowledge - with valid Chinese tags") + void testUpdateKnowledge_ChineseTagsValid_Success() throws ExecutionException, InterruptedException { + // Given - 10 Chinese characters (30 bytes, but 10 characters in length) + String chineseTag = "这是一个测试标签1234"; // 10 characters + knowledgeVO.setTags(Collections.singletonList(chineseTag)); + when(knowledgeService.updateKnowledge(any(KnowledgeVO.class))).thenReturn(mockKnowledge); + + // When + ApiResult result = knowledgeController.updateKnowledge(knowledgeVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + + verify(knowledgeService, times(1)).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge update with Chinese tags that are too long. + */ + @Test + @DisplayName("Update knowledge - with Chinese tags that are too long") + void testUpdateKnowledge_ChineseTagsTooLong_ThrowsException() { + // Given - 31 characters (Chinese + numbers) + String chineseTag = "这是一个非常长的中文标签用于测试边界条件的处理逻辑问题1234"; // 31 characters + assertThat(chineseTag.length()).isEqualTo(31); // Verify it's indeed 31 characters + knowledgeVO.setTags(Collections.singletonList(chineseTag)); + + // When & Then + assertThatThrownBy(() -> knowledgeController.updateKnowledge(knowledgeVO)) + .isInstanceOf(BusinessException.class) + .extracting("responseEnum") + .isEqualTo(ResponseEnum.REPO_KNOWLEDGE_TAG_TOO_LONG); + + verify(knowledgeService, never()).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test knowledge update with many valid tags. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Update knowledge - with many valid tags") + void testUpdateKnowledge_ManyValidTags_Success() throws ExecutionException, InterruptedException { + // Given + List tags = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + tags.add("tag" + i); // Each tag does not exceed 30 characters + } + knowledgeVO.setTags(tags); + when(knowledgeService.updateKnowledge(any(KnowledgeVO.class))).thenReturn(mockKnowledge); + + // When + ApiResult result = knowledgeController.updateKnowledge(knowledgeVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + + verify(knowledgeService, times(1)).updateKnowledge(any(KnowledgeVO.class)); + } + } + + /** + * Test cases for the enableKnowledge method. Validates knowledge enable/disable functionality and + * various input scenarios. + */ + @Nested + @DisplayName("enableKnowledge Tests") + class EnableKnowledgeTests { + + /** + * Test enabling knowledge with enabled=1. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Enable knowledge successfully with enabled=1") + void testEnableKnowledge_EnableSuccess() throws ExecutionException, InterruptedException { + // Given + String knowledgeId = "knowledge-001"; + Integer enabled = 1; + String expectedMessage = "Knowledge enabled successfully"; + when(knowledgeService.enableKnowledge(anyString(), anyInt())).thenReturn(expectedMessage); + + // When + ApiResult result = knowledgeController.enableKnowledge(knowledgeId, enabled); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isEqualTo(expectedMessage); + + verify(knowledgeService, times(1)).enableKnowledge(eq(knowledgeId), eq(enabled)); + } + + /** + * Test disabling knowledge with enabled=0. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Disable knowledge successfully with enabled=0") + void testEnableKnowledge_DisableSuccess() throws ExecutionException, InterruptedException { + // Given + String knowledgeId = "knowledge-002"; + Integer enabled = 0; + String expectedMessage = "Knowledge disabled successfully"; + when(knowledgeService.enableKnowledge(anyString(), anyInt())).thenReturn(expectedMessage); + + // When + ApiResult result = knowledgeController.enableKnowledge(knowledgeId, enabled); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isEqualTo(expectedMessage); + + verify(knowledgeService, times(1)).enableKnowledge(eq(knowledgeId), eq(enabled)); + } + + /** + * Test enabling knowledge with empty string ID. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Enable knowledge with empty string ID") + void testEnableKnowledge_EmptyId() throws ExecutionException, InterruptedException { + // Given + String knowledgeId = ""; + Integer enabled = 1; + when(knowledgeService.enableKnowledge(anyString(), anyInt())).thenReturn("success"); + + // When + ApiResult result = knowledgeController.enableKnowledge(knowledgeId, enabled); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + + verify(knowledgeService, times(1)).enableKnowledge(eq(knowledgeId), eq(enabled)); + } + + /** + * Test enabling knowledge with non-standard enabled value. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Enable knowledge with non-standard enabled value") + void testEnableKnowledge_NonStandardEnabledValue() throws ExecutionException, InterruptedException { + // Given + String knowledgeId = "knowledge-003"; + Integer enabled = 999; // Non-standard value + when(knowledgeService.enableKnowledge(anyString(), anyInt())).thenReturn("success"); + + // When + ApiResult result = knowledgeController.enableKnowledge(knowledgeId, enabled); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + + verify(knowledgeService, times(1)).enableKnowledge(eq(knowledgeId), eq(enabled)); + } + + /** + * Test enabling knowledge when service throws RuntimeException. + */ + @Test + @DisplayName("Enable knowledge - service throws RuntimeException") + void testEnableKnowledge_ServiceThrowsRuntimeException() { + // Given + String knowledgeId = "knowledge-001"; + Integer enabled = 1; + when(knowledgeService.enableKnowledge(anyString(), anyInt())) + .thenThrow(new RuntimeException("Enable failed")); + + // When & Then + assertThatThrownBy(() -> knowledgeController.enableKnowledge(knowledgeId, enabled)) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("Enable failed"); + + verify(knowledgeService, times(1)).enableKnowledge(eq(knowledgeId), eq(enabled)); + } + + /** + * Test enabling knowledge when service throws BusinessException. + */ + @Test + @DisplayName("Enable knowledge - service throws BusinessException") + void testEnableKnowledge_ServiceThrowsBusinessException() { + // Given + String knowledgeId = "knowledge-001"; + Integer enabled = 1; + when(knowledgeService.enableKnowledge(anyString(), anyInt())) + .thenThrow(new BusinessException(ResponseEnum.REPO_KNOWLEDGE_NOT_EXIST)); + + // When & Then + assertThatThrownBy(() -> knowledgeController.enableKnowledge(knowledgeId, enabled)) + .isInstanceOf(BusinessException.class) + .extracting("responseEnum") + .isEqualTo(ResponseEnum.REPO_KNOWLEDGE_NOT_EXIST); + + verify(knowledgeService, times(1)).enableKnowledge(eq(knowledgeId), eq(enabled)); + } + + /** + * Test enabling knowledge when service returns null. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Enable knowledge - service returns null") + void testEnableKnowledge_ServiceReturnsNull() throws ExecutionException, InterruptedException { + // Given + String knowledgeId = "knowledge-001"; + Integer enabled = 1; + when(knowledgeService.enableKnowledge(anyString(), anyInt())).thenReturn(null); + + // When + ApiResult result = knowledgeController.enableKnowledge(knowledgeId, enabled); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isNull(); + + verify(knowledgeService, times(1)).enableKnowledge(eq(knowledgeId), eq(enabled)); + } + + /** + * Test enabling knowledge when service returns empty string. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Enable knowledge - service returns empty string") + void testEnableKnowledge_ServiceReturnsEmptyString() throws ExecutionException, InterruptedException { + // Given + String knowledgeId = "knowledge-001"; + Integer enabled = 1; + when(knowledgeService.enableKnowledge(anyString(), anyInt())).thenReturn(""); + + // When + ApiResult result = knowledgeController.enableKnowledge(knowledgeId, enabled); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isEmpty(); + + verify(knowledgeService, times(1)).enableKnowledge(eq(knowledgeId), eq(enabled)); + } + + /** + * Test enabling knowledge with negative enabled value. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Enable knowledge with negative enabled value") + void testEnableKnowledge_NegativeEnabledValue() throws ExecutionException, InterruptedException { + // Given + String knowledgeId = "knowledge-001"; + Integer enabled = -1; + when(knowledgeService.enableKnowledge(anyString(), anyInt())).thenReturn("success"); + + // When + ApiResult result = knowledgeController.enableKnowledge(knowledgeId, enabled); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + + verify(knowledgeService, times(1)).enableKnowledge(eq(knowledgeId), eq(enabled)); + } + } + + /** + * Test cases for the deleteKnowledge method. Validates knowledge deletion functionality with + * various scenarios. + */ + @Nested + @DisplayName("deleteKnowledge Tests") + class DeleteKnowledgeTests { + + /** + * Test successful knowledge deletion. + */ + @Test + @DisplayName("Delete knowledge successfully") + void testDeleteKnowledge_Success() { + // Given + String knowledgeId = "knowledge-001"; + doNothing().when(knowledgeService).deleteKnowledge(anyString()); + + // When + ApiResult result = knowledgeController.deleteKnowledge(knowledgeId); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + assertThat(result.data()).isNull(); + + verify(knowledgeService, times(1)).deleteKnowledge(eq(knowledgeId)); + } + + /** + * Test deleting knowledge with empty string ID. + */ + @Test + @DisplayName("Delete knowledge with empty string ID") + void testDeleteKnowledge_EmptyId() { + // Given + String knowledgeId = ""; + doNothing().when(knowledgeService).deleteKnowledge(anyString()); + + // When + ApiResult result = knowledgeController.deleteKnowledge(knowledgeId); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + + verify(knowledgeService, times(1)).deleteKnowledge(eq(knowledgeId)); + } + + /** + * Test deleting knowledge with null ID. + */ + @Test + @DisplayName("Delete knowledge with null ID") + void testDeleteKnowledge_NullId() { + // Given + String knowledgeId = null; + doNothing().when(knowledgeService).deleteKnowledge(nullable(String.class)); + + // When + ApiResult result = knowledgeController.deleteKnowledge(knowledgeId); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + + verify(knowledgeService, times(1)).deleteKnowledge(isNull()); + } + + /** + * Test deleting knowledge when service throws RuntimeException. + */ + @Test + @DisplayName("Delete knowledge - service throws RuntimeException") + void testDeleteKnowledge_ServiceThrowsRuntimeException() { + // Given + String knowledgeId = "knowledge-001"; + doThrow(new RuntimeException("Delete failed")) + .when(knowledgeService) + .deleteKnowledge(anyString()); + + // When & Then + assertThatThrownBy(() -> knowledgeController.deleteKnowledge(knowledgeId)) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("Delete failed"); + + verify(knowledgeService, times(1)).deleteKnowledge(eq(knowledgeId)); + } + + /** + * Test deleting knowledge when service throws BusinessException. + */ + @Test + @DisplayName("Delete knowledge - service throws BusinessException") + void testDeleteKnowledge_ServiceThrowsBusinessException() { + // Given + String knowledgeId = "knowledge-001"; + doThrow(new BusinessException(ResponseEnum.REPO_KNOWLEDGE_NOT_EXIST)) + .when(knowledgeService) + .deleteKnowledge(anyString()); + + // When & Then + assertThatThrownBy(() -> knowledgeController.deleteKnowledge(knowledgeId)) + .isInstanceOf(BusinessException.class) + .extracting("responseEnum") + .isEqualTo(ResponseEnum.REPO_KNOWLEDGE_NOT_EXIST); + + verify(knowledgeService, times(1)).deleteKnowledge(eq(knowledgeId)); + } + + /** + * Test multiple deletions of the same ID. + */ + @Test + @DisplayName("Delete knowledge - multiple deletions of the same ID") + void testDeleteKnowledge_MultipleDeletionsSameId() { + // Given + String knowledgeId = "knowledge-001"; + doNothing().when(knowledgeService).deleteKnowledge(anyString()); + + // When + ApiResult result1 = knowledgeController.deleteKnowledge(knowledgeId); + ApiResult result2 = knowledgeController.deleteKnowledge(knowledgeId); + + // Then + assertThat(result1).isNotNull(); + assertThat(result1.code()).isEqualTo(0); + assertThat(result2).isNotNull(); + assertThat(result2.code()).isEqualTo(0); + + verify(knowledgeService, times(2)).deleteKnowledge(eq(knowledgeId)); + } + + /** + * Test deleting knowledge with long ID string. + */ + @Test + @DisplayName("Delete knowledge with long ID string") + void testDeleteKnowledge_LongId() { + // Given + String longId = "knowledge-" + "x".repeat(1000); + doNothing().when(knowledgeService).deleteKnowledge(anyString()); + + // When + ApiResult result = knowledgeController.deleteKnowledge(longId); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + + verify(knowledgeService, times(1)).deleteKnowledge(eq(longId)); + } + + /** + * Test deleting knowledge with special character ID. + */ + @Test + @DisplayName("Delete knowledge with special character ID") + void testDeleteKnowledge_SpecialCharacterId() { + // Given + String specialId = "knowledge-!@#$%^&*()"; + doNothing().when(knowledgeService).deleteKnowledge(anyString()); + + // When + ApiResult result = knowledgeController.deleteKnowledge(specialId); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isEqualTo(0); + + verify(knowledgeService, times(1)).deleteKnowledge(eq(specialId)); + } + } + + /** + * Integration scenario tests. Tests complete workflows combining multiple operations. + */ + @Nested + @DisplayName("Integration Scenario Tests") + class IntegrationScenarioTests { + + /** + * Test full lifecycle: create, update, enable, and delete knowledge. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Full lifecycle - create, update, enable, and delete") + void testFullLifecycle() throws ExecutionException, InterruptedException { + // Given + String knowledgeId = "knowledge-full-test"; + KnowledgeVO createVO = new KnowledgeVO(); + createVO.setContent("Initial content"); + + Knowledge createdKnowledge = Knowledge.builder() + .id(knowledgeId) + .enabled(0) + .build(); + + Knowledge updatedKnowledge = Knowledge.builder() + .id(knowledgeId) + .enabled(0) + .build(); + + when(knowledgeService.createKnowledge(any(KnowledgeVO.class))).thenReturn(createdKnowledge); + when(knowledgeService.updateKnowledge(any(KnowledgeVO.class))).thenReturn(updatedKnowledge); + when(knowledgeService.enableKnowledge(anyString(), anyInt())).thenReturn("enabled"); + doNothing().when(knowledgeService).deleteKnowledge(anyString()); + + // When - Create + ApiResult createResult = knowledgeController.createKnowledge(createVO); + assertThat(createResult.code()).isEqualTo(0); + assertThat(createResult.data().getId()).isEqualTo(knowledgeId); + + // When - Update + KnowledgeVO updateVO = new KnowledgeVO(); + updateVO.setId(knowledgeId); + updateVO.setContent("Updated content"); + updateVO.setTags(Arrays.asList("tag1", "tag2")); + ApiResult updateResult = knowledgeController.updateKnowledge(updateVO); + assertThat(updateResult.code()).isEqualTo(0); + + // When - Enable + ApiResult enableResult = knowledgeController.enableKnowledge(knowledgeId, 1); + assertThat(enableResult.code()).isEqualTo(0); + + // When - Delete + ApiResult deleteResult = knowledgeController.deleteKnowledge(knowledgeId); + assertThat(deleteResult.code()).isEqualTo(0); + + // Then - Verify all invocations + verify(knowledgeService, times(1)).createKnowledge(any(KnowledgeVO.class)); + verify(knowledgeService, times(1)).updateKnowledge(any(KnowledgeVO.class)); + verify(knowledgeService, times(1)).enableKnowledge(eq(knowledgeId), eq(1)); + verify(knowledgeService, times(1)).deleteKnowledge(eq(knowledgeId)); + } + + /** + * Test boundary scenario where all tags have exactly 30 characters. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("Boundary scenario - all tags have 30 characters") + void testBoundaryScenario_AllTags30Chars() throws ExecutionException, InterruptedException { + // Given + List tags = Arrays.asList( + "123456789012345678901234567890", // 30 chars + "abcdefghijklmnopqrstuvwxyz1234", // 30 chars + "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234" // 30 chars + ); + knowledgeVO.setTags(tags); + when(knowledgeService.updateKnowledge(any(KnowledgeVO.class))).thenReturn(mockKnowledge); + + // When + ApiResult result = knowledgeController.updateKnowledge(knowledgeVO); + + // Then + assertThat(result.code()).isEqualTo(0); + verify(knowledgeService, times(1)).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test error scenario where tag validation fails and service is not called. + */ + @Test + @DisplayName("Error scenario - tag validation fails and service is not called") + void testErrorScenario_TagValidationFailsNoServiceCall() { + // Given + knowledgeVO.setTags(Collections.singletonList("x".repeat(31))); + + // When & Then + assertThatThrownBy(() -> knowledgeController.updateKnowledge(knowledgeVO)) + .isInstanceOf(BusinessException.class); + + // Ensure service method is never called + verifyNoInteractions(knowledgeService); + } + } + + /** + * Parameter validation tests. Tests handling of null and edge-case parameter values. + */ + @Nested + @DisplayName("Parameter Validation Tests") + class ParameterValidationTests { + + /** + * Test createKnowledge with null parameter. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("createKnowledge with null parameter") + void testCreateKnowledge_NullParameter() throws ExecutionException, InterruptedException { + // Given + when(knowledgeService.createKnowledge(null)).thenReturn(null); + + // When + ApiResult result = knowledgeController.createKnowledge(null); + + // Then + assertThat(result).isNotNull(); + verify(knowledgeService, times(1)).createKnowledge(null); + } + + /** + * Test updateKnowledge with all VO fields being null. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("updateKnowledge with all VO fields being null") + void testUpdateKnowledge_AllFieldsNull() throws ExecutionException, InterruptedException { + // Given + KnowledgeVO emptyVO = new KnowledgeVO(); + when(knowledgeService.updateKnowledge(any(KnowledgeVO.class))).thenReturn(mockKnowledge); + + // When + ApiResult result = knowledgeController.updateKnowledge(emptyVO); + + // Then + assertThat(result.code()).isEqualTo(0); + verify(knowledgeService, times(1)).updateKnowledge(any(KnowledgeVO.class)); + } + + /** + * Test enableKnowledge with null parameters. + * + * @throws ExecutionException if the computation threw an exception + * @throws InterruptedException if the current thread was interrupted + */ + @Test + @DisplayName("enableKnowledge with null parameters") + void testEnableKnowledge_NullParameters() throws ExecutionException, InterruptedException { + // Given + when(knowledgeService.enableKnowledge(nullable(String.class), nullable(Integer.class))) + .thenReturn("success"); + + // When + ApiResult result = knowledgeController.enableKnowledge(null, null); + + // Then + assertThat(result.code()).isEqualTo(0); + verify(knowledgeService, times(1)).enableKnowledge(isNull(), isNull()); + } + } +} diff --git a/console/backend/toolkit/src/test/java/com/iflytek/astron/console/toolkit/controller/knowledge/RepoControllerTest.java b/console/backend/toolkit/src/test/java/com/iflytek/astron/console/toolkit/controller/knowledge/RepoControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7ec37187f33090c7c4a0848cc1cb635db7e7032c --- /dev/null +++ b/console/backend/toolkit/src/test/java/com/iflytek/astron/console/toolkit/controller/knowledge/RepoControllerTest.java @@ -0,0 +1,1973 @@ +package com.iflytek.astron.console.toolkit.controller.knowledge; + +import com.iflytek.astron.console.commons.response.ApiResult; +import com.iflytek.astron.console.toolkit.entity.common.PageData; +import com.iflytek.astron.console.toolkit.entity.dto.RepoDto; +import com.iflytek.astron.console.toolkit.entity.table.repo.HitTestHistory; +import com.iflytek.astron.console.toolkit.entity.table.repo.Repo; +import com.iflytek.astron.console.toolkit.entity.vo.knowledge.RepoVO; +import com.iflytek.astron.console.toolkit.service.repo.RepoService; +import jakarta.servlet.http.HttpServletRequest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.*; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +/** + * Comprehensive unit tests for {@link RepoController}. + * + *

+ * Coverage targets: + *

    + *
  • JaCoCo: Statement coverage >= 80%, Branch coverage >= 90%
  • + *
  • High PIT mutation test pass rate
  • + *
  • Covers normal flows, boundary conditions, and exception cases
  • + *
+ *

+ * + *

+ * Tech stack: JUnit 5 + Mockito + AssertJ + ParameterizedTest + *

+ * + *

+ * Mock dependencies: + *

    + *
  • {@code RepoService} (core business logic)
  • + *
  • {@code HttpServletRequest} (HTTP request)
  • + *
+ *

+ * + * @author Generated Test Suite + * @since 1.0 + */ +@ExtendWith(MockitoExtension.class) +@DisplayName("RepoController Unit Tests") +class RepoControllerTest { + + private static final Long VALID_REPO_ID = 1L; + private static final Long INVALID_REPO_ID = -1L; + private static final String VALID_NAME = "Test Repository"; + private static final String VALID_DESC = "Test Description"; + private static final String VALID_TAG = "CBG-RAG"; + private static final String VALID_QUERY = "Test Query"; + private static final String VALID_CONTENT = "Search Content"; + private static final Integer DEFAULT_PAGE_NO = 1; + private static final Integer DEFAULT_PAGE_SIZE = 10; + private static final Integer VALID_TOP_N = 3; + private static final Integer ENABLED = 1; + private static final Integer DISABLED = 0; + + @Mock + private RepoService repoService; + + @Mock + private HttpServletRequest request; + + @InjectMocks + private RepoController controller; + + // Argument Captors for verification + @Captor + private ArgumentCaptor repoVOCaptor; + + @Captor + private ArgumentCaptor longCaptor; + + @Captor + private ArgumentCaptor integerCaptor; + + @Captor + private ArgumentCaptor stringCaptor; + + // Test data fixtures + private RepoVO validRepoVO; + private Repo validRepo; + private RepoDto validRepoDto; + private PageData validPageData; + private PageData validHitTestHistoryPageData; + private HitTestHistory validHitTestHistory; + + @BeforeEach + void setUp() { + validRepoVO = createValidRepoVO(); + validRepo = createValidRepo(); + validRepoDto = createValidRepoDto(); + validPageData = createValidPageData(); + validHitTestHistory = createValidHitTestHistory(); + validHitTestHistoryPageData = createValidHitTestHistoryPageData(); + } + + // ==================== Test Data Builder Methods ==================== + + /** + * Creates a valid RepoVO object with all required fields populated. + * + * @return a fully populated RepoVO instance for testing + */ + private RepoVO createValidRepoVO() { + RepoVO vo = new RepoVO(); + vo.setId(VALID_REPO_ID); + vo.setName(VALID_NAME); + vo.setDesc(VALID_DESC); + vo.setAvatarIcon("icon.png"); + vo.setAvatarColor("#FF5733"); + vo.setTags(Arrays.asList("tag1", "tag2")); + vo.setEmbeddedModel("text-embedding-ada-002"); + vo.setIndexType(0); + vo.setAppId("test-app-id"); + vo.setSource(0); + vo.setOuterRepoId("outer-repo-123"); + vo.setCoreRepoId("core-repo-123"); + vo.setEnableAudit(true); + vo.setOperType(2); + vo.setVisibility(0); + vo.setUids(Arrays.asList("uid1", "uid2")); + vo.setTag(VALID_TAG); + return vo; + } + + /** + * Creates a valid Repo entity with all required fields populated. + * + * @return a fully populated Repo instance for testing + */ + private Repo createValidRepo() { + Repo repo = new Repo(); + repo.setId(VALID_REPO_ID); + repo.setName(VALID_NAME); + repo.setDescription(VALID_DESC); + repo.setUserId("user123"); + repo.setAppId("test-app-id"); + repo.setOuterRepoId("outer-repo-123"); + repo.setCoreRepoId("core-repo-123"); + repo.setIcon("icon.png"); + repo.setColor("#FF5733"); + repo.setStatus(1); + repo.setEmbeddedModel("text-embedding-ada-002"); + repo.setIndexType(0); + repo.setVisibility(0); + repo.setSource(0); + repo.setEnableAudit(true); + repo.setDeleted(false); + repo.setCreateTime(new Date()); + repo.setUpdateTime(new Date()); + repo.setIsTop(false); + repo.setTag(VALID_TAG); + repo.setSpaceId(100L); + return repo; + } + + /** + * Creates a valid RepoDto data transfer object with all fields populated. + * + * @return a fully populated RepoDto instance for testing + */ + private RepoDto createValidRepoDto() { + RepoDto dto = new RepoDto(); + dto.setId(VALID_REPO_ID); + dto.setName(VALID_NAME); + dto.setDescription(VALID_DESC); + dto.setAddress("http://localhost:8080"); + dto.setFileCount(10L); + dto.setCharCount(1000L); + dto.setKnowledgeCount(50L); + dto.setCorner("corner-value"); + return dto; + } + + /** + * Creates a valid PageData object containing RepoDto items. + * + * @return a PageData instance with sample RepoDto data for testing + */ + private PageData createValidPageData() { + PageData pageData = new PageData<>(); + pageData.setPage(DEFAULT_PAGE_NO); + pageData.setPageSize(DEFAULT_PAGE_SIZE); + pageData.setTotalCount(1L); + pageData.setTotalPages(1L); + pageData.setPageData(Collections.singletonList(validRepoDto)); + return pageData; + } + + /** + * Creates a valid HitTestHistory entity. + * + * @return a HitTestHistory instance with sample data for testing + */ + private HitTestHistory createValidHitTestHistory() { + HitTestHistory history = new HitTestHistory(); + history.setId(1L); + history.setUserId("user123"); + history.setRepoId(VALID_REPO_ID); + history.setQuery(VALID_QUERY); + return history; + } + + /** + * Creates a valid PageData object containing HitTestHistory items. + * + * @return a PageData instance with sample HitTestHistory data for testing + */ + private PageData createValidHitTestHistoryPageData() { + PageData pageData = new PageData<>(); + pageData.setPage(DEFAULT_PAGE_NO); + pageData.setPageSize(DEFAULT_PAGE_SIZE); + pageData.setTotalCount(1L); + pageData.setTotalPages(1L); + pageData.setPageData(Collections.singletonList(validHitTestHistory)); + return pageData; + } + + // ==================== createRepo Tests ==================== + + @Nested + @DisplayName("Create Repository Tests") + class CreateRepoTests { + + /** + * Tests successful repository creation with valid input. + * Verifies that the controller properly delegates to the service and returns the created repository. + */ + @Test + @DisplayName("Create repository - successful flow") + void createRepo_Success() { + // Given + when(repoService.createRepo(any(RepoVO.class))).thenReturn(validRepo); + + // When + ApiResult result = controller.createRepo(validRepoVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isZero(); + assertThat(result.data()).isEqualTo(validRepo); + assertThat(result.data().getId()).isEqualTo(VALID_REPO_ID); + assertThat(result.data().getName()).isEqualTo(VALID_NAME); + + verify(repoService, times(1)).createRepo(repoVOCaptor.capture()); + RepoVO capturedVO = repoVOCaptor.getValue(); + assertThat(capturedVO.getName()).isEqualTo(VALID_NAME); + } + + /** + * Tests repository creation with an empty VO object. Verifies that the controller can handle + * minimal input. + */ + @Test + @DisplayName("Create repository - with empty VO") + void createRepo_WithEmptyVO() { + // Given + RepoVO emptyVO = new RepoVO(); + Repo expectedRepo = new Repo(); + expectedRepo.setId(999L); + when(repoService.createRepo(any(RepoVO.class))).thenReturn(expectedRepo); + + // When + ApiResult result = controller.createRepo(emptyVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isZero(); + assertThat(result.data().getId()).isEqualTo(999L); + verify(repoService, times(1)).createRepo(emptyVO); + } + + /** + * Tests that exceptions from the service layer are properly propagated. + * Verifies error handling when repository creation fails. + */ + @Test + @DisplayName("Create repository - service throws exception") + void createRepo_ServiceThrowsException() { + // Given + when(repoService.createRepo(any(RepoVO.class))) + .thenThrow(new RuntimeException("Creation failed")); + + // When & Then + assertThatThrownBy(() -> controller.createRepo(validRepoVO)) + .isInstanceOf(RuntimeException.class) + .hasMessage("Creation failed"); + + verify(repoService, times(1)).createRepo(any(RepoVO.class)); + } + + /** + * Tests repository creation with all optional fields populated. Verifies that all optional + * parameters are correctly processed. + */ + @Test + @DisplayName("Create repository - with all optional fields") + void createRepo_WithAllOptionalFields() { + // Given + validRepoVO.setEnableAudit(false); + validRepoVO.setVisibility(1); + validRepoVO.setOperType(3); + when(repoService.createRepo(any(RepoVO.class))).thenReturn(validRepo); + + // When + ApiResult result = controller.createRepo(validRepoVO); + + // Then + assertThat(result.code()).isZero(); + verify(repoService).createRepo(repoVOCaptor.capture()); + RepoVO captured = repoVOCaptor.getValue(); + assertThat(captured.getEnableAudit()).isFalse(); + assertThat(captured.getVisibility()).isEqualTo(1); + assertThat(captured.getOperType()).isEqualTo(3); + } + } + + // ==================== updateRepo Tests ==================== + + @Nested + @DisplayName("Update Repository Tests") + class UpdateRepoTests { + + /** + * Tests successful repository update with valid data. Verifies that changes are properly applied + * and reflected in the response. + */ + @Test + @DisplayName("Update repository - successful flow") + void updateRepo_Success() { + // Given + validRepo.setName("Updated Name"); + when(repoService.updateRepo(any(RepoVO.class))).thenReturn(validRepo); + + // When + ApiResult result = controller.updateRepo(validRepoVO); + + // Then + assertThat(result).isNotNull(); + assertThat(result.code()).isZero(); + assertThat(result.data()).isNotNull(); + assertThat(result.data().getName()).isEqualTo("Updated Name"); + verify(repoService, times(1)).updateRepo(any(RepoVO.class)); + } + + /** + * Tests partial update of repository fields. Verifies that only specified fields are updated while + * others remain unchanged. + */ + @Test + @DisplayName("Update repository - partial update") + void updateRepo_PartialUpdate() { + // Given + RepoVO partialVO = new RepoVO(); + partialVO.setId(VALID_REPO_ID); + partialVO.setName("New Name"); + when(repoService.updateRepo(any(RepoVO.class))).thenReturn(validRepo); + + // When + ApiResult result = controller.updateRepo(partialVO); + + // Then + assertThat(result.code()).isZero(); + verify(repoService).updateRepo(repoVOCaptor.capture()); + assertThat(repoVOCaptor.getValue().getId()).isEqualTo(VALID_REPO_ID); + } + + /** + * Tests update attempt with a non-existent repository ID. Verifies that appropriate exception is + * thrown for invalid IDs. + */ + @Test + @DisplayName("Update repository - non-existent ID") + void updateRepo_NonExistentId() { + // Given + validRepoVO.setId(999L); + when(repoService.updateRepo(any(RepoVO.class))) + .thenThrow(new IllegalArgumentException("Repository not found")); + + // When & Then + assertThatThrownBy(() -> controller.updateRepo(validRepoVO)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Repository not found"); + } + + /** + * Tests behavior when service returns null during update. + * Verifies that null responses are properly handled. + */ + @Test + @DisplayName("Update repository - service returns null") + void updateRepo_ServiceReturnsNull() { + // Given + when(repoService.updateRepo(any(RepoVO.class))).thenReturn(null); + + // When + ApiResult result = controller.updateRepo(validRepoVO); + + // Then + assertThat(result.code()).isZero(); + assertThat(result.data()).isNull(); + } + } + + // ==================== updateRepoStatus Tests ==================== + + @Nested + @DisplayName("Update Repository Status Tests") + class UpdateRepoStatusTests { + + /** + * Tests successful repository status update. + * Verifies that status changes are properly applied. + */ + @Test + @DisplayName("Update status - success") + void updateRepoStatus_Success() { + // Given + when(repoService.updateRepoStatus(any(RepoVO.class))).thenReturn(true); + + // When + ApiResult result = controller.updateRepoStatus(validRepoVO); + + // Then + assertThat(result.code()).isZero(); + assertThat(result.data()).isTrue(); + verify(repoService, times(1)).updateRepoStatus(any(RepoVO.class)); + } + + /** + * Tests repository status update failure scenario. + * Verifies that failed updates are properly reported. + */ + @Test + @DisplayName("Update status - failure") + void updateRepoStatus_Failure() { + // Given + when(repoService.updateRepoStatus(any(RepoVO.class))).thenReturn(false); + + // When + ApiResult result = controller.updateRepoStatus(validRepoVO); + + // Then + assertThat(result.code()).isZero(); + assertThat(result.data()).isFalse(); + } + + /** + * Tests repository status update with different status values. Verifies that all valid status + * values are properly handled. + * + * @param status the status value to test + */ + @ParameterizedTest + @ValueSource(ints = {1, 2, 3, 4}) + @DisplayName("Update status - different status values") + void updateRepoStatus_DifferentStatuses(int status) { + // Given + validRepoVO.setOperType(status); + when(repoService.updateRepoStatus(any(RepoVO.class))).thenReturn(true); + + // When + ApiResult result = controller.updateRepoStatus(validRepoVO); + + // Then + assertThat(result.code()).isZero(); + verify(repoService).updateRepoStatus(repoVOCaptor.capture()); + assertThat(repoVOCaptor.getValue().getOperType()).isEqualTo(status); + } + + /** + * Tests exception handling when service throws during status update. + * Verifies that exceptions are properly propagated. + */ + @Test + @DisplayName("Update status - service throws exception") + void updateRepoStatus_ServiceThrowsException() { + // Given + when(repoService.updateRepoStatus(any(RepoVO.class))) + .thenThrow(new RuntimeException("Status update failed")); + + // When & Then + assertThatThrownBy(() -> controller.updateRepoStatus(validRepoVO)) + .isInstanceOf(RuntimeException.class) + .hasMessage("Status update failed"); + } + } + + // ==================== listRepos Tests ==================== + + @Nested + @DisplayName("List Repositories Tests") + class ListReposTests { + + /** + * Tests listing repositories with default pagination parameters. + * Verifies that default page number and page size are correctly applied. + */ + @Test + @DisplayName("List repositories - default pagination") + void listRepos_DefaultPagination() { + // Given + when(repoService.listRepos(anyInt(), anyInt(), isNull(), any(HttpServletRequest.class))) + .thenReturn(validPageData); + + // When + ApiResult> result = controller.listRepos( + DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, null, request); + + // Then + assertThat(result.code()).isZero(); + assertThat(result.data()).isNotNull(); + assertThat(result.data().getPage()).isEqualTo(DEFAULT_PAGE_NO); + assertThat(result.data().getPageSize()).isEqualTo(DEFAULT_PAGE_SIZE); + verify(repoService).listRepos(DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, null, request); + } + + /** + * Tests listing repositories with search content filter. + * Verifies that content parameter is properly passed to the service. + */ + @Test + @DisplayName("List repositories - with content filter") + void listRepos_WithContent() { + // Given + when(repoService.listRepos(anyInt(), anyInt(), eq(VALID_CONTENT), any(HttpServletRequest.class))) + .thenReturn(validPageData); + + // When + ApiResult> result = controller.listRepos( + DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, VALID_CONTENT, request); + + // Then + assertThat(result.code()).isZero(); + verify(repoService).listRepos( + integerCaptor.capture(), + integerCaptor.capture(), + stringCaptor.capture(), + any(HttpServletRequest.class)); + assertThat(stringCaptor.getValue()).isEqualTo(VALID_CONTENT); + } + + /** + * Tests listing repositories with various pagination parameters. Verifies that different page + * numbers and sizes are correctly handled. + * + * @param pageNo the page number + * @param pageSize the page size + */ + @ParameterizedTest + @CsvSource({ + "1, 10", + "2, 20", + "5, 50", + "10, 100" + }) + @DisplayName("List repositories - different pagination parameters") + void listRepos_DifferentPagination(int pageNo, int pageSize) { + // Given + PageData pageData = new PageData<>(); + pageData.setPage(pageNo); + pageData.setPageSize(pageSize); + when(repoService.listRepos(anyInt(), anyInt(), isNull(), any(HttpServletRequest.class))) + .thenReturn(pageData); + + // When + ApiResult> result = controller.listRepos( + pageNo, pageSize, null, request); + + // Then + assertThat(result.code()).isZero(); + assertThat(result.data().getPage()).isEqualTo(pageNo); + assertThat(result.data().getPageSize()).isEqualTo(pageSize); + } + + /** + * Tests listing repositories when no results are found. Verifies that empty result sets are + * properly handled. + */ + @Test + @DisplayName("List repositories - empty result") + void listRepos_EmptyResult() { + // Given + PageData emptyPageData = new PageData<>(); + emptyPageData.setPage(DEFAULT_PAGE_NO); + emptyPageData.setPageSize(DEFAULT_PAGE_SIZE); + emptyPageData.setTotalCount(0L); + emptyPageData.setPageData(Collections.emptyList()); + when(repoService.listRepos(anyInt(), anyInt(), isNull(), any(HttpServletRequest.class))) + .thenReturn(emptyPageData); + + // When + ApiResult> result = controller.listRepos( + DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, null, request); + + // Then + assertThat(result.code()).isZero(); + assertThat(result.data().getPageData()).isEmpty(); + assertThat(result.data().getTotalCount()).isZero(); + } + + /** + * Tests listing repositories with null or empty content parameter. + * Verifies that null and empty strings are properly handled. + * + * @param content the content parameter (null or empty) + */ + @ParameterizedTest + @NullAndEmptySource + @DisplayName("List repositories - null or empty content") + void listRepos_NullOrEmptyContent(String content) { + // Given + when(repoService.listRepos(anyInt(), anyInt(), eq(content), any(HttpServletRequest.class))) + .thenReturn(validPageData); + + // When + ApiResult> result = controller.listRepos( + DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, content, request); + + // Then + assertThat(result.code()).isZero(); + verify(repoService).listRepos(DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, content, request); + } + } + + // ==================== list Tests ==================== + + @Nested + @DisplayName("Simplified List Tests") + class ListTests { + + /** + * Tests simplified list endpoint with basic parameters. + * Verifies that minimal required parameters work correctly. + */ + @Test + @DisplayName("Simplified list - basic parameters") + void list_BasicParameters() { + // Given + when(repoService.list(anyInt(), anyInt(), isNull(), isNull(), any(HttpServletRequest.class), isNull())) + .thenReturn(validPageData); + + // When + Object result = controller.list(DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, null, null, null, request); + + // Then + assertThat(result).isNotNull(); + verify(repoService).list(DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, null, null, request, null); + } + + /** + * Tests simplified list with ordering parameter. Verifies that orderBy field is properly handled. + */ + @Test + @DisplayName("Simplified list - with order by field") + void list_WithOrderBy() { + // Given + String orderBy = "createTime"; + when(repoService.list(anyInt(), anyInt(), isNull(), eq(orderBy), any(HttpServletRequest.class), isNull())) + .thenReturn(validPageData); + + // When + Object result = controller.list(DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, null, orderBy, null, request); + + // Then + assertThat(result).isNotNull(); + verify(repoService).list(DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, null, orderBy, request, null); + } + + /** + * Tests simplified list with tag filter. + * Verifies that tag parameter is properly applied. + */ + @Test + @DisplayName("Simplified list - with tag filter") + void list_WithTag() { + // Given + when(repoService.list(anyInt(), anyInt(), isNull(), isNull(), any(HttpServletRequest.class), eq(VALID_TAG))) + .thenReturn(validPageData); + + // When + Object result = controller.list(DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, null, null, VALID_TAG, request); + + // Then + assertThat(result).isNotNull(); + verify(repoService).list(DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, null, null, request, VALID_TAG); + } + + /** + * Tests simplified list with all available parameters. Verifies that all parameters work together + * correctly. + */ + @Test + @DisplayName("Simplified list - with all parameters") + void list_WithAllParameters() { + // Given + String orderBy = "name"; + when(repoService.list(anyInt(), anyInt(), eq(VALID_CONTENT), eq(orderBy), any(HttpServletRequest.class), eq(VALID_TAG))) + .thenReturn(validPageData); + + // When + Object result = controller.list( + DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, VALID_CONTENT, orderBy, VALID_TAG, request); + + // Then + assertThat(result).isNotNull(); + verify(repoService).list(DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, VALID_CONTENT, orderBy, request, VALID_TAG); + } + + /** + * Tests simplified list with different orderBy field values. + * Verifies that various sorting fields are correctly handled. + * + * @param orderBy the field name to sort by + */ + @ParameterizedTest + @ValueSource(strings = {"name", "createTime", "updateTime", "status"}) + @DisplayName("Simplified list - different order by fields") + void list_DifferentOrderByFields(String orderBy) { + // Given + when(repoService.list(anyInt(), anyInt(), isNull(), eq(orderBy), any(HttpServletRequest.class), isNull())) + .thenReturn(validPageData); + + // When + controller.list(DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, null, orderBy, null, request); + + // Then + verify(repoService).list( + eq(DEFAULT_PAGE_NO), eq(DEFAULT_PAGE_SIZE), isNull(), + stringCaptor.capture(), any(HttpServletRequest.class), isNull()); + assertThat(stringCaptor.getValue()).isEqualTo(orderBy); + } + } + + // ==================== getDetail Tests ==================== + + @Nested + @DisplayName("Get Detail Tests") + class GetDetailTests { + + /** + * Tests successful retrieval of repository details. + * Verifies that repository information is correctly returned. + */ + @Test + @DisplayName("Get detail - successful flow") + void getDetail_Success() { + // Given + when(repoService.getDetail(eq(VALID_REPO_ID), eq(""), any(HttpServletRequest.class))) + .thenReturn(validRepoDto); + + // When + ApiResult result = controller.getDetail(VALID_REPO_ID, "", request); + + // Then + assertThat(result.code()).isZero(); + assertThat(result.data()).isNotNull(); + assertThat(result.data().getId()).isEqualTo(VALID_REPO_ID); + verify(repoService).getDetail(VALID_REPO_ID, "", request); + } + + /** + * Tests get detail with tag parameter. + * Verifies that tag filtering is correctly applied. + */ + @Test + @DisplayName("Get detail - with tag") + void getDetail_WithTag() { + // Given + when(repoService.getDetail(eq(VALID_REPO_ID), eq(VALID_TAG), any(HttpServletRequest.class))) + .thenReturn(validRepoDto); + + // When + ApiResult result = controller.getDetail(VALID_REPO_ID, VALID_TAG, request); + + // Then + assertThat(result.code()).isZero(); + verify(repoService).getDetail( + longCaptor.capture(), + stringCaptor.capture(), + any(HttpServletRequest.class)); + assertThat(longCaptor.getValue()).isEqualTo(VALID_REPO_ID); + assertThat(stringCaptor.getValue()).isEqualTo(VALID_TAG); + } + + /** + * Tests get detail with a non-existent repository ID. + * Verifies that appropriate exception is thrown. + */ + @Test + @DisplayName("Get detail - non-existent ID") + void getDetail_NonExistentId() { + // Given + when(repoService.getDetail(eq(INVALID_REPO_ID), anyString(), any(HttpServletRequest.class))) + .thenThrow(new IllegalArgumentException("Repository not found")); + + // When & Then + assertThatThrownBy(() -> controller.getDetail(INVALID_REPO_ID, "", request)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Repository not found"); + } + + /** + * Tests get detail when service returns null. + * Verifies that null results are properly handled. + */ + @Test + @DisplayName("Get detail - returns null") + void getDetail_ReturnsNull() { + // Given + when(repoService.getDetail(anyLong(), anyString(), any(HttpServletRequest.class))) + .thenReturn(null); + + // When + ApiResult result = controller.getDetail(VALID_REPO_ID, "", request); + + // Then + assertThat(result.code()).isZero(); + assertThat(result.data()).isNull(); + } + + /** + * Tests get detail with various repository ID values. Verifies that different valid IDs are + * correctly processed. + * + * @param id the repository ID to test + */ + @ParameterizedTest + @ValueSource(longs = {1L, 100L, 999L, Long.MAX_VALUE}) + @DisplayName("Get detail - different ID values") + void getDetail_DifferentIds(Long id) { + // Given + RepoDto dto = new RepoDto(); + dto.setId(id); + when(repoService.getDetail(eq(id), anyString(), any(HttpServletRequest.class))) + .thenReturn(dto); + + // When + ApiResult result = controller.getDetail(id, "", request); + + // Then + assertThat(result.data().getId()).isEqualTo(id); + } + } + + // ==================== hitTest Tests ==================== + + @Nested + @DisplayName("Hit Test Tests") + class HitTestTests { + + /** + * Tests hit test functionality with default topN value. Verifies that default parameters work + * correctly. + */ + @Test + @DisplayName("Hit test - default topN") + void hitTest_DefaultTopN() { + // Given + Object expectedResult = Collections.singletonMap("hits", Collections.emptyList()); + when(repoService.hitTest(eq(VALID_REPO_ID), eq(VALID_QUERY), eq(3), eq(true))) + .thenReturn(expectedResult); + + // When + Object result = controller.hitTest(VALID_REPO_ID, VALID_QUERY, 3); + + // Then + assertThat(result).isNotNull(); + verify(repoService).hitTest(VALID_REPO_ID, VALID_QUERY, 3, true); + } + + /** + * Tests hit test with different topN parameter values. Verifies that various topN values are + * correctly handled. + * + * @param topN the number of top results to return + */ + @ParameterizedTest + @ValueSource(ints = {1, 3, 5, 10, 20}) + @DisplayName("Hit test - different topN values") + void hitTest_DifferentTopN(int topN) { + // Given + Object expectedResult = Collections.emptyMap(); + when(repoService.hitTest(eq(VALID_REPO_ID), eq(VALID_QUERY), eq(topN), eq(true))) + .thenReturn(expectedResult); + + // When + Object result = controller.hitTest(VALID_REPO_ID, VALID_QUERY, topN); + + // Then + assertThat(result).isNotNull(); + verify(repoService).hitTest( + eq(VALID_REPO_ID), + eq(VALID_QUERY), + integerCaptor.capture(), + eq(true)); + assertThat(integerCaptor.getValue()).isEqualTo(topN); + } + + /** + * Tests hit test with empty query string. + * Verifies that empty queries are properly rejected. + */ + @Test + @DisplayName("Hit test - empty query string") + void hitTest_EmptyQuery() { + // Given + when(repoService.hitTest(anyLong(), eq(""), anyInt(), eq(true))) + .thenThrow(new IllegalArgumentException("Query cannot be empty")); + + // When & Then + assertThatThrownBy(() -> controller.hitTest(VALID_REPO_ID, "", VALID_TOP_N)) + .isInstanceOf(IllegalArgumentException.class); + } + + /** + * Tests hit test with invalid repository ID. + * Verifies that invalid IDs are properly rejected. + */ + @Test + @DisplayName("Hit test - invalid repository ID") + void hitTest_InvalidRepoId() { + // Given + when(repoService.hitTest(eq(INVALID_REPO_ID), anyString(), anyInt(), eq(true))) + .thenThrow(new IllegalArgumentException("Repository not found")); + + // When & Then + assertThatThrownBy(() -> controller.hitTest(INVALID_REPO_ID, VALID_QUERY, VALID_TOP_N)) + .isInstanceOf(IllegalArgumentException.class); + } + + /** + * Tests hit test when service returns null. + * Verifies that null responses are properly handled. + */ + @Test + @DisplayName("Hit test - service returns null") + void hitTest_ServiceReturnsNull() { + // Given + when(repoService.hitTest(anyLong(), anyString(), anyInt(), eq(true))) + .thenReturn(null); + + // When + Object result = controller.hitTest(VALID_REPO_ID, VALID_QUERY, VALID_TOP_N); + + // Then + assertThat(result).isNull(); + } + } + + // ==================== listHitTestHistoryByPage Tests ==================== + + @Nested + @DisplayName("List Hit Test History By Page Tests") + class ListHitTestHistoryByPageTests { + + /** + * Tests listing hit test history with default pagination. + * Verifies that historical test data is correctly retrieved. + */ + @Test + @DisplayName("History list - default pagination") + void listHitTestHistoryByPage_DefaultPagination() { + // Given + when(repoService.listHitTestHistoryByPage(eq(VALID_REPO_ID), eq(DEFAULT_PAGE_NO), eq(DEFAULT_PAGE_SIZE))) + .thenReturn(validHitTestHistoryPageData); + + // When + ApiResult> result = controller.listHitTestHistoryByPage( + VALID_REPO_ID, DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE); + + // Then + assertThat(result.code()).isZero(); + assertThat(result.data()).isNotNull(); + assertThat(result.data().getPageData()).hasSize(1); + verify(repoService).listHitTestHistoryByPage(VALID_REPO_ID, DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE); + } + + /** + * Tests listing hit test history with various pagination parameters. Verifies that different page + * numbers and sizes work correctly. + * + * @param pageNo the page number + * @param pageSize the page size + */ + @ParameterizedTest + @CsvSource({ + "1, 5", + "2, 10", + "3, 20", + "5, 50" + }) + @DisplayName("History list - different pagination parameters") + void listHitTestHistoryByPage_DifferentPagination(int pageNo, int pageSize) { + // Given + PageData pageData = new PageData<>(); + pageData.setPage(pageNo); + pageData.setPageSize(pageSize); + when(repoService.listHitTestHistoryByPage(eq(VALID_REPO_ID), eq(pageNo), eq(pageSize))) + .thenReturn(pageData); + + // When + ApiResult> result = controller.listHitTestHistoryByPage( + VALID_REPO_ID, pageNo, pageSize); + + // Then + assertThat(result.data().getPage()).isEqualTo(pageNo); + assertThat(result.data().getPageSize()).isEqualTo(pageSize); + } + + /** + * Tests listing hit test history with empty results. Verifies that empty history lists are properly + * handled. + */ + @Test + @DisplayName("History list - empty result") + void listHitTestHistoryByPage_EmptyResult() { + // Given + PageData emptyPageData = new PageData<>(); + emptyPageData.setPageData(Collections.emptyList()); + emptyPageData.setTotalCount(0L); + when(repoService.listHitTestHistoryByPage(anyLong(), anyInt(), anyInt())) + .thenReturn(emptyPageData); + + // When + ApiResult> result = controller.listHitTestHistoryByPage( + VALID_REPO_ID, DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE); + + // Then + assertThat(result.data().getPageData()).isEmpty(); + assertThat(result.data().getTotalCount()).isZero(); + } + + /** + * Tests listing hit test history with invalid repository ID. + * Verifies that invalid IDs are properly rejected. + */ + @Test + @DisplayName("History list - invalid repository ID") + void listHitTestHistoryByPage_InvalidRepoId() { + // Given + when(repoService.listHitTestHistoryByPage(eq(INVALID_REPO_ID), anyInt(), anyInt())) + .thenThrow(new IllegalArgumentException("Repository not found")); + + // When & Then + assertThatThrownBy(() -> controller.listHitTestHistoryByPage( + INVALID_REPO_ID, DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE)) + .isInstanceOf(IllegalArgumentException.class); + } + } + + // ==================== enableRepo Tests ==================== + + @Nested + @DisplayName("Enable/Disable Repository Tests") + class EnableRepoTests { + + /** + * Tests enabling a repository. Verifies that repositories can be successfully enabled. + */ + @Test + @DisplayName("Enable repository") + void enableRepo_Enable() { + // Given + doNothing().when(repoService).enableRepo(eq(VALID_REPO_ID), eq(ENABLED)); + + // When + ApiResult result = controller.enableRepo(VALID_REPO_ID, ENABLED); + + // Then + assertThat(result.code()).isZero(); + assertThat(result.data()).isNull(); + verify(repoService).enableRepo(VALID_REPO_ID, ENABLED); + } + + /** + * Tests disabling a repository. Verifies that repositories can be successfully disabled. + */ + @Test + @DisplayName("Disable repository") + void enableRepo_Disable() { + // Given + doNothing().when(repoService).enableRepo(eq(VALID_REPO_ID), eq(DISABLED)); + + // When + ApiResult result = controller.enableRepo(VALID_REPO_ID, DISABLED); + + // Then + assertThat(result.code()).isZero(); + verify(repoService).enableRepo( + longCaptor.capture(), + integerCaptor.capture()); + assertThat(longCaptor.getValue()).isEqualTo(VALID_REPO_ID); + assertThat(integerCaptor.getValue()).isEqualTo(DISABLED); + } + + /** + * Tests enable/disable with different state values. Verifies that both enabled and disabled states + * work correctly. + * + * @param enabled the enabled state (0 for disabled, 1 for enabled) + */ + @ParameterizedTest + @ValueSource(ints = {0, 1}) + @DisplayName("Enable/disable - different state values") + void enableRepo_DifferentStates(int enabled) { + // Given + doNothing().when(repoService).enableRepo(anyLong(), eq(enabled)); + + // When + ApiResult result = controller.enableRepo(VALID_REPO_ID, enabled); + + // Then + assertThat(result.code()).isZero(); + verify(repoService).enableRepo(VALID_REPO_ID, enabled); + } + + /** + * Tests enabling repository with invalid ID. Verifies that appropriate exception is thrown for + * invalid IDs. + */ + @Test + @DisplayName("Enable repository - invalid ID") + void enableRepo_InvalidId() { + // Given + doThrow(new IllegalArgumentException("Repository not found")) + .when(repoService) + .enableRepo(eq(INVALID_REPO_ID), anyInt()); + + // When & Then + assertThatThrownBy(() -> controller.enableRepo(INVALID_REPO_ID, ENABLED)) + .isInstanceOf(IllegalArgumentException.class); + verify(repoService).enableRepo(INVALID_REPO_ID, ENABLED); + } + + /** + * Tests enable repository when service throws RuntimeException. Verifies that system errors are + * properly propagated. + */ + @Test + @DisplayName("Enable repository - service throws RuntimeException") + void enableRepo_ServiceThrowsRuntimeException() { + // Given + doThrow(new RuntimeException("System error")) + .when(repoService) + .enableRepo(anyLong(), anyInt()); + + // When & Then + assertThatThrownBy(() -> controller.enableRepo(VALID_REPO_ID, ENABLED)) + .isInstanceOf(RuntimeException.class) + .hasMessage("System error"); + } + } + + // ==================== deleteRepo Tests ==================== + + @Nested + @DisplayName("Delete Repository Tests") + class DeleteRepoTests { + + /** + * Tests deleting repository without tag parameter. Verifies that deletion works with minimal + * parameters. + */ + @Test + @DisplayName("Delete repository - without tag") + void deleteRepo_WithoutTag() { + // Given + Object expectedResult = Collections.singletonMap("success", true); + when(repoService.deleteRepo(eq(VALID_REPO_ID), isNull(), any(HttpServletRequest.class))) + .thenReturn(expectedResult); + + // When + Object result = controller.deleteRepo(VALID_REPO_ID, null, request); + + // Then + assertThat(result).isNotNull(); + verify(repoService).deleteRepo(VALID_REPO_ID, null, request); + } + + /** + * Tests deleting repository with tag parameter. Verifies that tag-filtered deletion works + * correctly. + */ + @Test + @DisplayName("Delete repository - with tag") + void deleteRepo_WithTag() { + // Given + Object expectedResult = Collections.singletonMap("success", true); + when(repoService.deleteRepo(eq(VALID_REPO_ID), eq(VALID_TAG), any(HttpServletRequest.class))) + .thenReturn(expectedResult); + + // When + Object result = controller.deleteRepo(VALID_REPO_ID, VALID_TAG, request); + + // Then + assertThat(result).isNotNull(); + verify(repoService).deleteRepo( + longCaptor.capture(), + stringCaptor.capture(), + any(HttpServletRequest.class)); + assertThat(longCaptor.getValue()).isEqualTo(VALID_REPO_ID); + assertThat(stringCaptor.getValue()).isEqualTo(VALID_TAG); + } + + /** + * Tests deleting repository with invalid ID. + * Verifies that appropriate exception is thrown for non-existent repositories. + */ + @Test + @DisplayName("Delete repository - invalid ID") + void deleteRepo_InvalidId() { + // Given + when(repoService.deleteRepo(eq(INVALID_REPO_ID), isNull(), any(HttpServletRequest.class))) + .thenThrow(new IllegalArgumentException("Repository not found")); + + // When & Then + assertThatThrownBy(() -> controller.deleteRepo(INVALID_REPO_ID, null, request)) + .isInstanceOf(IllegalArgumentException.class); + } + + /** + * Tests deleting repository that has dependencies. + * Verifies that deletion is prevented when dependencies exist. + */ + @Test + @DisplayName("Delete repository - with dependencies") + void deleteRepo_WithDependencies() { + // Given + when(repoService.deleteRepo(eq(VALID_REPO_ID), isNull(), any(HttpServletRequest.class))) + .thenThrow(new RuntimeException("Repository has dependencies and cannot be deleted")); + + // When & Then + assertThatThrownBy(() -> controller.deleteRepo(VALID_REPO_ID, null, request)) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("dependencies"); + } + + /** + * Tests deleting repository with different tag values. Verifies that various tag values including + * null and empty are handled correctly. + * + * @param tag the tag parameter value + */ + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = {"CBG-RAG", "AIUI-RAG2"}) + @DisplayName("Delete repository - different tag values") + void deleteRepo_DifferentTags(String tag) { + // Given + Object expectedResult = Collections.singletonMap("success", true); + when(repoService.deleteRepo(eq(VALID_REPO_ID), eq(tag), any(HttpServletRequest.class))) + .thenReturn(expectedResult); + + // When + Object result = controller.deleteRepo(VALID_REPO_ID, tag, request); + + // Then + assertThat(result).isNotNull(); + verify(repoService).deleteRepo(VALID_REPO_ID, tag, request); + } + } + + // ==================== setTop Tests ==================== + + @Nested + @DisplayName("Set Top Repository Tests") + class SetTopTests { + + /** + * Tests successfully setting a repository as top/pinned. Verifies that repositories can be pinned + * to the top of lists. + */ + @Test + @DisplayName("Set top - success") + void setTop_Success() { + // Given + doNothing().when(repoService).setTop(eq(VALID_REPO_ID)); + + // When + Object result = controller.setTop(VALID_REPO_ID); + + // Then + assertThat(result).isNotNull(); + verify(repoService, times(1)).setTop(VALID_REPO_ID); + } + + /** + * Tests that setTop returns proper ApiResult. Verifies the response structure and success code. + */ + @Test + @DisplayName("Set top - verify ApiResult") + void setTop_VerifyApiResult() { + // Given + doNothing().when(repoService).setTop(anyLong()); + + // When + Object result = controller.setTop(VALID_REPO_ID); + + // Then + assertThat(result).isInstanceOf(ApiResult.class); + ApiResult apiResult = (ApiResult) result; + assertThat(apiResult.code()).isZero(); + } + + /** + * Tests setTop with different repository IDs. Verifies that various valid IDs are correctly + * processed. + * + * @param id the repository ID to pin + */ + @ParameterizedTest + @ValueSource(longs = {1L, 10L, 100L, 999L}) + @DisplayName("Set top - different IDs") + void setTop_DifferentIds(Long id) { + // Given + doNothing().when(repoService).setTop(eq(id)); + + // When + controller.setTop(id); + + // Then + verify(repoService).setTop(longCaptor.capture()); + assertThat(longCaptor.getValue()).isEqualTo(id); + } + + /** + * Tests setTop with invalid repository ID. Verifies that appropriate exception is thrown for + * non-existent repositories. + */ + @Test + @DisplayName("Set top - invalid ID") + void setTop_InvalidId() { + // Given + doThrow(new IllegalArgumentException("Repository not found")) + .when(repoService) + .setTop(eq(INVALID_REPO_ID)); + + // When & Then + assertThatThrownBy(() -> controller.setTop(INVALID_REPO_ID)) + .isInstanceOf(IllegalArgumentException.class); + } + + /** + * Tests setTop when service throws exception. Verifies that errors during pinning are properly + * propagated. + */ + @Test + @DisplayName("Set top - service throws exception") + void setTop_ServiceThrowsException() { + // Given + doThrow(new RuntimeException("Set top failed")) + .when(repoService) + .setTop(anyLong()); + + // When & Then + assertThatThrownBy(() -> controller.setTop(VALID_REPO_ID)) + .isInstanceOf(RuntimeException.class) + .hasMessage("Set top failed"); + } + } + + // ==================== listFiles Tests ==================== + + @Nested + @DisplayName("List Files Tests") + class ListFilesTests { + + /** + * Tests successful file listing for a repository. Verifies that repository files are correctly + * retrieved. + */ + @Test + @DisplayName("List files - success") + void listFiles_Success() { + // Given + Object expectedResult = Collections.singletonList( + Collections.singletonMap("fileName", "test.txt")); + when(repoService.listFiles(eq(VALID_REPO_ID))).thenReturn(expectedResult); + + // When + Object result = controller.listFiles(VALID_REPO_ID); + + // Then + assertThat(result).isNotNull(); + verify(repoService, times(1)).listFiles(VALID_REPO_ID); + } + + /** + * Tests listing files when repository has no files. + * Verifies that empty file lists are properly handled. + */ + @Test + @DisplayName("List files - empty list") + void listFiles_EmptyList() { + // Given + when(repoService.listFiles(anyLong())).thenReturn(Collections.emptyList()); + + // When + Object result = controller.listFiles(VALID_REPO_ID); + + // Then + assertThat(result).isNotNull(); + assertThat(result).isEqualTo(Collections.emptyList()); + } + + /** + * Tests listing files with different repository IDs. + * Verifies that various repository IDs are correctly processed. + * + * @param repoId the repository ID to query + */ + @ParameterizedTest + @ValueSource(longs = {1L, 50L, 100L, 500L}) + @DisplayName("List files - different repository IDs") + void listFiles_DifferentRepoIds(Long repoId) { + // Given + when(repoService.listFiles(eq(repoId))).thenReturn(Collections.emptyList()); + + // When + controller.listFiles(repoId); + + // Then + verify(repoService).listFiles(longCaptor.capture()); + assertThat(longCaptor.getValue()).isEqualTo(repoId); + } + + /** + * Tests listing files with invalid repository ID. + * Verifies that appropriate exception is thrown for non-existent repositories. + */ + @Test + @DisplayName("List files - invalid ID") + void listFiles_InvalidId() { + // Given + when(repoService.listFiles(eq(INVALID_REPO_ID))) + .thenThrow(new IllegalArgumentException("Repository not found")); + + // When & Then + assertThatThrownBy(() -> controller.listFiles(INVALID_REPO_ID)) + .isInstanceOf(IllegalArgumentException.class); + } + + /** + * Tests listing files when service returns null. + * Verifies that null responses are properly handled. + */ + @Test + @DisplayName("List files - service returns null") + void listFiles_ServiceReturnsNull() { + // Given + when(repoService.listFiles(anyLong())).thenReturn(null); + + // When + Object result = controller.listFiles(VALID_REPO_ID); + + // Then + assertThat(result).isNull(); + } + + /** + * Tests listing files when file system error occurs. + * Verifies that system errors are properly propagated. + */ + @Test + @DisplayName("List files - system error") + void listFiles_SystemError() { + // Given + when(repoService.listFiles(anyLong())) + .thenThrow(new RuntimeException("File system error")); + + // When & Then + assertThatThrownBy(() -> controller.listFiles(VALID_REPO_ID)) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("File system error"); + } + } + + // ==================== getRepoUseStatus Tests ==================== + + @Nested + @DisplayName("Get Repository Use Status Tests") + class GetRepoUseStatusTests { + + /** + * Tests successful retrieval of repository usage status. Verifies that usage statistics are + * correctly returned. + */ + @Test + @DisplayName("Get use status - success") + void getRepoUseStatus_Success() { + // Given + Map expectedStatus = new HashMap<>(); + expectedStatus.put("storage", "100MB"); + expectedStatus.put("queries", 1000); + expectedStatus.put("connections", 5); + when(repoService.getRepoUseStatus(eq(VALID_REPO_ID), any(HttpServletRequest.class))) + .thenReturn(expectedStatus); + + // When + Object result = controller.getRepoUseStatus(VALID_REPO_ID, request); + + // Then + assertThat(result).isNotNull(); + verify(repoService, times(1)).getRepoUseStatus(VALID_REPO_ID, request); + } + + /** + * Tests getting use status when repository has empty status. + * Verifies that empty status maps are properly handled. + */ + @Test + @DisplayName("Get use status - empty status") + void getRepoUseStatus_EmptyStatus() { + // Given + when(repoService.getRepoUseStatus(anyLong(), any(HttpServletRequest.class))) + .thenReturn(Collections.emptyMap()); + + // When + Object result = controller.getRepoUseStatus(VALID_REPO_ID, request); + + // Then + assertThat(result).isNotNull(); + assertThat(result).isEqualTo(Collections.emptyMap()); + } + + /** + * Tests getting use status with null repository ID. + * Verifies that null IDs are properly handled. + */ + @Test + @DisplayName("Get use status - null ID") + void getRepoUseStatus_NullId() { + // Given + when(repoService.getRepoUseStatus(isNull(), any(HttpServletRequest.class))) + .thenReturn(Collections.emptyMap()); + + // When + Object result = controller.getRepoUseStatus(null, request); + + // Then + assertThat(result).isNotNull(); + verify(repoService).getRepoUseStatus(null, request); + } + + /** + * Tests getting use status with different repository IDs. + * Verifies that various repository IDs are correctly processed. + * + * @param repoId the repository ID to query + */ + @ParameterizedTest + @ValueSource(longs = {1L, 10L, 100L, 1000L}) + @DisplayName("Get use status - different IDs") + void getRepoUseStatus_DifferentIds(Long repoId) { + // Given + when(repoService.getRepoUseStatus(eq(repoId), any(HttpServletRequest.class))) + .thenReturn(Collections.emptyMap()); + + // When + controller.getRepoUseStatus(repoId, request); + + // Then + verify(repoService).getRepoUseStatus(longCaptor.capture(), any(HttpServletRequest.class)); + assertThat(longCaptor.getValue()).isEqualTo(repoId); + } + + /** + * Tests getting use status with invalid repository ID. + * Verifies that appropriate exception is thrown for non-existent repositories. + */ + @Test + @DisplayName("Get use status - invalid ID") + void getRepoUseStatus_InvalidId() { + // Given + when(repoService.getRepoUseStatus(eq(INVALID_REPO_ID), any(HttpServletRequest.class))) + .thenThrow(new IllegalArgumentException("Repository not found")); + + // When & Then + assertThatThrownBy(() -> controller.getRepoUseStatus(INVALID_REPO_ID, request)) + .isInstanceOf(IllegalArgumentException.class); + } + + /** + * Tests getting use status when service throws exception. + * Verifies that errors during status retrieval are properly propagated. + */ + @Test + @DisplayName("Get use status - service throws exception") + void getRepoUseStatus_ServiceThrowsException() { + // Given + when(repoService.getRepoUseStatus(anyLong(), any(HttpServletRequest.class))) + .thenThrow(new RuntimeException("Get status failed")); + + // When & Then + assertThatThrownBy(() -> controller.getRepoUseStatus(VALID_REPO_ID, request)) + .isInstanceOf(RuntimeException.class) + .hasMessage("Get status failed"); + } + + /** + * Tests getting use status when service returns null. + * Verifies that null responses are properly handled. + */ + @Test + @DisplayName("Get use status - returns null") + void getRepoUseStatus_ReturnsNull() { + // Given + when(repoService.getRepoUseStatus(anyLong(), any(HttpServletRequest.class))) + .thenReturn(null); + + // When + Object result = controller.getRepoUseStatus(VALID_REPO_ID, request); + + // Then + assertThat(result).isNull(); + } + } + + // ==================== Edge Cases and Exception Tests ==================== + + @Nested + @DisplayName("Edge Cases and Exception Scenarios Tests") + class EdgeCasesAndExceptionsTests { + + /** + * Tests handling of large ID values. Verifies that maximum long values are correctly processed. + */ + @Test + @DisplayName("Large ID values test") + void testLargeIdValues() { + // Given + Long largeId = Long.MAX_VALUE; + when(repoService.getDetail(eq(largeId), anyString(), any(HttpServletRequest.class))) + .thenReturn(validRepoDto); + + // When + ApiResult result = controller.getDetail(largeId, "", request); + + // Then + assertThat(result.code()).isZero(); + verify(repoService).getDetail(largeId, "", request); + } + + /** + * Tests concurrent calls to the controller. + * Verifies that the controller is thread-safe under concurrent access. + * + * @throws InterruptedException if thread is interrupted during execution + */ + @Test + @DisplayName("Concurrent calls test") + void testConcurrentCalls() throws InterruptedException { + // Given + when(repoService.getDetail(anyLong(), anyString(), any(HttpServletRequest.class))) + .thenReturn(validRepoDto); + + // When + int threadCount = 10; + List threads = new ArrayList<>(); + for (int i = 0; i < threadCount; i++) { + Thread thread = new Thread(() -> + controller.getDetail(VALID_REPO_ID, "", request)); + threads.add(thread); + thread.start(); + } + + for (Thread thread : threads) { + thread.join(); + } + + // Then + verify(repoService, times(threadCount)).getDetail( + eq(VALID_REPO_ID), eq(""), any(HttpServletRequest.class)); + } + + /** + * Tests handling of special characters in input. Verifies that special characters are properly + * escaped and processed. + */ + @Test + @DisplayName("Special characters handling test") + void testSpecialCharacters() { + // Given + String specialContent = "test<>&\"'%#@!"; + when(repoService.listRepos(anyInt(), anyInt(), eq(specialContent), any(HttpServletRequest.class))) + .thenReturn(validPageData); + + // When + ApiResult> result = controller.listRepos( + DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, specialContent, request); + + // Then + assertThat(result.code()).isZero(); + verify(repoService).listRepos(anyInt(), anyInt(), eq(specialContent), any(HttpServletRequest.class)); + } + + /** + * Tests handling of very long strings. Verifies that extremely long input strings are properly + * processed. + */ + @Test + @DisplayName("Very long string test") + void testVeryLongString() { + // Given + String longString = "a".repeat(10000); + when(repoService.listRepos(anyInt(), anyInt(), eq(longString), any(HttpServletRequest.class))) + .thenReturn(validPageData); + + // When + ApiResult> result = controller.listRepos( + DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, longString, request); + + // Then + assertThat(result.code()).isZero(); + } + + /** + * Tests handling of extreme pagination parameter values. + * Verifies that maximum integer values for pagination are properly handled. + */ + @Test + @DisplayName("Extreme pagination values test") + void testExtremePaginationValues() { + // Given + when(repoService.listRepos(eq(Integer.MAX_VALUE), eq(Integer.MAX_VALUE), isNull(), any(HttpServletRequest.class))) + .thenReturn(validPageData); + + // When + ApiResult> result = controller.listRepos( + Integer.MAX_VALUE, Integer.MAX_VALUE, null, request); + + // Then + assertThat(result.code()).isZero(); + } + + /** + * Tests handling of multiple null parameters. + * Verifies that methods work correctly when multiple optional parameters are null. + */ + @Test + @DisplayName("Multiple null parameters test") + void testMultipleNullParameters() { + // Given + when(repoService.list(anyInt(), anyInt(), isNull(), isNull(), any(HttpServletRequest.class), isNull())) + .thenReturn(validPageData); + + // When + Object result = controller.list(DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, null, null, null, request); + + // Then + assertThat(result).isNotNull(); + verify(repoService).list( + eq(DEFAULT_PAGE_NO), eq(DEFAULT_PAGE_SIZE), + isNull(), isNull(), any(HttpServletRequest.class), isNull()); + } + + /** + * Tests handling of Unicode characters including emojis. Verifies that Unicode strings are properly + * processed. + */ + @Test + @DisplayName("Unicode characters test") + void testUnicodeCharacters() { + // Given + String unicodeContent = "test🚀📊💡"; + when(repoService.listRepos(anyInt(), anyInt(), eq(unicodeContent), any(HttpServletRequest.class))) + .thenReturn(validPageData); + + // When + ApiResult> result = controller.listRepos( + DEFAULT_PAGE_NO, DEFAULT_PAGE_SIZE, unicodeContent, request); + + // Then + assertThat(result.code()).isZero(); + } + } + + // ==================== Integration Scenario Tests ==================== + + @Nested + @DisplayName("Integration Scenarios Tests") + class IntegrationScenariosTests { + + /** + * Tests complete workflow: create, query, update, and delete operations. + * Verifies that all CRUD operations work together correctly. + */ + @Test + @DisplayName("Full workflow - create, query, update, delete") + void fullWorkflow_CreateQueryUpdateDelete() { + // 1. Create + when(repoService.createRepo(any(RepoVO.class))).thenReturn(validRepo); + ApiResult createResult = controller.createRepo(validRepoVO); + assertThat(createResult.code()).isZero(); + + // 2. Query + when(repoService.getDetail(eq(VALID_REPO_ID), anyString(), any(HttpServletRequest.class))) + .thenReturn(validRepoDto); + ApiResult detailResult = controller.getDetail(VALID_REPO_ID, "", request); + assertThat(detailResult.code()).isZero(); + + // 3. Update + when(repoService.updateRepo(any(RepoVO.class))).thenReturn(validRepo); + ApiResult updateResult = controller.updateRepo(validRepoVO); + assertThat(updateResult.code()).isZero(); + + // 4. Delete + when(repoService.deleteRepo(eq(VALID_REPO_ID), isNull(), any(HttpServletRequest.class))) + .thenReturn(Collections.singletonMap("success", true)); + Object deleteResult = controller.deleteRepo(VALID_REPO_ID, null, request); + assertThat(deleteResult).isNotNull(); + + // Verify all interactions + verify(repoService).createRepo(any(RepoVO.class)); + verify(repoService).getDetail(eq(VALID_REPO_ID), anyString(), any(HttpServletRequest.class)); + verify(repoService).updateRepo(any(RepoVO.class)); + verify(repoService).deleteRepo(eq(VALID_REPO_ID), isNull(), any(HttpServletRequest.class)); + } + + /** + * Tests search and pagination scenario. + * Verifies that search with pagination across multiple pages works correctly. + */ + @Test + @DisplayName("Search and pagination scenario") + void searchAndPaginationScenario() { + // Given + when(repoService.listRepos(anyInt(), anyInt(), anyString(), any(HttpServletRequest.class))) + .thenReturn(validPageData); + + // When - First page + ApiResult> page1 = controller.listRepos(1, 10, "test", request); + // When - Second page + ApiResult> page2 = controller.listRepos(2, 10, "test", request); + + // Then + assertThat(page1.code()).isZero(); + assertThat(page2.code()).isZero(); + verify(repoService, times(2)).listRepos(anyInt(), anyInt(), eq("test"), any(HttpServletRequest.class)); + } + + /** + * Tests hit test and history query scenario. Verifies that hit testing and history retrieval work + * together correctly. + */ + @Test + @DisplayName("Hit test and history query scenario") + void hitTestAndHistoryScenario() { + // Given + Object hitTestResult = Collections.singletonMap("hits", Collections.emptyList()); + when(repoService.hitTest(anyLong(), anyString(), anyInt(), eq(true))) + .thenReturn(hitTestResult); + when(repoService.listHitTestHistoryByPage(anyLong(), anyInt(), anyInt())) + .thenReturn(validHitTestHistoryPageData); + + // When + Object testResult = controller.hitTest(VALID_REPO_ID, "test query", 5); + ApiResult> historyResult = + controller.listHitTestHistoryByPage(VALID_REPO_ID, 1, 10); + + // Then + assertThat(testResult).isNotNull(); + assertThat(historyResult.code()).isZero(); + verify(repoService).hitTest(VALID_REPO_ID, "test query", 5, true); + verify(repoService).listHitTestHistoryByPage(VALID_REPO_ID, 1, 10); + } + } + + // ==================== Mockito Verification Tests ==================== + + @Nested + @DisplayName("Mockito Verification Tests") + class MockitoVerificationTests { + + /** + * Tests verification of method invocation counts. + * Verifies that methods are called the expected number of times. + */ + @Test + @DisplayName("Verify method invocation counts") + void verifyMethodInvocationCounts() { + // Given + when(repoService.listFiles(anyLong())).thenReturn(Collections.emptyList()); + + // When + controller.listFiles(VALID_REPO_ID); + controller.listFiles(VALID_REPO_ID); + controller.listFiles(VALID_REPO_ID); + + // Then + verify(repoService, times(3)).listFiles(VALID_REPO_ID); + verify(repoService, never()).deleteRepo(anyLong(), anyString(), any(HttpServletRequest.class)); + } + + /** + * Tests verification of argument capture. + * Verifies that method arguments are correctly captured for verification. + */ + @Test + @DisplayName("Verify argument capture") + void verifyArgumentCapture() { + // Given + when(repoService.createRepo(any(RepoVO.class))).thenReturn(validRepo); + + // When + controller.createRepo(validRepoVO); + + // Then + verify(repoService).createRepo(repoVOCaptor.capture()); + RepoVO captured = repoVOCaptor.getValue(); + assertThat(captured.getName()).isEqualTo(VALID_NAME); + assertThat(captured.getDesc()).isEqualTo(VALID_DESC); + assertThat(captured.getTags()).containsExactly("tag1", "tag2"); + } + + /** + * Tests verification of method invocation order. + * Verifies that methods are called in the expected sequence. + */ + @Test + @DisplayName("Verify method invocation order") + void verifyMethodInvocationOrder() { + // Given + when(repoService.createRepo(any(RepoVO.class))).thenReturn(validRepo); + when(repoService.updateRepo(any(RepoVO.class))).thenReturn(validRepo); + doNothing().when(repoService).setTop(anyLong()); + + // When + controller.createRepo(validRepoVO); + controller.updateRepo(validRepoVO); + controller.setTop(VALID_REPO_ID); + + // Then + var inOrder = inOrder(repoService); + inOrder.verify(repoService).createRepo(any(RepoVO.class)); + inOrder.verify(repoService).updateRepo(any(RepoVO.class)); + inOrder.verify(repoService).setTop(VALID_REPO_ID); + } + + /** + * Tests verification that no interactions occurred. Verifies that service methods were not called + * when controller methods are not invoked. + */ + @Test + @DisplayName("Verify no interactions") + void verifyNoInteractionsTest() { + // When - no methods called + + // Then + verifyNoMoreInteractions(repoService); + } + } +} diff --git a/core/common/.env.example b/core/common/.env.example index 2a85a150c554cc14dceac2f745dce636e38c6ab9..3493ac8d4ab4ef1436f9c4df3638d11986121461 100644 --- a/core/common/.env.example +++ b/core/common/.env.example @@ -6,19 +6,20 @@ SERVICE_LOCATION=hf SERVICE_PORT=7880 # CACHE -REDIS_CLUSTER_ADDR=node-a.redis-hf04-aldav8.svc.hfb.ipaas.cn:9000,node-b.redis-hf04-aldav8.svc.hfb.ipaas.cn:9000,node-c.redis-hf04-aldav8.svc.hfb.ipaas.cn:9000,node-d.redis-hf04-aldav8.svc.hfb.ipaas.cn:9000,node-e.redis-hf04-aldav8.svc.hfb.ipaas.cn:9000,node-f.redis-hf04-aldav8.svc.hfb.ipaas.cn:9000 -REDIS_PASSWORD=NPTzHSR8 +REDIS_CLUSTER_ADDR= +REDIS_PASSWORD= REDIS_EXPIRE=60 # DATABASE -MYSQL_HOST=mysql-Nu8weB0lBq.mysql.zone-hfyc-1.dbaas.private -MYSQL_PORT=28290 -MYSQL_USER=admin -MYSQL_PASSWORD=EdgeAIGo! -MYSQL_DB=langflow_dev +MYSQL_HOST= +MYSQL_PORT= +MYSQL_USER= +MYSQL_PASSWORD= +MYSQL_DB= # KAFKA -KAFKA_SERVERS=kafka-0.kafka-hf04-1quuxb.svc.hfb.ipaas.cn:9092,kafka-1.kafka-hf04-1quuxb.svc.hfb.ipaas.cn:9092,kafka-2.kafka-hf04-1quuxb.svc.hfb.ipaas.cn:9092 +KAFKA_ENABLE=0 +KAFKA_SERVERS= KAFKA_TIMEOUT=10 # LOG @@ -28,13 +29,13 @@ LOG_LEVEL="ERROR" # MASDK (Model as SDK) Configuration # Service discovery and model integration settings for distributed AI services # MASDK_SWITCH=1 -MASDK_POLARIS_URL=http://companion-test.iflyaicloud.com:9080 -MASDK_POLARIS_PROJECT=AIaaS -MASDK_POLARIS_GROUP=madx -MASDK_POLARIS_SERVICE=janus-client -MASDK_POLARIS_VERSION=3.1.2 -MASDK_CHANNEL=xingchen_agent_workflow -MASDK_FUNCTION=business.total +MASDK_POLARIS_URL= +MASDK_POLARIS_PROJECT= +MASDK_POLARIS_GROUP= +MASDK_POLARIS_SERVICE= +MASDK_POLARIS_VERSION= +MASDK_CHANNEL= +MASDK_FUNCTION= # OSS # ============================================================================= @@ -43,19 +44,19 @@ MASDK_FUNCTION=business.total # Object Storage Service Settings # Storage type options: ifly_gateway_storage (iFlytek), s3 (Amazon S3 compatible) -OSS_TYPE=ifly_gateway_storage -OSS_ENDPOINT=http://172.30.209.27:8211 -OSS_ACCESS_KEY_ID=sjliu777 -OSS_ACCESS_KEY_SECRET=12345678 -OSS_BUCKET_NAME=sjliu +OSS_TYPE= +OSS_ENDPOINT= +OSS_ACCESS_KEY_ID= +OSS_ACCESS_KEY_SECRET= +OSS_BUCKET_NAME= # Download domain for S3, required when using S3 storage type -OSS_DOWNLOAD_HOST=https://oss-beijing-m8.openstorage.cn +OSS_DOWNLOAD_HOST= # File validity period for iFlytek object storage (in seconds) OSS_TTL=157788000 # OTLP # 上报地址 -OTLP_ENDPOINT=172.30.209.27:4317 +OTLP_ENDPOINT= # 上报开关 OTLP_ENABLE=1 @@ -77,14 +78,14 @@ OTLP_TRACE_EXPORT_TIMEOUT_MILLIS=3000 # CONFIG - 需要配置在容器环境中 CONFIG_ENV_PATH=./.env POLARIS_ENABLED=false -POLARIS_BASE_URL=http://172.30.209.27:8090/ -POLARIS_USERNAME=mingduan -POLARIS_PASSWORD=123456l -POLARIS_PROJECT=hy-spark-agent-builder -POLARIS_CLUSTER=dev -POLARIS_SERVICE=spark-agent +POLARIS_BASE_URL= +POLARIS_USERNAME= +POLARIS_PASSWORD= +POLARIS_PROJECT= +POLARIS_CLUSTER= +POLARIS_SERVICE= POLARIS_VERSION=1.0.0 -POLARIS_CONFIG_FILE=spark-agent.env +POLARIS_CONFIG_FILE= POLARIS_RETRY_COUNT=3 POLARIS_RETRY_INTERVAL=10 diff --git a/core/common/service/kafka/factory.py b/core/common/service/kafka/factory.py index 843024fd5b6a6bba5f4681514eae69763ae2020e..605c8f5c0d2ab6080ada092848303e0e668d3d91 100644 --- a/core/common/service/kafka/factory.py +++ b/core/common/service/kafka/factory.py @@ -16,7 +16,14 @@ class KafkaProducerServiceFactory(ServiceFactory): :return: KafkaProducerService 实例 """ servers = servers or os.getenv("KAFKA_SERVERS") - if not servers: + enable = os.getenv("KAFKA_ENABLE", "false").lower() in ( + "true", + "1", + "yes", + "on", + ) + + if enable and not servers: raise ValueError("KAFKA_SERVERS 环境变量未配置") config = {"bootstrap.servers": servers, **kwargs} diff --git a/core/common/service/kafka/kafka_service.py b/core/common/service/kafka/kafka_service.py index 747dcfdfe129ea8dc11dca84eeb9d806cd4001ca..4541c2c6cf23cbaca8797308a99bfb1353346e94 100644 --- a/core/common/service/kafka/kafka_service.py +++ b/core/common/service/kafka/kafka_service.py @@ -23,7 +23,7 @@ class KafkaProducerService(Service): topic: str, value: str, callback: Optional[Any] = None, - timeout: int = int(os.getenv("KAFKA_TIMEOUT", 10)), + timeout: Optional[int] = None, ) -> None: """ 发送 Kafka 消息 @@ -32,6 +32,17 @@ class KafkaProducerService(Service): :param callback: 回调函数 :param timeout: poll timeout (秒) """ + if os.getenv("KAFKA_ENABLE", "false").lower() not in ( + "true", + "1", + "yes", + "on", + ): + return + + if not timeout: + timeout = int(os.getenv("KAFKA_TIMEOUT", 10)) + if not callback: callback = self._delivery_report try: diff --git a/core/memory/database/main.py b/core/memory/database/main.py index aa60ec8c87756eb60d4d1e57fd583f12894dc7b4..258eb638f9371a7353dc6c660fff1185a9958516 100644 --- a/core/memory/database/main.py +++ b/core/memory/database/main.py @@ -178,7 +178,7 @@ if __name__ == "__main__": workers=( None if sys.platform in ["win", "win32", "darwin"] - else int(os.getenv("WORKERS", "20")) + else int(os.getenv("WORKERS", "1")) ), reload=False, log_level="error", diff --git a/core/memory/database/repository/middleware/database/db_manager.py b/core/memory/database/repository/middleware/database/db_manager.py index 7d3b2837ac0a906a7e12a3f085351694fbe726b6..6f0f1faf58a2a030adb2bf69397299a5d2e14a60 100644 --- a/core/memory/database/repository/middleware/database/db_manager.py +++ b/core/memory/database/repository/middleware/database/db_manager.py @@ -34,8 +34,8 @@ class DatabaseService(Service): self, database_url: str, connect_timeout: int = 10, - pool_size: int = 200, - max_overflow: int = 800, + pool_size: int = 20, + max_overflow: int = 20, pool_recycle: int = 3600, ): """Initialize database service with connection parameters. @@ -60,8 +60,8 @@ class DatabaseService(Service): cls, database_url: str, connect_timeout: int = 10, - pool_size: int = 200, - max_overflow: int = 800, + pool_size: int = 20, + max_overflow: int = 20, pool_recycle: int = 3600, ) -> "DatabaseService": """Create and initialize database service instance. diff --git a/core/workflow/api/v1/chat/node_debug.py b/core/workflow/api/v1/chat/node_debug.py index b080e58601f5e0d5752289bb31fa015655c6c9cc..f6e24274c44c1c5d026355c57c33b8068e3b051a 100644 --- a/core/workflow/api/v1/chat/node_debug.py +++ b/core/workflow/api/v1/chat/node_debug.py @@ -80,10 +80,14 @@ async def node_debug(node_debug_vo: NodeDebugVo) -> JSONResponse: span = Span() with span.start(attributes={"flow_id": node_debug_vo.id}) as span_context: try: - if node_debug_vo.data.nodes[0].id.split("::")[0] in NodeType.DATABASE.value: + if ( + node_debug_vo.data.nodes + and node_debug_vo.data.nodes[0].id.split("::")[0] + in NodeType.DATABASE.value + ): span.uid = node_debug_vo.data.nodes[0].data.nodeParam.get("uid", "") node_debug_resp_vo = await flow_service.node_debug( - node_debug_vo.data, span_context + node_debug_vo.data, node_debug_vo.id, span_context ) except CustomException as err: diff --git a/core/workflow/api/v1/flow/layout.py b/core/workflow/api/v1/flow/layout.py index 5097f74c5f3eb70a58f612638bf298b95a17aa30..b95b417debab94d423398c781c2804703ff23fb6 100644 --- a/core/workflow/api/v1/flow/layout.py +++ b/core/workflow/api/v1/flow/layout.py @@ -20,7 +20,6 @@ from starlette.responses import JSONResponse, StreamingResponse from workflow.cache.flow import del_flow_by_id from workflow.consts.comparisons import Tag -from workflow.consts.flow import FlowStatus from workflow.domain.entities.compare_flow import DeleteComparisonVo, SaveComparisonVo from workflow.domain.entities.flow import FlowRead, FlowUpdate from workflow.domain.entities.response import Resp, Streaming @@ -33,7 +32,7 @@ from workflow.extensions.middleware.cache.base import BaseCacheService from workflow.extensions.middleware.getters import get_cache_service, get_session from workflow.extensions.otlp.metric.meter import Meter from workflow.extensions.otlp.trace.span import Span -from workflow.service import app_service, flow_service, license_service +from workflow.service import app_service, flow_service router = APIRouter(tags=["Flows"]) @@ -56,12 +55,6 @@ def add( ) as current_span: try: current_span.add_info_event(f"add flow vo: {flow.json()}") - if flow.status not in [FlowStatus.DRAFT.value, FlowStatus.PUBLISHED.value]: - raise CustomException( - err_code=CodeEnum.PROTOCOL_CREATE_ERROR, - err_msg=f"status value can only be 0 or 1, " - f"current value is {flow.status}", - ) app_info = app_service.get_info(flow.app_id, session, current_span) db_flow = flow_service.save(flow, app_info, session, current_span) @@ -164,13 +157,6 @@ def update( if not db_flow: raise CustomException(CodeEnum.FLOW_NOT_FOUND_ERROR) - # Register app_id to App table for published workflows - # and bind in license table - if db_flow.status > 0 or (flow.status is not None and flow.status > 0): - if not db_flow.app_id: - raise CustomException(CodeEnum.FLOW_NO_APP_ID_ERROR) - db_app = app_service.get_info(db_flow.app_id, session, current_span) - license_service.bind(session, db_app, db_flow.group_id) flow_service.update(session, db_flow, flow, flow_id, current_span) m.in_success_count() return Resp.success(None, span.sid) @@ -337,7 +323,6 @@ def save_comparisons( name=db_flow.name, data=chat_input.data, description=db_flow.description, - status=db_flow.status, app_id=db_flow.app_id, source=db_flow.source, version=chat_input.version, diff --git a/core/workflow/config.env b/core/workflow/config.env index afb90ab14775c401c2d463258c4253a993d8d714..7c2dde188ffd51a897b14c410ffbf902b69e0411 100644 --- a/core/workflow/config.env +++ b/core/workflow/config.env @@ -99,6 +99,7 @@ OSS_TTL=157788000 # Apache Kafka Configuration # Message queue settings for asynchronous processing and event streaming +KAFKA_ENABLE=1 KAFKA_SERVERS=127.0.0.1:9092 KAFKA_TIMEOUT=10 KAFKA_TOPIC=spark-agent-builder diff --git a/core/workflow/consts/engine/timeout.py b/core/workflow/consts/engine/timeout.py index 21466bbd99d05de24222812caccec042181538ad..39abea0249b6ceae63a9f873913169bd90f07265 100644 --- a/core/workflow/consts/engine/timeout.py +++ b/core/workflow/consts/engine/timeout.py @@ -3,3 +3,4 @@ from enum import Enum class QueueTimeout(Enum): AsyncQT = 600 + PingQT = 30 diff --git a/core/workflow/consts/flow.py b/core/workflow/consts/flow.py deleted file mode 100644 index ab793dbe0b1fd409e9bcaa26473add7087b61e74..0000000000000000000000000000000000000000 --- a/core/workflow/consts/flow.py +++ /dev/null @@ -1,19 +0,0 @@ -""" -Workflow and flow-related constants. - -This module defines constants and enumerations for workflow execution, -node statuses, error handling, and flow states. -""" - -from enum import Enum - - -class FlowStatus(Enum): - """ - Flow status enumeration. - - Defines the publication status of workflows. - """ - - DRAFT = 0 - PUBLISHED = 1 diff --git a/core/workflow/domain/entities/flow.py b/core/workflow/domain/entities/flow.py index 8078b07e86b8879c5f3698658675be66f15006e1..0135485ace4926904c747a6b686d59175f228ad5 100644 --- a/core/workflow/domain/entities/flow.py +++ b/core/workflow/domain/entities/flow.py @@ -31,7 +31,6 @@ class FlowUpdate(BaseModel): :param description: Workflow description :param data: Workflow data dictionary :param app_id: Application ID - :param status: Workflow status """ id: Optional[str] = None @@ -39,7 +38,6 @@ class FlowUpdate(BaseModel): description: Optional[str] = None data: Optional[Dict] = None app_id: Optional[str] = None - status: Optional[int] = None class Edge(BaseModel): diff --git a/core/workflow/domain/models/flow.py b/core/workflow/domain/models/flow.py index 6401cf40b21681e1aafdb56b7c87077b454c1851..45ca8b9619209c6e1b3936831989051c5288975a 100644 --- a/core/workflow/domain/models/flow.py +++ b/core/workflow/domain/models/flow.py @@ -29,7 +29,6 @@ class Flow(SQLModelSerializable, table=True): # type: ignore :param release_data: Released workflow data (stored as JSON) :param description: Workflow description :param version: Workflow version string - :param status: Workflow status (0=inactive, 1=active) :param release_status: Release status (0=not released, 1=released) :param app_id: Associated application identifier :param source: Source identifier for the workflow @@ -45,7 +44,6 @@ class Flow(SQLModelSerializable, table=True): # type: ignore release_data: Dict = Field(default_factory=dict, sa_column=Column(JSON)) description: str = Field(default="", index=True) version: str = Field(default="", index=True) - status: int = Field(default=0) release_status: int = Field(default=0) app_id: str = Field(default="") source: int = Field(default=0) diff --git a/core/workflow/engine/dsl_engine.py b/core/workflow/engine/dsl_engine.py index 27fdb0f82ad3389f55da870c6c04e1adaee13582..c217cb2b9012a9bf34495447281b0e241ca6785e 100644 --- a/core/workflow/engine/dsl_engine.py +++ b/core/workflow/engine/dsl_engine.py @@ -35,7 +35,6 @@ from workflow.engine.entities.variable_pool import VariablePool from workflow.engine.entities.workflow_dsl import Edge, Node, NodeRef, WorkflowDSL from workflow.engine.node import NodeFactory, SparkFlowEngineNode from workflow.engine.nodes.base_node import BaseNode -from workflow.engine.nodes.cache_node import tool_classes from workflow.engine.nodes.entities.node_run_result import ( NodeRunResult, WorkflowNodeExecutionStatus, @@ -2026,6 +2025,9 @@ class WorkflowEngineBuilder: :return: None :raises CustomException: If node validation fails """ + + from workflow.engine.nodes.cache_node import tool_classes + node_type = node_id.split(":")[0] node_class = tool_classes.get(node_type) diff --git a/core/workflow/engine/entities/file.py b/core/workflow/engine/entities/file.py index 366d82bf6051060165ff79d432ffd03a50088f90..b6d9369422aab4b4df6f0ffe39762a049497d771 100644 --- a/core/workflow/engine/entities/file.py +++ b/core/workflow/engine/entities/file.py @@ -1,7 +1,6 @@ import re from typing import Tuple -import requests # type: ignore from pydantic import BaseModel from workflow.configs import workflow_config @@ -121,6 +120,8 @@ class File(BaseModel): """ try: # Send HEAD request + import requests # type: ignore + response = requests.head(input_file_url) # Get file metadata from response headers content_length = response.headers.get( diff --git a/core/workflow/engine/entities/variable_pool.py b/core/workflow/engine/entities/variable_pool.py index 1dfaa460a699af353dc15471d3f33710d1d1cb00..11b4ca41c1958bea04b75a1994cfcd45e1297f58 100644 --- a/core/workflow/engine/entities/variable_pool.py +++ b/core/workflow/engine/entities/variable_pool.py @@ -162,7 +162,8 @@ class ParamKey(str, Enum): Enumeration of system parameter keys. """ - FlowOutputMode = "flowOutputMode" + FlowId = "flow_id" + FlowOutputMode = "flow_output_mode" IsRelease = "is_release" diff --git a/core/workflow/engine/node.py b/core/workflow/engine/node.py index 30540c3f9094c2b956952a43840b05bee7686801..acf091ad6dccc651a54d3a2ef647cc11b549c88a 100644 --- a/core/workflow/engine/node.py +++ b/core/workflow/engine/node.py @@ -14,7 +14,6 @@ from workflow.engine.entities.retry_config import RetryConfig from workflow.engine.entities.variable_pool import VariablePool from workflow.engine.entities.workflow_dsl import InputItem, Node, OutputItem from workflow.engine.nodes.base_node import BaseNode -from workflow.engine.nodes.cache_node import tool_classes from workflow.engine.nodes.entities.node_run_result import ( NodeRunResult, WorkflowNodeExecutionStatus, @@ -654,6 +653,9 @@ class NodeFactory: :return: Created node instance :raises CustomException: When node type is not supported """ + + from workflow.engine.nodes.cache_node import tool_classes + node_class = tool_classes.get(node.get_node_type()) if not node_class: raise CustomException( diff --git a/core/workflow/engine/nodes/base_node.py b/core/workflow/engine/nodes/base_node.py index cc58004c8b3dab753f0336faa3e5741bec03dc4e..11d33be17fdb9cd4aa38e36359f5c60a6a3687ec 100644 --- a/core/workflow/engine/nodes/base_node.py +++ b/core/workflow/engine/nodes/base_node.py @@ -6,7 +6,6 @@ from abc import abstractmethod from asyncio import Event from typing import Any, AsyncIterator, Dict, List, Literal, Optional, Tuple -import requests # type: ignore from pydantic import BaseModel, Field, PrivateAttr from workflow.consts.engine.chat_status import ChatStatus, SparkLLMStatus @@ -1188,6 +1187,8 @@ class BaseLLMNode(BaseNode): payload_comp_history.pop(0) # If it's an image understanding model, reserve the first position in array for image if image_url: + import requests # type: ignore + image_response = requests.get(image_url) if image_response.status_code != 200: raise Exception(f"Failed to download image from {image_url}") diff --git a/core/workflow/engine/nodes/global_variables/global_variables_node.py b/core/workflow/engine/nodes/global_variables/global_variables_node.py index 3eab31977ecef3353ec8e95e02f58808e1b452a9..0c5dbba467c32721de839ca017ab07cc88b1120f 100644 --- a/core/workflow/engine/nodes/global_variables/global_variables_node.py +++ b/core/workflow/engine/nodes/global_variables/global_variables_node.py @@ -11,7 +11,7 @@ from typing import Any, Literal from pydantic import Field -from workflow.engine.entities.variable_pool import VariablePool +from workflow.engine.entities.variable_pool import ParamKey, VariablePool from workflow.engine.nodes.base_node import BaseNode from workflow.engine.nodes.entities.node_run_result import ( NodeRunResult, @@ -126,7 +126,6 @@ class GlobalVariablesNode(BaseNode): """ method: Literal["set", "get"] = Field(...) # Operation method: "set" or "get" - flowId: str = Field(...) # Flow identifier for variable scope async def async_execute( self, @@ -151,10 +150,10 @@ class GlobalVariablesNode(BaseNode): try: inputs: dict = {} outputs: dict = {} - + flow_id: str = variable_pool.system_params.get(ParamKey.FlowId) # Build Redis key components for cache operations redis_key = { - "flow_id": self.flowId, + "flow_id": flow_id, "uid": span.uid, "app_id": span.app_id, "chat_id": variable_pool.chat_id, @@ -165,7 +164,7 @@ class GlobalVariablesNode(BaseNode): # Initialize variable manager for cache operations var_manager = VariablesManage( - flow_id=self.flowId, + flow_id=flow_id, uid=span.uid, app_id=span.app_id, chat_id=variable_pool.chat_id, diff --git a/core/workflow/engine/nodes/knowledge/knowledge_node.py b/core/workflow/engine/nodes/knowledge/knowledge_node.py index 8fdf13ad2b670d58c7fb6118a6862d4bfd90a280..fdba24cb142714592a2f5d54d0ebb15f2e159ce8 100644 --- a/core/workflow/engine/nodes/knowledge/knowledge_node.py +++ b/core/workflow/engine/nodes/knowledge/knowledge_node.py @@ -5,7 +5,7 @@ from typing import Any from pydantic import Field from workflow.engine.entities.history import EnableChatHistoryV2, History -from workflow.engine.entities.variable_pool import VariablePool +from workflow.engine.entities.variable_pool import ParamKey, VariablePool from workflow.engine.nodes.base_node import BaseNode from workflow.engine.nodes.entities.node_run_result import ( NodeRunResult, @@ -37,7 +37,6 @@ class KnowledgeNode(BaseNode): docIds: list = Field( default_factory=list ) # Optional list of specific document IDs to search - flowId: str = Field(default="") # Optional flow ID for context score: float = Field(default=0.1) # Minimum similarity threshold for results enableChatHistoryV2: EnableChatHistoryV2 = Field( default_factory=EnableChatHistoryV2 @@ -100,13 +99,14 @@ class KnowledgeNode(BaseNode): knowledge_recall_url = ( f"{os.getenv('KNOWLEDGE_BASE_URL')}/knowledge/v1/chunk/query" ) + flow_id: str = variable_pool.system_params.get(ParamKey.FlowId) knowledge_config = KnowledgeConfig( top_n=self.topN, rag_type=self.ragType, repo_id=self.repoId, url=knowledge_recall_url, query=str(query), - flow_id=self.flowId, + flow_id=flow_id, doc_ids=self.docIds, threshold=self.score, history=history, diff --git a/core/workflow/engine/nodes/plugin_tool/link_client.py b/core/workflow/engine/nodes/plugin_tool/link_client.py index b669ee20b107f06a1811da506af5f4033c212186..ed34460557b3680e8e82c9650f04374217ddc947 100644 --- a/core/workflow/engine/nodes/plugin_tool/link_client.py +++ b/core/workflow/engine/nodes/plugin_tool/link_client.py @@ -3,8 +3,6 @@ import time from base64 import b64encode from typing import Any, Dict, List, Set, Tuple -import requests # type: ignore - from workflow.exception.e import CustomException from workflow.exception.errors.code_convert import CodeConvert from workflow.exception.errors.err_code import CodeEnum @@ -263,6 +261,9 @@ class Tool: ) # Execute HTTP request to Link system + + import requests # type: ignore + try: from aiohttp import ClientSession @@ -371,6 +372,9 @@ class Link: "versions": [self.version], "app_id": self.app_id, } + + import requests # type: ignore + response_json = requests.get( self.get_url, headers=self.const_headers, params=params ).json() diff --git a/core/workflow/extensions/fastapi/middleware/auth.py b/core/workflow/extensions/fastapi/middleware/auth.py index df45385890d5a34250067a9cc2c92a746d841943..92493a8dc670de34e208ec6412b87c3cb25ecb2d 100644 --- a/core/workflow/extensions/fastapi/middleware/auth.py +++ b/core/workflow/extensions/fastapi/middleware/auth.py @@ -2,7 +2,6 @@ import json import os from typing import Any -import requests # type: ignore from common.utils.hmac_auth import HMACAuth from fastapi import Request from starlette.middleware.base import BaseHTTPMiddleware @@ -134,6 +133,9 @@ class AuthMiddleware(BaseHTTPMiddleware): if app_id: return app_id url = f"{url}/{api_key}" + + import requests # type: ignore + resp = requests.get(url, headers=self._gen_app_auth_header(url)) span.add_info_event(f"Application management platform response: {resp.text}") if resp.status_code != 200: diff --git a/core/workflow/extensions/middleware/kafka/manager.py b/core/workflow/extensions/middleware/kafka/manager.py index 0d70a70f11bfa4d1f41876bd88767022100c9978..ad67d0704ffd332ee91645540aea92cb502f4f19 100644 --- a/core/workflow/extensions/middleware/kafka/manager.py +++ b/core/workflow/extensions/middleware/kafka/manager.py @@ -23,7 +23,21 @@ class KafkaProducerService(Service): :param config: Dictionary containing Kafka producer configuration parameters """ self.config = config - self.producer = Producer(**config) + if int(os.getenv("KAFKA_ENABLE", 0)) == 0: + logger.info("❌ Kafka is disabled") + else: + self.producer = Producer(**config) + self._check_kafka_connection() + + def _check_kafka_connection(self) -> None: + """ + Check if the Kafka connection is established. + """ + try: + self.producer.list_topics(timeout=10) + except Exception as e: + logger.error(f"Kafka connection check failed: {e}") + raise e def send( self, @@ -41,6 +55,10 @@ class KafkaProducerService(Service): :param timeout: Poll timeout in seconds for message delivery :raises Exception: If message sending fails """ + + if int(os.getenv("KAFKA_ENABLE", 0)) == 0: + return + # Use default delivery report callback if none provided if not callback: callback = self._delivery_report diff --git a/core/workflow/extensions/middleware/oss/manager.py b/core/workflow/extensions/middleware/oss/manager.py index 85b1229aeb7720162c9a3d9aeecc00613ca83d57..ac7602479625eb74259e7a47281065d53825e227 100644 --- a/core/workflow/extensions/middleware/oss/manager.py +++ b/core/workflow/extensions/middleware/oss/manager.py @@ -10,7 +10,6 @@ from typing import Optional from urllib.parse import urlencode import boto3 # type: ignore -import requests # type: ignore from botocore.exceptions import ClientError from common.utils.hmac_auth import HMACAuth from loguru import logger @@ -187,6 +186,9 @@ class IFlyGatewayStorageClient(BaseOSSService, Service): headers["X-TTL"] = str(self.ttl) headers["Content-Length"] = str(len(file_bytes)) try: + + import requests # type: ignore + resp = requests.post(url, headers=headers, data=file_bytes) except Exception as e: logger.error(e) diff --git a/core/workflow/infra/providers/llm/openai/openai_chat_llm.py b/core/workflow/infra/providers/llm/openai/openai_chat_llm.py index 67977fc3b6d44275e1799b56ecf38388885dc8d8..82b7283fcee0efbe2204ae2d79b07e707b1c8fb7 100644 --- a/core/workflow/infra/providers/llm/openai/openai_chat_llm.py +++ b/core/workflow/infra/providers/llm/openai/openai_chat_llm.py @@ -9,8 +9,6 @@ import asyncio import json from typing import Any, AsyncIterator, Dict, Tuple -from openai import AsyncOpenAI # type: ignore - from workflow.consts.engine.chat_status import ChatStatus from workflow.engine.nodes.entities.llm_response import LLMResponse from workflow.exception.e import CustomException @@ -110,6 +108,8 @@ class OpenAIChatAI(ChatAI): :raises CustomException: If request times out or fails """ # Initialize OpenAI async client + from openai import AsyncOpenAI # type: ignore + aclient = AsyncOpenAI( api_key=self.api_key, base_url=url, diff --git a/core/workflow/main.py b/core/workflow/main.py index 7978ef91221efdc631ae65978b052d62e7eefaf6..d2ec1f32f3862639ee62d7d79fb711188fff1208 100644 --- a/core/workflow/main.py +++ b/core/workflow/main.py @@ -10,10 +10,8 @@ import json import multiprocessing import os import sys -from pathlib import Path import uvicorn -from dotenv import load_dotenv from fastapi import FastAPI from fastapi.exceptions import RequestValidationError from fastapi.routing import APIRoute @@ -22,7 +20,6 @@ from starlette.middleware.cors import CORSMiddleware from workflow.api.v1.router import old_auth_router, sparkflow_router, workflow_router from workflow.cache.event_registry import EventRegistry -from workflow.consts.runtime_env import RuntimeEnv from workflow.extensions.fastapi.handler.validation import validation_exception_handler from workflow.extensions.fastapi.middleware.auth import AuthMiddleware from workflow.extensions.fastapi.middleware.otlp import OtlpMiddleware @@ -134,36 +131,6 @@ def create_app() -> FastAPI: return app -def set_env() -> None: - """ - Set environment variables by loading configuration from environment files. - - This function determines the appropriate configuration file based on the - runtime environment (local vs production) and loads the environment - variables from the corresponding .env file. - - :raises ValueError: If no configuration file is found - :raises Exception: Re-raises any other exceptions that occur during loading - """ - # Determine the runtime environment (defaults to Local) - running_env = os.getenv("RUNTIME_ENV", "") - - # Select the appropriate configuration file based on environment - if running_env == RuntimeEnv.Local.value: - env_file = Path(__file__).parent.parent / "workflow/config.local.env" - else: - env_file = Path(__file__).parent.parent / "workflow/config.env" - - logger.debug(f"🔍 Loading config.env file: {env_file}") - - # Load environment variables from the configuration file - if os.path.exists(env_file): - load_dotenv(env_file, override=False) - logger.debug("✅ Using config.env file.") - else: - raise ValueError("❌ No config.env file found.") - - def _get_worker_count() -> int: """ Get the number of workers to use for the application. @@ -190,7 +157,7 @@ if __name__ == "__main__": port=int(os.getenv("SERVICE_PORT", "7880")), # Default port 7880 workers=_get_worker_count(), reload=( - bool(os.getenv("RELOAD", "False")) + os.getenv("RELOAD", "false").lower() == "true" ), # Enable auto-reload for development log_level=os.getenv( "LOG_LEVEL", "error" diff --git a/core/workflow/service/app_service.py b/core/workflow/service/app_service.py index 7caf1d83673a65ceb608b4a444585f967e028b98..56bfab613a45eb727fe1fb8e9719c42af31de991 100644 --- a/core/workflow/service/app_service.py +++ b/core/workflow/service/app_service.py @@ -1,7 +1,6 @@ import json import os -import requests # type: ignore from common.utils.hmac_auth import HMACAuth from sqlmodel import Session # type: ignore @@ -50,6 +49,9 @@ def get_app_source_id(app_id: str, span: Span) -> str: url = f"{os.getenv('APP_MANAGE_PLAT_BASE_URL')}/v2/app/list" # Make authenticated request to get application list + + import requests # type: ignore + resp = requests.get( url, headers=_gen_app_auth_header(url), params={"app_ids": app_id} ) @@ -92,6 +94,9 @@ def get_app_source_detail(app_id: str, span: Span) -> tuple[str, str, str, str]: url = f"{os.getenv('APP_MANAGE_PLAT_BASE_URL')}/v2/app/details" # Make authenticated request to get application details + + import requests # type: ignore + resp = requests.get( url, headers=_gen_app_auth_header(url), params={"app_ids": app_id} ) diff --git a/core/workflow/service/chat_service.py b/core/workflow/service/chat_service.py index ca60e0937b0ac11d00b4f02081b776a8af6d3903..7b05368ef3e4397747fa1b38d6a28a3af3fea2a4 100644 --- a/core/workflow/service/chat_service.py +++ b/core/workflow/service/chat_service.py @@ -4,22 +4,10 @@ import json import time from asyncio import Queue from datetime import datetime -from typing import ( - Any, - AsyncGenerator, - AsyncIterator, - Awaitable, - Callable, - Dict, - List, - Optional, - Tuple, - cast, -) +from typing import Any, AsyncGenerator, AsyncIterator, Dict, List, Optional, Tuple, cast from loguru import logger -from workflow.cache.engine import get_engine, set_engine from workflow.cache.event_registry import Event, EventRegistry from workflow.consts.app_audit import AppAuditPolicy from workflow.consts.engine.chat_status import ChatStatus @@ -38,7 +26,6 @@ from workflow.engine.callbacks.openai_types_sse import ( WorkflowStep, ) from workflow.engine.dsl_engine import WorkflowEngine, WorkflowEngineFactory -from workflow.engine.entities.file import File from workflow.engine.entities.msg_or_end_dep_info import MsgOrEndDepInfo from workflow.engine.entities.node_entities import NodeType from workflow.engine.entities.variable_pool import ParamKey, VariablePool @@ -176,6 +163,8 @@ async def _get_or_build_workflow_engine( need_rebuild = True # Attempt to retrieve engine from cache + from workflow.cache.engine import get_engine, set_engine + sparkflow_engine_cache_obj = get_engine( is_release, chat_vo.flow_id, chat_vo.version, app_alias_id ) @@ -311,6 +300,8 @@ async def _validate_file_inputs( :raises CustomException: When file validation fails or required parameters are missing """ + from workflow.engine.entities.file import File + file_info_list, has_file = File.has_file_in_dsl(workflow_dsl, span_context) if not has_file: return @@ -533,6 +524,9 @@ async def _run( structured_data: dict[Any, Any] = {} support_stream_node_id_queue: asyncio.Queue[Any] = asyncio.Queue() + sparkflow_engine.engine_ctx.variable_pool.system_params.set( + ParamKey.FlowId, chat_vo.flow_id + ) # Initialize model content output queues await _init_stream_q( sparkflow_engine.engine_ctx.msg_or_end_node_deps, @@ -687,20 +681,6 @@ def change_dsl_triplets( return dsl -async def _get_response_or_ping( - sid: str, - node_info: NodeInfo, - getter: Callable[[], Awaitable[LLMGenerate]], - timeout: float = 30.0, -) -> LLMGenerate: - response: LLMGenerate - try: - response = await asyncio.wait_for(getter(), timeout=timeout) - except asyncio.TimeoutError: - response = LLMGenerate._ping(sid=sid, node_info=node_info) - return response - - async def _get_response( app_audit_policy: AppAuditPolicy, audit_strategy: Optional[AuditStrategy], @@ -724,21 +704,22 @@ async def _get_response( last_response.workflow_step if last_response else None ) node: Optional[NodeInfo] = step.node if step else None - if last_response and node and node.id.startswith(NodeType.RPA.value): - response = await _get_response_or_ping( - sid=last_response.id, node_info=node, getter=lambda: response_queue.get() - ) - elif app_audit_policy == AppAuditPolicy.AGENT_PLATFORM and audit_strategy: - frame_audit_result: FrameAuditResult = await asyncio.wait_for( - audit_strategy.context.output_queue.get(), - timeout=QueueTimeout.AsyncQT.value, - ) - if frame_audit_result.error: - raise frame_audit_result.error - response = cast(LLMGenerate, frame_audit_result.source_frame) - else: - response = await asyncio.wait_for( - response_queue.get(), timeout=QueueTimeout.AsyncQT.value + try: + if app_audit_policy == AppAuditPolicy.AGENT_PLATFORM and audit_strategy: + frame_audit_result: FrameAuditResult = await asyncio.wait_for( + audit_strategy.context.output_queue.get(), + timeout=QueueTimeout.PingQT.value, + ) + if frame_audit_result.error: + raise frame_audit_result.error + response = cast(LLMGenerate, frame_audit_result.source_frame) + else: + response = await asyncio.wait_for( + response_queue.get(), timeout=QueueTimeout.PingQT.value + ) + except asyncio.TimeoutError: + response = LLMGenerate._ping( + sid=last_response.id if last_response else "", node_info=node ) return response @@ -952,11 +933,7 @@ async def _chat_response_stream( node: Optional[NodeInfo] = ( response.workflow_step.node if response.workflow_step else None ) - last_response = ( - response - if node and node.id.startswith(NodeType.RPA.value) - else last_response - ) + last_response = response if node else last_response response = _filter_response_frame( response_frame=response, @@ -1087,7 +1064,7 @@ async def _forward_queue_messages( node: Optional[NodeInfo] = ( response.workflow_step.node if response.workflow_step else None ) - if node and node.id.startswith(NodeType.RPA.value): + if node: last_response = response event = EventRegistry().get_event(event_id=event_id) data = json.dumps(response.dict(), ensure_ascii=False) diff --git a/core/workflow/service/flow_service.py b/core/workflow/service/flow_service.py index 887801f491e132b8c87639f5014db54bf2da47e8..8055befcaaa372d76a1227fe3aff11e27be6098d 100644 --- a/core/workflow/service/flow_service.py +++ b/core/workflow/service/flow_service.py @@ -57,7 +57,6 @@ def save(flow: Flow, app_info: App, session: Session, span: Span) -> Flow: name=flow.name, data=flow.data, description=flow.description, - status=flow.status, app_id=flow.app_id, source=app_info.actual_source, version="-1", # Initial version for new flows @@ -95,11 +94,6 @@ def update( db_flow.app_id = flow.app_id if flow.data: db_flow.data = flow.data - if flow.status: - db_flow.status = flow.status - # Set release data when status is published (status > 0) - if flow.status > 0: - db_flow.release_data = db_flow.data session.add(db_flow) session.commit() @@ -252,7 +246,9 @@ def gen_mcp_input_schema(flow: Flow) -> dict: } -async def node_debug(workflow_dsl: WorkflowDSL, span: Span) -> NodeDebugRespVo: +async def node_debug( + workflow_dsl: WorkflowDSL, flow_id: str, span: Span +) -> NodeDebugRespVo: """ Execute node debugging for a single workflow node. @@ -278,6 +274,8 @@ async def node_debug(workflow_dsl: WorkflowDSL, span: Span) -> NodeDebugRespVo: # Disable retry mechanism for node debugging to get immediate feedback node_instance.retry_config.should_retry = False + variable_pool.system_params.set(ParamKey.FlowId, flow_id) + if node_instance.node_id.startswith(NodeType.FLOW.value): set_flow_node_output_mode( variable_pool=variable_pool, node_instance=node_instance, span=span diff --git a/core/workflow/service/publish_service.py b/core/workflow/service/publish_service.py index f077b08f6ea979e6352565319f5a7c4f45b5e163..8affa151aa202e6a78d56c1efe34230b0ea17c98 100644 --- a/core/workflow/service/publish_service.py +++ b/core/workflow/service/publish_service.py @@ -266,7 +266,6 @@ def _handle_version( release_data=db_flow.release_data, description=db_flow.description, version=publish_input.version, - status=db_flow.status, release_status=db_flow.release_status, app_id=db_flow.app_id, source=db_flow.source, diff --git a/docker/astronAgent/.env.example b/docker/astronAgent/.env.example index 5ca4236a0360bc568f7f873c7866bb1d8c09dbd1..d82943c00200907ffd96dc0da15c5996a09e899c 100644 --- a/docker/astronAgent/.env.example +++ b/docker/astronAgent/.env.example @@ -1,6 +1,13 @@ # Docker Compose environment variable configuration example # Copy this file to .env and modify the configuration as needed +# ============================================================================ +# Image Version Configuration +# ============================================================================ + +# astron-agent image version tag (default: latest) +ASTRON_AGENT_VERSION=latest + # ============================================================================ # Middleware Configuration # ============================================================================ @@ -37,6 +44,7 @@ ELASTICSEARCH_SECURITY_ENABLED=false ES_JAVA_OPTS='-Xms512m -Xmx512m' # Kafka Configuration +KAFKA_ENABLE=0 KAFKA_REPLICATION_FACTOR=1 KAFKA_CLUSTER_ID=MkU3OEVBNTcwNTJENDM2Qk KAFKA_TIMEOUT=60 @@ -80,6 +88,9 @@ HOST_BASE_ADDRESS=http://localhost # astron-agent Application Port Configuration # ============================================================================ +# Core Service Port Configuration +CASDOOR_PORT=8000 + # Core Service Port Configuration CORE_TENANT_PORT=5052 CORE_DATABASE_PORT=7990 @@ -94,7 +105,7 @@ CORE_WORKFLOW_PORT=7880 # These variables are prioritized over VITE_CASDOOR_* equivalents in frontend builds # Note: The CONSOLE_DOMAIN variable is used to dynamically set the Casdoor redirectUris # The entrypoint.sh script in casdoor container will replace redirectUris with ${CONSOLE_DOMAIN}/callback -CONSOLE_CASDOOR_URL=${HOST_BASE_ADDRESS}:8000 +CONSOLE_CASDOOR_URL=${HOST_BASE_ADDRESS}:${CASDOOR_PORT} CONSOLE_CASDOOR_ID=astron-agent-client CONSOLE_CASDOOR_APP=astron-agent-app CONSOLE_CASDOOR_ORG=built-in @@ -192,7 +203,7 @@ REDIS_DATABASE_CONSOLE=1 # OAuth2 Configuration for Console Backend Api Server (as OAuth2 Resource Server) OAUTH2_ISSUER_URI=${CONSOLE_CASDOOR_URL:-http://auth-server:8000} -OAUTH2_JWK_SET_URI=${CONSOLE_CASDOOR_URL:-http://auth-server:8000}/.well-known/jwks +OAUTH2_JWK_SET_URI=http://casdoor:8000/.well-known/jwks OAUTH2_AUDIENCE=${CONSOLE_CASDOOR_ID:-your-oauth2-client-id} # Open Platform API Configuration @@ -247,6 +258,7 @@ ADMIN_UID=9999 APP_URL=http://core-tenant:${CORE_TENANT_PORT:-5052}/v2/app KNOWLEDGE_URL=http://core-knowledge:${CORE_KNOWLEDGE_PORT:-20010}/knowledge TOOL_URL=http://core-link:18888 +TOOL_RPA_URL=http://core-rpa:17198 WORKFLOW_URL=http://core-workflow:${CORE_WORKFLOW_PORT:-7880} SPARK_DB_URL=http://core-database:${CORE_DATABASE_PORT:-7990} # Local model service address: The model service is open source, @@ -290,6 +302,4 @@ HEALTH_CHECK_INTERVAL=30s HEALTH_CHECK_TIMEOUT=10s HEALTH_CHECK_RETRIES=60 -# Network configuration -NETWORK_SUBNET=172.20.0.0/16 diff --git a/docker/astronAgent/astronRPA/.env.example b/docker/astronAgent/astronRPA/.env.example new file mode 100644 index 0000000000000000000000000000000000000000..f18a37ddbbfc74694bd454a731a7a34d4b843802 --- /dev/null +++ b/docker/astronAgent/astronRPA/.env.example @@ -0,0 +1,47 @@ +# AI-Service +LOG_LEVEL="INFO" +LOG_DIR="/app/log" + +MONTHLY_GRANT_AMOUNT=100000 +AICHAT_POINTS_COST=100 +OCR_GENERAL_POINTS_COST=50 +JFBYM_POINTS_COST=10 + +AICHAT_BASE_URL="" +AICHAT_API_KEY="" + +XFYUN_APP_ID="" +XFYUN_API_SECRET="" +XFYUN_API_KEY="" + +JFBYM_ENDPOINT="" +JFBYM_API_TOKEN="" + +# Mysql +DATABASE_USERNAME="root" +DATABASE_PASSWORD="rpa123456" +DATABASE_HOST="rpa-mysql" +DATABASE_PORT=3306 +DATABASE_NAME="rpa" +ATLAS_URL="" + +# Redis +REDIS_HOST="rpa-redis" +REDIS_PORT=6379 +REDIS_DB=0 +REDIS_PASSWORD="" + +# Minio +MINIO_URL="http://rpa-minio:9000" +MINIO_BUCKET="rpa-resource" +MINIO_AK="rpaminioadmin" +MINIO_SK="rpaminioadmin123" + +# Casdoor +CASDOOR_ENDPOINT="http://astron-agent-casdoor:8000" +CASDOOR_CLIENT_ID="e3ba6fec42cfe996121f" +CASDOOR_CLIENT-SECRET="0c18bf2a11ffbb756ec6ce47dae9e09bdd48e3dd" +CASDOOR_ORGANIZATION_NAME="example-org" +CASDOOR_APPLICATION_NAME="example-app" +CASDOOR_REDIRECT_URL="https://tauri.localhost/" +CASDOOR_EXTERNAL_ENDPOINT="http://172.29.231.250:8000" \ No newline at end of file diff --git a/docker/astronAgent/astronRPA/docker-compose.yml b/docker/astronAgent/astronRPA/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..96bad9b7e9fa07916a94121b7c9a3f1b286a3fbe --- /dev/null +++ b/docker/astronAgent/astronRPA/docker-compose.yml @@ -0,0 +1,293 @@ +name: rpa-opensource-studio +x-env-file: &env_file + - .env + +services: + rpa-mysql: + image: mysql:8.4.6 + container_name: rpa-opensource-mysql + restart: always + environment: + MYSQL_ROOT_PASSWORD: ${DATABASE_PASSWORD} + MYSQL_DATABASE: ${DATABASE_NAME} + env_file: *env_file + # ports: + # - "${DATABASE_PORT}:3306" + volumes: + - ./volumes/mysql/my.cnf:/etc/mysql/conf.d/my.cnf + # - ./data/mysql:/var/lib/mysql + - ./volumes/mysql/schema.sql:/docker-entrypoint-initdb.d/01-schema.sql + - ./volumes/mysql/init_app_market_dict_data.sql:/docker-entrypoint-initdb.d/02-init_data.sql + - ./volumes/mysql/init_c_atom_meta_data.sql:/docker-entrypoint-initdb.d/03-init_data.sql + - ./volumes/mysql/init_his_data_enum_data.sql:/docker-entrypoint-initdb.d/04-init_data.sql + healthcheck: + test: + [ + 'CMD', + 'mysqladmin', + 'ping', + '-h', + 'localhost', + '-u${DATABASE_USERNAME}', + '-p${DATABASE_PASSWORD}', + ] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + networks: + - astron-agent-network + + rpa-redis: + image: bitnami/redis:latest + container_name: rpa-opensource-redis + restart: always + user: root + privileged: true + env_file: *env_file + environment: + - REDIS_AOF_ENABLED=no + - REDIS_PORT_NUMBER=${REDIS_PORT} + - REDIS_IO_THREADS=4 + - ALLOW_EMPTY_PASSWORD=yes + # ports: + # - "${REDIS_PORT}:6379" + volumes: + - ./data/bitnami/redis:/bitnami/redis/data:rw,Z + command: > + bash -c " + /opt/bitnami/scripts/redis/setup.sh + # Set proper permissions for data directories + chown -R redis:redis /bitnami/redis/data + chmod g+s /bitnami/redis/data + + exec /opt/bitnami/scripts/redis/entrypoint.sh /opt/bitnami/scripts/redis/run.sh + " + healthcheck: + test: ['CMD', 'redis-cli', 'ping'] + interval: 5s + timeout: 10s + retries: 10 + start_period: 10s + networks: + - astron-agent-network + + rpa-minio: + image: minio/minio:RELEASE.2025-06-13T11-33-47Z-cpuv1 + container_name: rpa-opensource-minio + user: root + privileged: true + restart: always + env_file: *env_file + # ports: + # - "9000:9000" + # - "9001:9001" + volumes: + - ./data/minio:/data + environment: + MINIO_ROOT_USER: ${MINIO_AK} + MINIO_ROOT_PASSWORD: ${MINIO_SK} + MINIO_DEFAULT_BUCKETS: ${MINIO_BUCKET} + entrypoint: + - /bin/sh + - -c + - | + # Run initialization in background + ( + # Wait for MinIO to be ready + until (/usr/bin/mc alias set localminio http://localhost:9000 ${MINIO_AK} ${MINIO_SK}) do + echo "Waiting for MinIO to be ready..." + sleep 1 + done + + # Create bucket + /usr/bin/mc mb --ignore-existing localminio/${MINIO_BUCKET} + + echo "MinIO initialization complete." + ) & + + # Start minio server in foreground + exec minio server /data --console-address ":9001" + healthcheck: + test: + [ + 'CMD-SHELL', + '/usr/bin/mc alias set health_check http://localhost:9000 ${MINIO_AK} ${MINIO_SK} && /usr/bin/mc ready health_check', + ] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s + networks: + - astron-agent-network + + openresty-nginx: + image: openresty/openresty:1.27.1.1-alpine + container_name: rpa-opensource-openresty-nginx + restart: always + ports: + - "32742:80" + volumes: + - ./volumes/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro + - ./volumes/nginx/lua:/usr/local/openresty/nginx/lua:ro + - ./logs/nginx:/usr/local/openresty/nginx/logs + depends_on: + - resource-service + - robot-service + - ai-service + - openapi-service + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + networks: + - astron-agent-network + + # casdoor service is disabled in integrated mode + # Use astronAgent's shared casdoor instead + # casdoor: + # image: casbin/casdoor:v2.67.0 + # container_name: rpa-opensource-casdoor + # restart: always + # env_file: *env_file + # environment: + # - driverName=mysql + # - dataSourceName=${DATABASE_USERNAME}:${DATABASE_PASSWORD}@tcp(${DATABASE_HOST}:${DATABASE_PORT})/ + # ports: + # - "8000:8000" + # volumes: + # - ./volumes/casdoor/init_data_dump.json:/init_data.json + # depends_on: + # mysql: + # condition: service_healthy + # networks: + # - astron-agent-network + + mysql-init: + image: mysql:8.4.6 + container_name: rpa-opensource-mysql-init + depends_on: + rpa-mysql: + condition: service_healthy + resource-service: + condition: service_started + environment: + MYSQL_ROOT_PASSWORD: ${DATABASE_PASSWORD} + MYSQL_DATABASE: ${DATABASE_NAME} + env_file: *env_file + volumes: + - ./volumes/mysql/init_robot_example_data.sql:/init_robot_example_data.sql + command: > + sh -c " + echo 'Waiting for robot-service to be ready...' + sleep 10 + echo 'Executing robot example data initialization...' + mysql -h rpa-mysql -u root -p$$MYSQL_ROOT_PASSWORD --default-character-set=utf8mb4 --init-command='SET NAMES utf8mb4;' $$MYSQL_DATABASE < /init_robot_example_data.sql + echo 'Robot example data initialization completed!' + " + networks: + - astron-agent-network + + ai-service: + build: + context: .. + dockerfile: backend/ai-service/Dockerfile + container_name: rpa-opensource-ai-service + restart: always + env_file: *env_file + environment: + - DATABASE_URL=mysql+aiomysql://${DATABASE_USERNAME}:${DATABASE_PASSWORD}@rpa-mysql:3306/${DATABASE_NAME} + - REDIS_URL=redis://rpa-redis:6379/${REDIS_DB} + - AICHAT_BASE_URL=${AICHAT_BASE_URL} + - AICHAT_API_KEY=${AICHAT_API_KEY} + # ports: + # - "8010:8010" + volumes: + - ../backend/ai-service/app:/app/app + depends_on: + rpa-mysql: + condition: service_healthy + rpa-redis: + condition: service_healthy + casdoor: + condition: service_started + networks: + - astron-agent-network + + openapi-service: + build: + context: .. + dockerfile: backend/openapi-service/Dockerfile + container_name: rpa-opensource-openapi-service + restart: always + env_file: *env_file + environment: + - DATABASE_URL=mysql+aiomysql://${DATABASE_USERNAME}:${DATABASE_PASSWORD}@rpa-mysql:3306/${DATABASE_NAME} + - REDIS_URL=redis://rpa-redis:6379/${REDIS_DB} + - AICHAT_BASE_URL=${AICHAT_BASE_URL} + - AICHAT_API_KEY=${AICHAT_API_KEY} + # ports: + # - "8020:8020" + volumes: + - ../backend/openapi-service/app:/app/app + depends_on: + rpa-mysql: + condition: service_healthy + rpa-redis: + condition: service_healthy + casdoor: + condition: service_started + networks: + - astron-agent-network + + resource-service: + build: + context: .. + dockerfile: backend/resource-service/Dockerfile + container_name: rpa-opensource-resource-service + restart: always + env_file: *env_file + # ports: + # - "8030:8030" + volumes: + - ./logs/resource-service:/app/logs + depends_on: + rpa-mysql: + condition: service_healthy + rpa-redis: + condition: service_healthy + rpa-minio: + condition: service_healthy + casdoor: + condition: service_started + networks: + - astron-agent-network + + robot-service: + build: + context: .. + dockerfile: backend/robot-service/Dockerfile + container_name: rpa-opensource-robot-service + restart: always + env_file: *env_file + # ports: + # - "8040:8040" + volumes: + - ./logs/robot-service:/app/logs + depends_on: + rpa-mysql: + condition: service_healthy + rpa-redis: + condition: service_healthy + casdoor: + condition: service_started + networks: + - astron-agent-network + +networks: + astron-agent-network: + # In integrated mode (via include), this network is created by docker-compose-with-auth.yaml + # Docker Compose will automatically use the same network without needing 'external: true' + name: astron-agent-network diff --git a/docker/astronAgent/astronRPA/volumes/mysql/init_app_market_dict_data.sql b/docker/astronAgent/astronRPA/volumes/mysql/init_app_market_dict_data.sql new file mode 100644 index 0000000000000000000000000000000000000000..09e5a5634da2352bad99f984837f5403eaf33fcf --- /dev/null +++ b/docker/astronAgent/astronRPA/volumes/mysql/init_app_market_dict_data.sql @@ -0,0 +1,37 @@ +INSERT INTO rpa.app_market_dict (business_code,name,dict_code,dict_value,user_type,description,seq,creator_id,create_time,updater_id,update_time,deleted) VALUES + ('marketRoleFunc','编辑市场','market_team_edit','T','owner',NULL,NULL,'73','2025-05-19 17:33:11','73','2025-05-19 17:33:11',0), + ('marketRoleFunc','编辑市场','market_team_edit','F','admin',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','编辑市场','market_team_edit','F','acquirer',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','编辑市场','market_team_edit','F','author',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','解散市场','market_team_dissolve','T','owner',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','解散市场','market_team_dissolve','F','admin',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','解散市场','market_team_dissolve','F','acquirer',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','解散市场','market_team_dissolve','F','author',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','离开市场','market_team_leave','T','owner',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','离开市场','market_team_leave','T','admin',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','离开市场','market_team_leave','T','acquirer',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','离开市场','market_team_leave','T','author',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','删除应用','market_resource_delete','T','owner',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','删除应用','market_resource_delete','T','admin',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','删除应用','market_resource_delete','F','acquirer',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','删除应用','market_resource_delete','T','author',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','更新到市场','market_resource_upgrade_to_market','T','owner',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','更新到市场','market_resource_upgrade_to_market','T','admin',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','更新到市场','market_resource_upgrade_to_market','F','acquirer',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','更新到市场','market_resource_upgrade_to_market','T','author',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','邀请成员-查询员工','market_user_get_user','T','owner',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','邀请成员-查询员工','market_user_get_user','T','admin',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','邀请成员-查询员工','market_user_get_user','F','acquirer',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','邀请成员-查询员工','market_user_get_user','F','author',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','邀请成员','market_user_invite','T','owner',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','邀请成员','market_user_invite','T','admin',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','邀请成员','market_user_invite','F','acquirer',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','邀请成员','market_user_invite','F','author',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','移出成员','market_user_delete','T','owner',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','移出成员','market_user_delete','T','admin',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','移出成员','market_user_delete','F','acquirer',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','移出成员','market_user_delete','F','author',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','设置角色','market_user_role','T','owner',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','设置角色','market_user_role','T','admin',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','设置角色','market_user_role','F','acquirer',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0), + ('marketRoleFunc','设置角色','market_user_role','F','author',NULL,NULL,'73','2024-03-25 10:27:56','73','2024-03-25 10:27:56',0); \ No newline at end of file diff --git a/docker/astronAgent/astronRPA/volumes/mysql/init_c_atom_meta_data.sql b/docker/astronAgent/astronRPA/volumes/mysql/init_c_atom_meta_data.sql new file mode 100644 index 0000000000000000000000000000000000000000..269c3500d2be1120a0bac0eae65e4a95d1033666 --- /dev/null +++ b/docker/astronAgent/astronRPA/volumes/mysql/init_c_atom_meta_data.sql @@ -0,0 +1 @@ +INSERT INTO `c_atom_meta` VALUES (14,'root','atomCommon','{\"atomicTree\":[{\"key\":\"ai\",\"title\":\"AI\",\"atomics\":[{\"key\":\"aim\",\"title\":\"大模型\",\"atomics\":[{\"key\":\"ChatAI.chat\",\"title\":\"多轮会话\",\"icon\":\"multi-chat\"},{\"key\":\"ChatAI.single_turn_chat\",\"title\":\"单轮会话\",\"icon\":\"single-chat\"},{\"key\":\"ChatAI.knowledge_chat\",\"title\":\"知识问答\",\"icon\":\"knowledge-qa\"},{\"key\":\"DocumentAI.theme_expand\",\"title\":\"主题扩写\",\"icon\":\"topic-expand\"},{\"key\":\"DocumentAI.sentence_expand\",\"title\":\"段落扩写\",\"icon\":\"paragraph-expand\"},{\"key\":\"DocumentAI.sentence_reduce\",\"title\":\"段落缩写\",\"icon\":\"paragraph-abbreviate\"},{\"key\":\"RecruitAI.rating_resume\",\"title\":\"简历评分\",\"icon\":\"resume-scoring\"},{\"key\":\"RecruitAI.generate_keywords\",\"title\":\"职位关键词生成\",\"icon\":\"job-keyword-generation\"},{\"key\":\"ContractAI.get_factors\",\"title\":\"合同要素提取\",\"icon\":\"contract-element-extraction\"},{\"key\":\"Agent.call_dify\",\"title\":\"调用Dify流程\",\"icon\":\"call-dify-workflow\"},{\"key\":\"Agent.call_xcagent\",\"title\":\"调用星辰Agent流程\",\"icon\":\"call-dify-workflow\"}]},{\"key\":\"ocr\",\"title\":\"OCR\",\"atomics\":[{\"key\":\"OpenApi.business_license\",\"title\":\"营业执照识别\",\"icon\":\"business-license-recognition\"},{\"key\":\"OpenApi.id_card\",\"title\":\"身份证识别\",\"icon\":\"id-card-recognition\"},{\"key\":\"OpenApi.vat_invoice\",\"title\":\"增值税发票识别\",\"icon\":\"vat-invoice-recognition\"},{\"key\":\"OpenApi.train_ticket\",\"title\":\"火车票识别\",\"icon\":\"train-ticket-recognition\"},{\"key\":\"OpenApi.taxi_ticket\",\"title\":\"出租车发票识别\",\"icon\":\"taxi-invoice-recognition\"},{\"key\":\"OpenApi.common_ocr\",\"title\":\"通用文字识别\",\"icon\":\"general-text-recognition\"}]},{\"key\":\"verify\",\"title\":\"验证码\",\"atomics\":[{\"key\":\"VerifyCode.picture_code\",\"title\":\"通用数英验证码\",\"icon\":\"captcha-text\"},{\"key\":\"VerifyCode.slider_code\",\"title\":\"通用滑块验证码\",\"icon\":\"captcha-slider\"},{\"key\":\"VerifyCode.click_code\",\"title\":\"通用点击验证码\",\"icon\":\"captcha-click\"}]}]},{\"key\":\"process\",\"title\":\"流程\",\"atomics\":[{\"key\":\"Code.Process\",\"title\":\"运行子流程\",\"icon\":\"run-sub-process\"},{\"key\":\"Script.module\",\"title\":\"运行Python模块\",\"icon\":\"run-python-module\"}]},{\"key\":\"code\",\"title\":\"代码流程\",\"atomics\":[{\"key\":\"DataProcess.set_variable_value\",\"title\":\"设置变量值\",\"icon\":\"set-variable-value\"},{\"key\":\"Report.print\",\"title\":\"日志打印\",\"icon\":\"log-print\"},{\"key\":\"if\",\"title\":\"条件判断\",\"atomics\":[{\"key\":\"Code.If\",\"title\":\"IF条件\",\"icon\":\"if-condition\"},{\"key\":\"CV.is_image_exist\",\"title\":\"IF图像存在\",\"icon\":\"if-image-exists\"},{\"key\":\"Folder.folder_exist\",\"title\":\"IF文件夹存在\",\"icon\":\"check-folder-exists\"},{\"key\":\"File.file_exist\",\"title\":\"IF文件存在\",\"icon\":\"check-file-exists\"},{\"key\":\"Window.exist\",\"title\":\"IF窗口存在\",\"icon\":\"check-window-exists\"},{\"key\":\"Code.ElseIf\",\"title\":\"ELSE IF条件\",\"icon\":\"else-if-condition\"},{\"key\":\"Code.Else\",\"title\":\"ELSE条件\",\"icon\":\"else-condition\"}]},{\"key\":\"for\",\"title\":\"循环\",\"atomics\":[{\"key\":\"Code.ForDict\",\"title\":\"字典For循环\",\"icon\":\"dictionary-for-loop\"},{\"key\":\"Code.ForList\",\"title\":\"列表For循环\",\"icon\":\"list-for-loop\"},{\"key\":\"Code.ForStep\",\"title\":\"计数For循环\",\"icon\":\"count-for-loop\"},{\"key\":\"Excel.loop_excel_content\",\"title\":\"循环Excel内容\",\"icon\":\"excel-loop-content\"},{\"key\":\"BrowserElement.loop_similar\",\"title\":\"循环相似元素列表(web)\",\"icon\":\"loop-similar-elements-web\"},{\"key\":\"Code.While\",\"title\":\"While循环\",\"icon\":\"while-loop\"},{\"key\":\"Code.Break\",\"title\":\"退出循环(Break)\",\"icon\":\"break-loop\"},{\"key\":\"Code.Continue\",\"title\":\"继续下次循环(Continue)\",\"icon\":\"continue-next-loop\"}]},{\"key\":\"error\",\"title\":\"错误处理\",\"atomics\":[{\"key\":\"Code.Try\",\"title\":\"捕获异常(Try)\",\"icon\":\"try-exception\"},{\"key\":\"Code.Finally\",\"title\":\"捕获异常(Finally)\",\"icon\":\"finally-exception\"}]}]},{\"key\":\"web\",\"title\":\"网页自动化\",\"atomics\":[{\"key\":\"BrowserSoftware.browser_open\",\"title\":\"打开浏览器\",\"icon\":\"open-browser\"},{\"key\":\"BrowserSoftware.browser_close\",\"title\":\"关闭浏览器\",\"icon\":\"close-browser\"},{\"key\":\"BrowserSoftware.get_current_obj\",\"title\":\"获取已打开的浏览器对象\",\"icon\":\"get-open-browser-objects\"},{\"key\":\"BrowserElement.element_exist\",\"title\":\"元素是否存在(web)\",\"icon\":\"wait-element-web\"},{\"key\":\"BrowserElement.wait_element\",\"title\":\"等待元素(web)\",\"icon\":\"wait-element-web\"},{\"key\":\"BrowserElement.element_operation\",\"title\":\"元素操作(web)\",\"icon\":\"element-operation-web\"},{\"key\":\"BrowserElement.click\",\"title\":\"点击元素(web)\",\"icon\":\"click-element-web\"},{\"key\":\"BrowserElement.element_text\",\"title\":\"获取元素文本内容(web)\",\"icon\":\"get-element-text-web\"},{\"key\":\"BrowserElement.input\",\"title\":\"填写输入框(web)\",\"icon\":\"fill-input-web\"},{\"key\":\"BrowserElement.get_checked\",\"title\":\"获取复选框(web)\",\"icon\":\"get-checkbox-web\"},{\"key\":\"BrowserElement.set_checked\",\"title\":\"操作复选框(web)\",\"icon\":\"operate-checkbox-web\"},{\"key\":\"BrowserElement.get_select\",\"title\":\"获取下拉框(web)\",\"icon\":\"get-dropdown-web\"},{\"key\":\"BrowserElement.set_select\",\"title\":\"操作下拉框(web)\",\"icon\":\"operate-dropdown-web\"},{\"key\":\"BrowserElement.slider_hover\",\"title\":\"拾取滑块拖拽(web)\",\"icon\":\"pick-slider-drag-web\"},{\"key\":\"BrowserElement.hover_over\",\"title\":\"鼠标悬停在元素上(web)\",\"icon\":\"mouse-hover-element-web\"},{\"key\":\"BrowserElement.screenshot\",\"title\":\"拾取元素截图(web)\",\"icon\":\"pick-element-screenshot-web\"},{\"key\":\"BrowserElement.position_screenshot\",\"title\":\"元素位置截图(web)\",\"icon\":\"element-position-screenshot-web\"},{\"key\":\"BrowserElement.scroll_into_view\",\"title\":\"元素置于可视区域(web)\",\"icon\":\"element-to-visible-web\"},{\"key\":\"BrowserElement.get_table\",\"title\":\"获取表格数据(web)\",\"icon\":\"get-table-data-web\"},{\"key\":\"BrowserElement.data_batch\",\"title\":\"数据抓取(web)\",\"icon\":\"data-scraping-web\"},{\"key\":\"BrowserElement.similar\",\"title\":\"获取相似元素列表(web)\",\"icon\":\"get-similar-elements-web\"},{\"key\":\"BrowserElement.loop_similar\",\"title\":\"循环相似元素列表(web)\",\"icon\":\"loop-similar-elements-web\"},{\"key\":\"BrowserElement.create_element\",\"title\":\"获取元素对象(web)\",\"icon\":\"get-element-object-web\"},{\"key\":\"BrowserElement.get_relative_element\",\"title\":\"获取关联元素(web)\",\"icon\":\"get-related-elements-web\"},{\"key\":\"web.cookie\",\"title\":\"Cookie\",\"atomics\":[{\"key\":\"BrowserSoftware.set_cookies\",\"title\":\"设置Cookie\",\"icon\":\"set-cookie\"},{\"key\":\"BrowserSoftware.get_cookies\",\"title\":\"获取Cookie\",\"icon\":\"get-cookie\"}]},{\"key\":\"web.page\",\"title\":\"网页操作\",\"atomics\":[{\"key\":\"BrowserSoftware.web_open\",\"title\":\"打开新网页\",\"icon\":\"open-new-webpage\"},{\"key\":\"BrowserSoftware.get_current_tab_id\",\"title\":\"获取当前标签页ID\",\"icon\":\"get-current-tab-id\"},{\"key\":\"BrowserSoftware.web_switch\",\"title\":\"切换到已存在标签页\",\"icon\":\"switch-existing-tab\"},{\"key\":\"BrowserSoftware.web_close\",\"title\":\"关闭网页\",\"icon\":\"close-webpage\"},{\"key\":\"BrowserSoftware.web_refresh\",\"title\":\"刷新当前网页\",\"icon\":\"refresh-current-page\"},{\"key\":\"BrowserSoftware.stop_web_load\",\"title\":\"停止加载网页\",\"icon\":\"stop-loading-page\"},{\"key\":\"BrowserSoftware.browser_forward\",\"title\":\"网页前进\",\"icon\":\"webpage-forward\"},{\"key\":\"BrowserSoftware.browser_back\",\"title\":\"网页后退\",\"icon\":\"webpage-backward\"},{\"key\":\"BrowserSoftware.screenshot\",\"title\":\"网页截图\",\"icon\":\"webpage-screenshot\"},{\"key\":\"BrowserElement.scroll\",\"title\":\"鼠标滚动网页\",\"icon\":\"mouse-scroll-webpage\"},{\"key\":\"BrowserSoftware.get_current_url\",\"title\":\"获取网页URL\",\"icon\":\"get-webpage-url\"},{\"key\":\"BrowserSoftware.get_current_title\",\"title\":\"获取网页标题\",\"icon\":\"get-webpage-title\"},{\"key\":\"BrowserSoftware.wait_web_load\",\"title\":\"等待页面加载完成\",\"icon\":\"wait-page-load\"}]},{\"key\":\"web.file\",\"title\":\"网页文件\",\"atomics\":[{\"key\":\"BrowserSoftware.download_web_file\",\"title\":\"文件下载(web)\",\"icon\":\"file-download-web\"},{\"key\":\"BrowserSoftware.upload_web_file\",\"title\":\"文件上传(web)\",\"icon\":\"file-upload-web\"}]}]},{\"key\":\"desktop\",\"title\":\"桌面自动化\",\"atomics\":[{\"key\":\"Software.close\",\"title\":\"关闭程序\",\"icon\":\"close-program\"},{\"key\":\"Software.open\",\"title\":\"打开程序\",\"icon\":\"open-program\"},{\"key\":\"WinEle.click_element\",\"title\":\"点击元素(桌面)\",\"icon\":\"click-element-win\"},{\"key\":\"WinEle.screenshot_element\",\"title\":\"元素截图(桌面)\",\"icon\":\"element-screenshot-win\"},{\"key\":\"WinEle.hover_element\",\"title\":\"鼠标悬停元素(桌面)\",\"icon\":\"mouse-hover-element-win\"},{\"key\":\"WinEle.input_text_element\",\"title\":\"填写输入框(桌面)\",\"icon\":\"fill-input-win\"},{\"key\":\"WinEle.get_element_text\",\"title\":\"获取元素文本(桌面)\",\"icon\":\"get-element-text-win\"},{\"key\":\"WinEle.similar\",\"title\":\"获取相似元素列表(桌面)\",\"icon\":\"get-similar-elements-win\"},{\"key\":\"desktop.window\",\"title\":\"窗口操作\",\"atomics\":[{\"key\":\"Window.exist\",\"title\":\"IF窗口存在\",\"icon\":\"check-window-exists\"},{\"key\":\"Window.top\",\"title\":\"置顶窗口\",\"icon\":\"pin-window\"},{\"key\":\"Window.close\",\"title\":\"关闭窗口\",\"icon\":\"close-window\"},{\"key\":\"Window.set_size\",\"title\":\"调整窗口大小\",\"icon\":\"resize-window\"}]}]},{\"key\":\"document\",\"title\":\"文档处理\",\"atomics\":[{\"key\":\"document.PDF\",\"title\":\"PDF\",\"atomics\":[{\"key\":\"PDF.get_pages_num\",\"title\":\"获取PDF文档页数\",\"icon\":\"pdf-get-page-count\"},{\"key\":\"PDF.get_pdf_text\",\"title\":\"提取PDF文档文本\",\"icon\":\"pdf-extract-text\"},{\"key\":\"PDF.merge_pdf_files\",\"title\":\"合并PDF文件\",\"icon\":\"merge-pdf-files\"},{\"key\":\"PDF.get_pdf_images\",\"title\":\"提取PDF文档图片\",\"icon\":\"pdf-extract-images\"},{\"key\":\"PDF.extract_pdf_file\",\"title\":\"抽取PDF指定页\",\"icon\":\"pdf-extract-page\"},{\"key\":\"PDF.extract_forms_from_pdf\",\"title\":\"提取PDF表格到Excel\",\"icon\":\"pdf-extract-table-to-excel\"},{\"key\":\"PDF.convert_pdf_to_img\",\"title\":\"PDF页面转图片\",\"icon\":\"pdf-page-to-image\"}]},{\"key\":\"document.Word\",\"title\":\"Word\",\"atomics\":[{\"key\":\"Docx.open_document\",\"title\":\"打开Word\",\"icon\":\"word-open-document\"},{\"key\":\"Docx.read_document_content\",\"title\":\"读取Word内容\",\"icon\":\"word-read-content\"},{\"key\":\"Docx.create_docx\",\"title\":\"创建Word\",\"icon\":\"word-new-document\"},{\"key\":\"Docx.save_docx\",\"title\":\"保存Word\",\"icon\":\"word-save-document\"},{\"key\":\"Docx.close_docx\",\"title\":\"关闭Word\",\"icon\":\"word-close-document\"},{\"key\":\"Docx.insert_docx\",\"title\":\"插入文本到Word\",\"icon\":\"word-insert-text\"},{\"key\":\"Docx.select_text\",\"title\":\"选择Word文本\",\"icon\":\"word-select-text\"},{\"key\":\"Docx.get_cursor_position\",\"title\":\"定位Word光标\",\"icon\":\"word-position-cursor\"},{\"key\":\"Docx.move_cursor\",\"title\":\"移动Word光标\",\"icon\":\"word-move-cursor\"},{\"key\":\"Docx.insert_sep\",\"title\":\"Word插入页/段落\",\"icon\":\"word-insert-page\"},{\"key\":\"Docx.insert_hyperlink\",\"title\":\"Word插入超链接\",\"icon\":\"word-insert-hyperlink\"},{\"key\":\"Docx.insert_img\",\"title\":\"Word插入图片\",\"icon\":\"word-insert-image\"},{\"key\":\"Docx.read_table\",\"title\":\"Word读取表格\",\"icon\":\"word-read-table\"},{\"key\":\"Docx.insert_table\",\"title\":\"Word插入表格\",\"icon\":\"word-insert-table\"},{\"key\":\"Docx.delete\",\"title\":\"Word删除内容\",\"icon\":\"word-delete-content\"},{\"key\":\"Docx.replace\",\"title\":\"Word替换内容\",\"icon\":\"word-replace-content\"},{\"key\":\"Docx.create_comment\",\"title\":\"Word创建批注\",\"icon\":\"word-create-comment\"},{\"key\":\"Docx.delete_comment\",\"title\":\"Word删除批注\",\"icon\":\"word-delete-comment\"},{\"key\":\"Docx.convert_format\",\"title\":\"Word导出为PDF/TXT\",\"icon\":\"word-export-pdf-txt\"}]},{\"key\":\"document.Excel\",\"title\":\"Excel\",\"atomics\":[{\"key\":\"Excel.open_excel\",\"title\":\"打开Excel\",\"icon\":\"excel-open-file\"},{\"key\":\"Excel.add_excel_worksheet\",\"title\":\"添加Excel工作表\",\"icon\":\"add-excel-worksheet\"},{\"key\":\"Excel.get_excel\",\"title\":\"获取已打开的Excel对象\",\"icon\":\"get-open-excel-objects\"},{\"key\":\"Excel.loop_excel_content\",\"title\":\"循环Excel内容\",\"icon\":\"excel-loop-content\"},{\"key\":\"Excel.create_excel\",\"title\":\"创建Excel\",\"icon\":\"excel-create-file\"},{\"key\":\"Excel.save_excel\",\"title\":\"保存Excel\",\"icon\":\"excel-save-file\"},{\"key\":\"Excel.close_excel\",\"title\":\"关闭Excel\",\"icon\":\"excel-close-file\"},{\"key\":\"Excel.edit_excel\",\"title\":\"写入Excel\",\"icon\":\"excel-write-file\"},{\"key\":\"Excel.read_excel\",\"title\":\"读取Excel内容\",\"icon\":\"excel-read-content\"},{\"key\":\"Excel.design_cell_type\",\"title\":\"设置单元格格式\",\"icon\":\"excel-set-cell-format\"},{\"key\":\"Excel.copy_excel\",\"title\":\"复制Excel单元格\",\"icon\":\"excel-copy-cell\"},{\"key\":\"Excel.paste_excel\",\"title\":\"粘贴Excel单元格\",\"icon\":\"excel-paste-cell\"},{\"key\":\"Excel.delete_excel_cell\",\"title\":\"删除Excel单元格\",\"icon\":\"excel-delete-cell\"},{\"key\":\"Excel.get_excel_worksheet_names\",\"title\":\"获取Excel工作表名称\",\"icon\":\"excel-get-sheet-names\"},{\"key\":\"Excel.clear_excel_content\",\"title\":\"清除Excel区域内容\",\"icon\":\"excel-clear-range\"},{\"key\":\"Excel.insert_excel_row_or_column\",\"title\":\"插入Excel行或列\",\"icon\":\"excel-insert-row-column\"},{\"key\":\"Excel.get_excel_row_num\",\"title\":\"获取Excel行数\",\"icon\":\"excel-get-row-count\"},{\"key\":\"Excel.get_excel_col_num\",\"title\":\"获取Excel列数\",\"icon\":\"excel-get-column-count\"},{\"key\":\"Excel.get_excel_first_available_row\",\"title\":\"获取Excel第一个可用行\",\"icon\":\"excel-get-first-available-row\"},{\"key\":\"Excel.get_excel_first_available_col\",\"title\":\"获取Excel第一个可用列\",\"icon\":\"excel-get-first-available-column\"},{\"key\":\"Excel.excel_set_row_height\",\"title\":\"设置Excel行高\",\"icon\":\"excel-set-row-height\"},{\"key\":\"Excel.excel_set_col_width\",\"title\":\"设置Excel列宽\",\"icon\":\"excel-set-column-width\"},{\"key\":\"Excel.excel_get_cell_color\",\"title\":\"获取Excel单元格颜色\",\"icon\":\"excel-get-cell-color\"},{\"key\":\"Excel.merge_split_excel_cell\",\"title\":\"合并或拆分Excel单元格\",\"icon\":\"excel-split-cell\"},{\"key\":\"Excel.move_excel_worksheet\",\"title\":\"移动Excel工作表\",\"icon\":\"excel-move-sheet\"},{\"key\":\"Excel.delete_excel_worksheet\",\"title\":\"删除Excel工作表\",\"icon\":\"excel-delete-sheet\"},{\"key\":\"Excel.rename_excel_worksheet\",\"title\":\"重命名Excel工作表\",\"icon\":\"excel-rename-sheet\"},{\"key\":\"Excel.copy_excel_worksheet\",\"title\":\"复制Excel工作表\",\"icon\":\"excel-copy-sheet\"},{\"key\":\"Excel.search_and_replace_excel_content\",\"title\":\"查找或替换Excel内容\",\"icon\":\"excel-find-replace\"},{\"key\":\"Excel.insert_pic\",\"title\":\"插入Excel图片\",\"icon\":\"excel-insert-image\"},{\"key\":\"Excel.insert_formula\",\"title\":\"插入Excel公式\",\"icon\":\"excel-insert-formula\"},{\"key\":\"Excel.create_excel_comment\",\"title\":\"创建Excel批注\",\"icon\":\"excel-create-comment\"},{\"key\":\"Excel.delete_excel_comment\",\"title\":\"删除Excel批注\",\"icon\":\"excel-delete-comment\"},{\"key\":\"Excel.excel_text_to_number\",\"title\":\"Excel区域文本转数字\",\"icon\":\"excel-text-to-number\"},{\"key\":\"Excel.excel_number_to_text\",\"title\":\"Excel区域数字转文本\",\"icon\":\"excel-number-to-text\"}]}]},{\"key\":\"keyboard\",\"title\":\"鼠标键盘\",\"atomics\":[{\"key\":\"Gui.keyboard\",\"title\":\"键盘输入\",\"icon\":\"keyboard-input\"},{\"key\":\"Gui.mouse\",\"title\":\"鼠标点击\",\"icon\":\"mouse-click\"},{\"key\":\"Gui.mouse_wheel\",\"title\":\"鼠标滚动\",\"icon\":\"mouse-scroll-webpage\"},{\"key\":\"Gui.mouse_move\",\"title\":\"鼠标移动\",\"icon\":\"mouse-move\"},{\"key\":\"Gui.mouse_drag\",\"title\":\"鼠标拖拽\",\"icon\":\"mouse-drag\"},{\"key\":\"Gui.mouse_position\",\"title\":\"获取鼠标位置\",\"icon\":\"get-mouse-position\"},{\"key\":\"Gui.key_input\",\"title\":\"键盘模拟按键\",\"icon\":\"keyboard-simulate-key\"}]},{\"key\":\"data\",\"title\":\"数据处理\",\"atomics\":[{\"key\":\"data.Math\",\"title\":\"数学操作\",\"atomics\":[{\"key\":\"MathProcess.generate_random_number\",\"title\":\"生成随机数\",\"icon\":\"generate-random-number\"},{\"key\":\"MathProcess.get_rounding_number\",\"title\":\"四舍五入\",\"icon\":\"round-number\"},{\"key\":\"MathProcess.self_calculation_number\",\"title\":\"自增自减\",\"icon\":\"increment-decrement\"},{\"key\":\"MathProcess.get_absolute_number\",\"title\":\"获取绝对值\",\"icon\":\"get-absolute-value\"},{\"key\":\"MathProcess.calculate_expression\",\"title\":\"数学计算\",\"icon\":\"math-calculation\"}]},{\"key\":\"data.String\",\"title\":\"字符串操作\",\"atomics\":[{\"key\":\"StringProcess.extract_content_from_string\",\"title\":\"文本提取内容\",\"icon\":\"text-extract-content\"},{\"key\":\"StringProcess.replace_content_in_string\",\"title\":\"文本替换内容\",\"icon\":\"text-replace-content\"},{\"key\":\"StringProcess.merge_list_to_string\",\"title\":\"列表聚合为文本\",\"icon\":\"list-to-text\"},{\"key\":\"StringProcess.split_string_to_list\",\"title\":\"文本分割为列表\",\"icon\":\"text-split-to-list\"},{\"key\":\"StringProcess.concatenate_string\",\"title\":\"文本合并\",\"icon\":\"text-merge\"},{\"key\":\"StringProcess.fill_string_to_length\",\"title\":\"文本补齐至固定长度\",\"icon\":\"text-pad-to-length\"},{\"key\":\"StringProcess.strip_string\",\"title\":\"文本去除两侧空格\",\"icon\":\"text-trim-spaces\"},{\"key\":\"StringProcess.cut_string_to_length\",\"title\":\"截取固定长度文本\",\"icon\":\"screenshot-fixed-text\"},{\"key\":\"StringProcess.change_case_of_string\",\"title\":\"更改文本大小写\",\"icon\":\"change-text-case\"},{\"key\":\"StringProcess.get_string_length\",\"title\":\"获取文本长度\",\"icon\":\"get-text-length\"},{\"key\":\"DataConvertProcess.json_convertor\",\"title\":\"JSON字符串互转\",\"icon\":\"json-string-convert\"},{\"key\":\"DataConvertProcess.other_to_str\",\"title\":\"其他格式转文本\",\"icon\":\"format-to-text\"},{\"key\":\"DataConvertProcess.str_to_other\",\"title\":\"文本转其他格式\",\"icon\":\"text-convert-format\"}]},{\"key\":\"data.List\",\"title\":\"列表操作\",\"atomics\":[{\"key\":\"ListProcess.create_new_list\",\"title\":\"创建新列表\",\"icon\":\"create-new-list\"},{\"key\":\"ListProcess.clear_list\",\"title\":\"清空列表\",\"icon\":\"list-clear\"},{\"key\":\"ListProcess.insert_value_to_list\",\"title\":\"列表插入值\",\"icon\":\"list-insert-value\"},{\"key\":\"ListProcess.change_value_in_list\",\"title\":\"列表修改值\",\"icon\":\"list-modify-value\"},{\"key\":\"ListProcess.get_list_position\",\"title\":\"获取值在列表位置\",\"icon\":\"get-value-position\"},{\"key\":\"ListProcess.remove_value_from_list\",\"title\":\"列表删除值\",\"icon\":\"list-remove-value\"},{\"key\":\"ListProcess.sort_list\",\"title\":\"列表排序\",\"icon\":\"list-sort\"},{\"key\":\"ListProcess.random_shuffle_list\",\"title\":\"列表随机打乱顺序\",\"icon\":\"list-shuffle\"},{\"key\":\"ListProcess.filter_elements_from_list\",\"title\":\"剔除列表中的多项\",\"icon\":\"list-remove-multiple\"},{\"key\":\"ListProcess.reverse_list\",\"title\":\"列表反转\",\"icon\":\"list-reverse\"},{\"key\":\"ListProcess.merge_list\",\"title\":\"列表合并\",\"icon\":\"list-merge\"},{\"key\":\"ListProcess.get_unique_list\",\"title\":\"列表去重\",\"icon\":\"list-remove-duplicates\"},{\"key\":\"ListProcess.get_common_elements_from_list\",\"title\":\"获取两个列表的重复项\",\"icon\":\"get-list-duplicates\"},{\"key\":\"ListProcess.get_value_from_list\",\"title\":\"根据索引获取列表值\",\"icon\":\"get-list-value-by-index\"},{\"key\":\"ListProcess.get_length_of_list\",\"title\":\"获取列表长度\",\"icon\":\"get-list-length\"}]},{\"key\":\"data.Dict\",\"title\":\"字典操作\",\"atomics\":[{\"key\":\"DictProcess.create_new_dict\",\"title\":\"创建新字典\",\"icon\":\"create-new-dict\"},{\"key\":\"DictProcess.set_value_to_dict\",\"title\":\"字典设置值\",\"icon\":\"dict-set-value\"},{\"key\":\"DictProcess.delete_value_from_dict\",\"title\":\"字典删除值\",\"icon\":\"dict-delete-value\"},{\"key\":\"DictProcess.get_value_from_dict\",\"title\":\"字典获取值\",\"icon\":\"dict-get-value\"},{\"key\":\"DictProcess.get_keys_from_dict\",\"title\":\"获取字典所有键\",\"icon\":\"get-dict-all-keys\"},{\"key\":\"DictProcess.get_values_from_dict\",\"title\":\"获取字典所有值\",\"icon\":\"get-dict-all-values\"}]},{\"key\":\"data.Time\",\"title\":\"时间操作\",\"atomics\":[{\"key\":\"TimeProcess.get_current_time\",\"title\":\"获取当前时间\",\"icon\":\"get-current-time\"},{\"key\":\"TimeProcess.set_time\",\"title\":\"设置时间\",\"icon\":\"set-time\"},{\"key\":\"TimeProcess.time_to_timestamp\",\"title\":\"时间对象转时间戳\",\"icon\":\"datetime-to-timestamp\"},{\"key\":\"TimeProcess.timestamp_to_time\",\"title\":\"时间戳转时间对象\",\"icon\":\"timestamp-to-datetime\"},{\"key\":\"TimeProcess.get_time_difference\",\"title\":\"获取时间差\",\"icon\":\"get-time-difference\"},{\"key\":\"TimeProcess.format_datetime\",\"title\":\"输出指定格式时间文本\",\"icon\":\"output-formatted-time\"}]}]},{\"key\":\"os\",\"title\":\"操作系统\",\"atomics\":[{\"key\":\"os.file\",\"title\":\"文件操作\",\"atomics\":[{\"key\":\"File.file_exist\",\"title\":\"IF文件存在\",\"icon\":\"check-file-exists\"},{\"key\":\"File.file_create\",\"title\":\"创建文件\",\"icon\":\"create-new-file\"},{\"key\":\"File.file_write\",\"title\":\"写入文件\",\"icon\":\"write-file\"},{\"key\":\"File.file_read\",\"title\":\"读取文件\",\"icon\":\"read-file\"},{\"key\":\"File.file_copy\",\"title\":\"复制文件\",\"icon\":\"copy-file\"},{\"key\":\"File.file_move\",\"title\":\"移动文件\",\"icon\":\"move-file\"},{\"key\":\"File.file_rename\",\"title\":\"重命名文件\",\"icon\":\"rename-file\"},{\"key\":\"File.file_delete\",\"title\":\"删除文件\",\"icon\":\"delete-file\"},{\"key\":\"File.file_search\",\"title\":\"查找文件\",\"icon\":\"find-file\"},{\"key\":\"File.file_wait_status\",\"title\":\"等待文件\",\"icon\":\"wait-file\"},{\"key\":\"File.get_file_encoding_type\",\"title\":\"获取文件编码类型\",\"icon\":\"get-file-encoding\"},{\"key\":\"File.file_info\",\"title\":\"获取文件信息\",\"icon\":\"get-file-info\"},{\"key\":\"File.get_file_list\",\"title\":\"获取文件列表\",\"icon\":\"get-file-list\"},{\"key\":\"Enterprise.upload_to_sharefolder\",\"title\":\"上传文件至共享文件夹\",\"icon\":\"upload-to-shared-folder\"},{\"key\":\"Enterprise.download_from_sharefolder\",\"title\":\"从共享文件夹下载文件\",\"icon\":\"download-from-shared-folder\"}]},{\"key\":\"os.path\",\"title\":\"文件夹操作\",\"atomics\":[{\"key\":\"Folder.folder_exist\",\"title\":\"IF文件夹存在\",\"icon\":\"check-folder-exists\"},{\"key\":\"Folder.folder_create\",\"title\":\"创建文件夹\",\"icon\":\"create-folder\"},{\"key\":\"Folder.folder_open\",\"title\":\"打开文件夹\",\"icon\":\"open-folder\"},{\"key\":\"Folder.folder_copy\",\"title\":\"复制文件夹\",\"icon\":\"copy-folder\"},{\"key\":\"Folder.folder_move\",\"title\":\"移动文件夹\",\"icon\":\"move-folder\"},{\"key\":\"Folder.folder_rename\",\"title\":\"重命名文件夹\",\"icon\":\"rename-folder\"},{\"key\":\"Folder.folder_clear\",\"title\":\"清空文件夹\",\"icon\":\"clear-folder\"},{\"key\":\"Folder.folder_delete\",\"title\":\"删除文件夹\",\"icon\":\"delete-folder-ftp\"},{\"key\":\"Folder.get_folder_list\",\"title\":\"获取文件夹列表\",\"icon\":\"get-folder-list\"}]},{\"key\":\"os.zip\",\"title\":\"压缩/解压\",\"atomics\":[{\"key\":\"System.compress\",\"title\":\"压缩\",\"icon\":\"compress\"},{\"key\":\"System.uncompress\",\"title\":\"解压\",\"icon\":\"decompress\"}]},{\"key\":\"os.system\",\"title\":\"系统命令\",\"atomics\":[{\"key\":\"System.run_command\",\"title\":\"运行或打开\",\"icon\":\"run-or-open\"},{\"key\":\"System.get_pid\",\"title\":\"获取进程PID\",\"icon\":\"get-process-pid\"},{\"key\":\"System.terminate_process\",\"title\":\"终止进程\",\"icon\":\"terminate-process\"}]},{\"key\":\"os.screenshot\",\"title\":\"截图\",\"atomics\":[{\"key\":\"System.screen_shot\",\"title\":\"屏幕截图\",\"icon\":\"screen-screenshot\"}]},{\"key\":\"os.clipboard\",\"title\":\"剪切板\",\"atomics\":[{\"key\":\"System.copy_clip\",\"title\":\"复制到剪切板\",\"icon\":\"copy-to-clipboard\"},{\"key\":\"System.clear_clip\",\"title\":\"清空剪切板\",\"icon\":\"clear-clipboard\"},{\"key\":\"System.paste_clip\",\"title\":\"获取剪切板\",\"icon\":\"get-clipboard\"}]},{\"key\":\"encrypt\",\"title\":\"加解密/编解码\",\"atomics\":[{\"key\":\"Encrypt.sha_encrypt\",\"title\":\"SHA加密\",\"icon\":\"sha-encrypt\"},{\"key\":\"Encrypt.md5_encrypt\",\"title\":\"MD5加密\",\"icon\":\"md5-encrypt\"},{\"key\":\"Encrypt.symmetric_decrypt\",\"title\":\"对称解密\",\"icon\":\"symmetric-decrypt\"},{\"key\":\"Encrypt.symmetric_encrypt\",\"title\":\"对称加密\",\"icon\":\"symmetric-encrypt\"},{\"key\":\"Encrypt.base64_decoding\",\"title\":\"Base64解码\",\"icon\":\"base64-decode\"},{\"key\":\"Encrypt.base64_encoding\",\"title\":\"Base64编码\",\"icon\":\"base64-encode\"}]}]},{\"key\":\"network\",\"title\":\"网络\",\"atomics\":[{\"key\":\"email\",\"title\":\"邮件\",\"atomics\":[{\"key\":\"Email.send_email\",\"title\":\"发送邮件\",\"icon\":\"send-email\"},{\"key\":\"Email.receive_email\",\"title\":\"接收邮件\",\"icon\":\"receive-email\"}]},{\"key\":\"http\",\"title\":\"HTTP\",\"atomics\":[{\"key\":\"Network.http_request\",\"title\":\"HTTP请求\",\"icon\":\"http-request\"},{\"key\":\"Network.http_download\",\"title\":\"HTTP下载\",\"icon\":\"http-download\"}]},{\"key\":\"ftp\",\"title\":\"FTP\",\"atomics\":[{\"key\":\"Network.ftp_create\",\"title\":\"创建FTP连接\",\"icon\":\"ftp-create-connection\"},{\"key\":\"Network.ftp_close\",\"title\":\"关闭FTP连接\",\"icon\":\"ftp-close-connection\"},{\"key\":\"Network.get_work_dir\",\"title\":\"获取工作目录(FTP)\",\"icon\":\"get-work-directory\"},{\"key\":\"Network.change_working_dir\",\"title\":\"切换工作目录(FTP)\",\"icon\":\"change-work-directory\"},{\"key\":\"Network.create_folder\",\"title\":\"创建文件夹(FTP)\",\"icon\":\"create-folder\"},{\"key\":\"Network.get_ftp_list\",\"title\":\"获取文件/文件夹(FTP)\",\"icon\":\"get-folder\"},{\"key\":\"Network.ftp_upload\",\"title\":\"上传文件/文件夹(FTP)\",\"icon\":\"upload-folder\"},{\"key\":\"Network.ftp_rename\",\"title\":\"重命名文件/文件夹(FTP)\",\"icon\":\"rename-folder\"},{\"key\":\"Network.ftp_download\",\"title\":\"下载文件/文件夹(FTP)\",\"icon\":\"download-folder\"},{\"key\":\"Network.ftp_delete\",\"title\":\"删除文件/文件夹(FTP)\",\"icon\":\"delete-folder-ftp\"}]}]},{\"key\":\"cv\",\"title\":\"CV图像\",\"atomics\":[{\"key\":\"CV.is_image_exist\",\"title\":\"IF图像存在\",\"icon\":\"if-image-exists\"},{\"key\":\"CV.cv_click\",\"title\":\"点击图像\",\"icon\":\"click-image\"},{\"key\":\"CV.hover_image\",\"title\":\"鼠标悬浮在图像上\",\"icon\":\"mouse-hover-image\"},{\"key\":\"CV.wait_image\",\"title\":\"等待图像\",\"icon\":\"wait-image\"},{\"key\":\"CV.image_input\",\"title\":\"图像输入框输入\",\"icon\":\"image-input-box\"}]},{\"key\":\"dialog\",\"title\":\"对话框\",\"atomics\":[{\"key\":\"Dialog.message_box\",\"title\":\"消息提示框\",\"icon\":\"message-dialog\"},{\"key\":\"Dialog.input_box\",\"title\":\"输入对话框\",\"icon\":\"input-dialog\"},{\"key\":\"Dialog.select_box\",\"title\":\"选择对话框\",\"icon\":\"select-dialog\"},{\"key\":\"Dialog.select_time_box\",\"title\":\"日期时间选择框\",\"icon\":\"datetime-picker\"},{\"key\":\"Dialog.select_file_box\",\"title\":\"文件选择对话框\",\"icon\":\"file-select-dialog\"},{\"key\":\"Dialog.custom_box\",\"title\":\"自定义对话框\",\"icon\":\"custom-dialog\"}]},{\"key\":\"script\",\"title\":\"自定义脚本\",\"atomics\":[{\"key\":\"BrowserScript.js_run\",\"title\":\"JS脚本\",\"icon\":\"js-script\"},{\"key\":\"Script.module\",\"title\":\"运行Python模块\",\"icon\":\"run-python-module\"}]},{\"key\":\"remote\",\"title\":\"卓越中心\",\"atomics\":[{\"key\":\"Enterprise.get_shared_variable\",\"title\":\"获取共享变量\",\"icon\":\"get-shared-variable\"},{\"key\":\"Enterprise.upload_to_sharefolder\",\"title\":\"上传文件至共享文件夹\",\"icon\":\"upload-to-shared-folder\"},{\"key\":\"Enterprise.download_from_sharefolder\",\"title\":\"从共享文件夹下载文件\",\"icon\":\"download-from-shared-folder\"}]}],\"atomicTreeExtend\":[{\"key\":\"feishu\",\"title\":\"飞书\",\"atomics\":[{\"key\":\"FeishuBase.connect_base\",\"title\":\"连接到多维表格\",\"icon\":\"connect-to-multi-sheet\"},{\"key\":\"FeishuBase.search_records\",\"title\":\"列出记录(筛选)\",\"icon\":\"list-records-filtered\"},{\"key\":\"FeishuBase.read_records\",\"title\":\"列出记录(指定)\",\"icon\":\"list-records-specified\"},{\"key\":\"FeishuBase.create_records\",\"title\":\"创建记录\",\"icon\":\"create-record\"},{\"key\":\"FeishuBase.update_records\",\"title\":\"更新记录\",\"icon\":\"update-record\"},{\"key\":\"FeishuBase.delete_records\",\"title\":\"删除记录\",\"icon\":\"delete-record\"},{\"key\":\"FeishuBase.get_table_list\",\"title\":\"列出数据表\",\"icon\":\"list-tables\"},{\"key\":\"FeishuBase.add_table\",\"title\":\"新增数据表\",\"icon\":\"add-table\"},{\"key\":\"FeishuBase.delete_table\",\"title\":\"删除数据表\",\"icon\":\"delete-table\"},{\"key\":\"FeishuBase.update_table\",\"title\":\"重命名数据表\",\"icon\":\"rename-table\"},{\"key\":\"FeishuBase.get_field_list\",\"title\":\"列出字段\",\"icon\":\"list-fields\"},{\"key\":\"FeishuBase.add_field\",\"title\":\"新增字段\",\"icon\":\"add-field\"},{\"key\":\"FeishuBase.update_field\",\"title\":\"更新字段\",\"icon\":\"update-field\"},{\"key\":\"FeishuBase.delete_field\",\"title\":\"删除字段\",\"icon\":\"delete-field\"},{\"key\":\"FeishuSheet.connect_spreadsheet\",\"title\":\"连接数据表\",\"icon\":\"connect-table\"},{\"key\":\"FeishuSheet.get_sheet_info\",\"title\":\"获取工作表信息\",\"icon\":\"get-worksheet-info\"},{\"key\":\"FeishuSheet.set_filter\",\"title\":\"设置筛选器\",\"icon\":\"set-filter\"},{\"key\":\"FeishuSheet.get_filter\",\"title\":\"获取筛选结果\",\"icon\":\"get-filter-result\"},{\"key\":\"FeishuSheet.read_data\",\"title\":\"读取工作表数据\",\"icon\":\"read-worksheet-data\"},{\"key\":\"FeishuSheet.write_data\",\"title\":\"写入数据\",\"icon\":\"write-data\"}]}],\"commonAdvancedParameter\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"RADIO\",\"params\":{}},\"key\":\"__res_print__\",\"title\":\"打印输出变量值\",\"name\":\"__res_print__\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\",\"params\":{}},\"key\":\"__delay_before__\",\"title\":\"执行前延迟(秒)\",\"name\":\"__delay_before__\",\"default\":0},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"__delay_after__\",\"title\":\"执行后延迟(秒)\",\"name\":\"__delay_after__\",\"default\":0},{\"types\":\"Str\",\"formType\":{\"type\":\"RADIO\",\"params\":{}},\"key\":\"__skip_err__\",\"title\":\"执行异常时\",\"name\":\"__skip_err__\",\"options\":[{\"label\":\"退出\",\"value\":\"exit\"},{\"label\":\"跳过\",\"value\":\"skip\"},{\"label\":\"重试\",\"value\":\"retry\"}],\"default\":\"exit\"},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"__retry_time__\",\"title\":\"重试次数(次)\",\"name\":\"__retry_time__\",\"dynamics\":[{\"key\":\"$this.__retry_time__.show\",\"expression\":\"return $this.__skip_err__.value == \'retry\'\"}],\"default\":0},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"__retry_interval__\",\"title\":\"重试间隔(秒)\",\"name\":\"__retry_interval__\",\"dynamics\":[{\"key\":\"$this.__retry_interval__.show\",\"expression\":\"return $this.__skip_err__.value == \'retry\'\"}],\"default\":0}],\"types\":{\"Any\":{\"key\":\"Any\",\"src\":\"\",\"desc\":\"任意值\",\"version\":\"1.1.47\",\"channel\":\"global\",\"template\":\"任何值\",\"funcList\":[]},\"Float\":{\"key\":\"Float\",\"src\":\"\",\"desc\":\"数值\",\"version\":\"1.1.47\",\"channel\":\"global,main\",\"template\":\"10.1\",\"funcList\":[{\"key\":\"Float.toStr\",\"funcDesc\":\"转文本\",\"resType\":\"Str\",\"resDesc\":\"字符串\",\"useSrc\":\"str(@{self:self})\"},{\"key\":\"Float.toInt\",\"funcDesc\":\"取整数部分\",\"resType\":\"Int\",\"resDesc\":\"整数\",\"useSrc\":\"int(@{self:self})\"}]},\"Int\":{\"key\":\"Int\",\"src\":\"\",\"desc\":\"整数\",\"version\":\"1.1.47\",\"channel\":\"global,main\",\"template\":\"10\",\"funcList\":[{\"key\":\"Int.toStr\",\"funcDesc\":\"转文本\",\"resType\":\"Str\",\"resDesc\":\"字符串\",\"useSrc\":\"str(@{self:self})\"}]},\"Bool\":{\"key\":\"Bool\",\"src\":\"\",\"desc\":\"布尔值\",\"version\":\"1.1.47\",\"channel\":\"global,main\",\"template\":\"true或者false\",\"funcList\":[]},\"Str\":{\"key\":\"Str\",\"src\":\"\",\"desc\":\"字符串\",\"version\":\"1.1.47\",\"channel\":\"global,main\",\"template\":\"“你好”\",\"funcList\":[{\"key\":\"Str.strip\",\"funcDesc\":\"删除两端空格\",\"resType\":\"Str\",\"resDesc\":\"字符串\",\"useSrc\":\"@{self:self}.strip()\"},{\"key\":\"Str.toInt\",\"funcDesc\":\"转整数\",\"resType\":\"Int\",\"resDesc\":\"整数\",\"useSrc\":\"int(@{self:self})\"},{\"key\":\"Str.toFloat\",\"funcDesc\":\"转数值\",\"resType\":\"Float\",\"resDesc\":\"数值\",\"useSrc\":\"float(@{self:self})\"}]},\"List\":{\"key\":\"List\",\"src\":\"\",\"desc\":\"列表\",\"version\":\"1.1.47\",\"channel\":\"global\",\"template\":\"[1,2,3]\",\"funcList\":[{\"key\":\"List.get\",\"funcDesc\":\"列表第@{p1:int}项\",\"resType\":\"Any\",\"resDesc\":\"任意值\",\"useSrc\":\"@{self:self}[@(p1:int)]\"},{\"key\":\"List.getEnd\",\"funcDesc\":\"列表倒数第@{p1:int}项\",\"resType\":\"Any\",\"resDesc\":\"任意值\",\"useSrc\":\"@{self:self}[-@(p1:int)]\"},{\"key\":\"List.getLen\",\"funcDesc\":\"列表长度\",\"resType\":\"Int\",\"resDesc\":\"整数\",\"useSrc\":\"len(@{self:self})\"},{\"key\":\"List.getSlice\",\"funcDesc\":\"列表第@{p1:int}项到第@{p2:int}项\",\"resType\":\"List\",\"resDesc\":\"列表\",\"useSrc\":\"@{self:self}[@(p1:int):@(p2:int)]\"}]},\"Dict\":{\"key\":\"Dict\",\"src\":\"\",\"desc\":\"字典\",\"version\":\"1.1.47\",\"channel\":\"global\",\"template\":\"{\\\"name\\\":\\\"小明\\\"}\",\"funcList\":[{\"key\":\"Dict.get\",\"funcDesc\":\"字典键@{p1:str}的值\",\"resType\":\"Any\",\"resDesc\":\"任意值\",\"useSrc\":\"@{self:self}[\\\"@(p1:str)\\\"]\"},{\"key\":\"List.getLen\",\"funcDesc\":\"字典包含元素个数\",\"resType\":\"Int\",\"resDesc\":\"整数\",\"useSrc\":\"len(@{self:self})\"}]},\"PATH\":{\"key\":\"PATH\",\"src\":\"\",\"desc\":\"文件路径\",\"version\":\"1.1.47\",\"channel\":\"global,main\",\"template\":\"C://Users\",\"funcList\":[{\"key\":\"PATH.root\",\"funcDesc\":\"根目录\",\"resType\":\"Str\",\"resDesc\":\"字符串\",\"useSrc\":\"@{self:self}.root()\"},{\"key\":\"PATH.directory\",\"funcDesc\":\"父目录\",\"resType\":\"Str\",\"resDesc\":\"字符串\",\"useSrc\":\"@{self:self}.directory()\"},{\"key\":\"PATH.file_name\",\"funcDesc\":\"文件名称\",\"resType\":\"Str\",\"resDesc\":\"字符串\",\"useSrc\":\"@{self:self}.file_name()\"},{\"key\":\"PATH.file_name_without_extension\",\"funcDesc\":\"文件名称(不带扩展名)\",\"resType\":\"Str\",\"resDesc\":\"字符串\",\"useSrc\":\"@{self:self}.file_name_without_extension()\"},{\"key\":\"PATH.file_extension\",\"funcDesc\":\"文件扩展名\",\"resType\":\"Str\",\"resDesc\":\"字符串\",\"useSrc\":\"@{self:self}.file_extension()\"}]},\"DIRPATH\":{\"key\":\"DIRPATH\",\"src\":\"\",\"desc\":\"文件夹路径\",\"version\":\"1.1.79\",\"channel\":\"global,main\",\"template\":\"C://Users\",\"funcList\":[{\"key\":\"DIRPATH.root\",\"funcDesc\":\"root\",\"resType\":\"Str\",\"resDesc\":\"字符串\",\"useSrc\":\"@{self:self}.root()\"},{\"key\":\"DIRPATH.directory\",\"funcDesc\":\"directory\",\"resType\":\"Str\",\"resDesc\":\"字符串\",\"useSrc\":\"@{self:self}.directory()\"}]},\"Date\":{\"key\":\"Date\",\"src\":\"\",\"desc\":\"日期时间\",\"version\":\"1.1.53\",\"channel\":\"global,main\",\"template\":\"2025-01-10 17:00:00\",\"funcList\":[{\"key\":\"Date.get_time_year\",\"funcDesc\":\"获取年份\",\"resType\":\"Int\",\"resDesc\":\"整数\",\"useSrc\":\"@{self:self}.get_time_year()\"},{\"key\":\"Date.get_time_month\",\"funcDesc\":\"获取月份\",\"resType\":\"Int\",\"resDesc\":\"整数\",\"useSrc\":\"@{self:self}.get_time_month()\"},{\"key\":\"Date.get_time_day\",\"funcDesc\":\"获取日\",\"resType\":\"Int\",\"resDesc\":\"整数\",\"useSrc\":\"@{self:self}.get_time_day()\"},{\"key\":\"Date.get_time_hour\",\"funcDesc\":\"获取小时\",\"resType\":\"Int\",\"resDesc\":\"整数\",\"useSrc\":\"@{self:self}.get_time_hour()\"},{\"key\":\"Date.get_time_minute\",\"funcDesc\":\"获取分钟\",\"resType\":\"Int\",\"resDesc\":\"整数\",\"useSrc\":\"@{self:self}.get_time_minute()\"},{\"key\":\"Date.get_time_second\",\"funcDesc\":\"获取秒\",\"resType\":\"Int\",\"resDesc\":\"整数\",\"useSrc\":\"@{self:self}.get_time_second()\"},{\"key\":\"Date.get_time_weekday\",\"funcDesc\":\"获取周几\",\"resType\":\"Int\",\"resDesc\":\"整数\",\"useSrc\":\"@{self:self}.get_time_weekday()\"},{\"key\":\"Date.get_time_week\",\"funcDesc\":\"获取周数\",\"resType\":\"Int\",\"resDesc\":\"整数\",\"useSrc\":\"@{self:self}.get_time_week()\"}]},\"URL\":{\"key\":\"URL\",\"src\":\"\",\"desc\":\"地址\",\"version\":\"1.1.47\",\"channel\":\"global\",\"template\":\"https://www.iflytek.com/\",\"funcList\":[]},\"Pick\":{\"key\":\"Pick\",\"src\":\"\",\"desc\":\"元素\",\"version\":\"1.1.47\",\"channel\":\"\",\"template\":\"JSON字符串\",\"funcList\":[]},\"WebPick\":{\"key\":\"WebPick\",\"src\":\"\",\"desc\":\"网页元素\",\"version\":\"1.1.47\",\"channel\":\"global\",\"template\":\"JSON字符串\",\"funcList\":[]},\"WinPick\":{\"key\":\"WinPick\",\"src\":\"\",\"desc\":\"桌面元素\",\"version\":\"1.1.47\",\"channel\":\"global\",\"template\":\"JSON字符串\",\"funcList\":[]},\"IMGPick\":{\"key\":\"IMGPick\",\"src\":\"\",\"desc\":\"图像元素\",\"version\":\"1.1.79\",\"channel\":\"global\",\"template\":\"JSON字符串\",\"funcList\":[]},\"Password\":{\"key\":\"Password\",\"src\":\"\",\"desc\":\"密码\",\"version\":\"1.1.51\",\"channel\":\"global,main\",\"template\":\"******\",\"funcList\":[]},\"FeishuBaseInstance\":{\"key\":\"FeishuBaseInstance\",\"src\":\"\",\"desc\":\"飞书对象\",\"version\":\"1.1.47\",\"channel\":\"\",\"template\":\"飞书对象.\",\"funcList\":[]},\"DialogResult\":{\"key\":\"DialogResult\",\"src\":\"\",\"desc\":\"对话框输出结果\",\"version\":\"1.1.47\",\"channel\":\"\",\"template\":\"JSON字符串\",\"funcList\":[]},\"Browser\":{\"key\":\"Browser\",\"src\":\"rpabrowser.browser.Browser()\",\"desc\":\"浏览器对象\",\"version\":\"1.0.22\",\"channel\":\"global\",\"template\":\"Browser对象\",\"funcList\":[{\"key\":\"Browser.get_url\",\"funcDesc\":\"该网页的地址\",\"resType\":\"Str\",\"resDesc\":\"字符串\",\"useSrc\":\"@{self:self}.get_url()\"},{\"key\":\"Browser.get_title\",\"funcDesc\":\"该网页的标题\",\"resType\":\"Str\",\"resDesc\":\"字符串\",\"useSrc\":\"@{self:self}.get_title()\"}]},\"DocumentObject\":{\"key\":\"DocumentObject\",\"src\":\"astronverse.word.docx_obj.DocumentObject()\",\"desc\":\"Word对象\",\"version\":\"1.0.1\",\"channel\":\"global\",\"template\":\"DocumentObject对象\",\"funcList\":[]},\"ExcelObj\":{\"key\":\"ExcelObj\",\"src\":\"astronverse.excel.excel_obj.ExcelObj()\",\"desc\":\"Excel对象\",\"version\":\"1.0.38\",\"channel\":\"global\",\"template\":\"ExcelObj对象\",\"funcList\":[{\"key\":\"ExcelObj.get_full_name\",\"funcDesc\":\"文件所在位置\",\"resType\":\"Str\",\"resDesc\":\"字符串\",\"useSrc\":\"@{self:self}.get_full_name()\"},{\"key\":\"ExcelObj.get_first_free_row\",\"funcDesc\":\"第一个可用行\",\"resType\":\"Int\",\"resDesc\":\"整数\",\"useSrc\":\"@{self:self}.get_first_free_row()\"}]}}}',0,'1','2025-02-21 19:54:57',1,'2025-10-15 17:38:05','1',NULL,'1000000'),(15,'ai/aim','Agent.call_dify','{\"key\":\"Agent.call_dify\",\"title\":\"调用Dify流程\",\"version\":\"1.0.0\",\"src\":\"astronverse.ai.agent.Agent().call_dify\",\"comment\":\"调用Dify流程 @{app_token} ,完成您指定的任务。\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"user\",\"title\":\"用户名\",\"name\":\"user\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"app_token\",\"title\":\"Dify流程密钥\",\"name\":\"app_token\",\"tip\":\"Dify流程密钥\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"file_flag\",\"title\":\"是否上传文件\",\"name\":\"file_flag\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"variable_name\",\"title\":\"变量名\",\"name\":\"variable_name\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"variable_value\",\"title\":\"变量值\",\"name\":\"variable_value\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.variable_value.show\",\"expression\":\"return $this.file_flag.value == false\"}],\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"文件路径\",\"name\":\"file_path\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.file_path.show\",\"expression\":\"return $this.file_flag.value == true\"}],\"required\":true},{\"types\":\"DifyFileTypes\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"file_type\",\"title\":\"文件类型\",\"name\":\"file_type\",\"tip\":\"\",\"options\":[{\"label\":\"文档\",\"value\":\"document\"},{\"label\":\"图像\",\"value\":\"image\"},{\"label\":\"视频\",\"value\":\"video\"},{\"label\":\"音频\",\"value\":\"audio\"},{\"label\":\"其他格式\",\"value\":\"custom\"}],\"default\":\"document\",\"dynamics\":[{\"key\":\"$this.file_type.show\",\"expression\":\"return $this.file_flag.value == true\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"dify_result\",\"title\":\"Dify流程结果输出\",\"tip\":\"\"}],\"icon\":\"call-dify-workflow\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(16,'ai/aim','Agent.call_xcagent','{\"key\":\"Agent.call_xcagent\",\"title\":\"调用星辰Agent流程\",\"version\":\"1.0.0\",\"src\":\"astronverse.ai.agent.Agent().call_xcagent\",\"comment\":\"调用星辰Agent流程 @{flow_id} ,完成您指定的任务。\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"api_key\",\"title\":\"api_key\",\"name\":\"api_key\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"api_secret\",\"title\":\"api_secret\",\"name\":\"api_secret\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"flow_id\",\"title\":\"流程id\",\"name\":\"flow_id\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT\"},\"key\":\"input_value\",\"title\":\"工作流默认输入\",\"name\":\"input_value\",\"tip\":\"\",\"default\":\"\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"xcagent_result\",\"title\":\"星辰Agent返回值\",\"tip\":\"\"}],\"icon\":\"call-dify-workflow\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(17,'ai/aim','ChatAI.single_turn_chat','{\"key\":\"ChatAI.single_turn_chat\",\"title\":\"单轮会话\",\"version\":\"1.0.0\",\"src\":\"astronverse.ai.chat.ChatAI().single_turn_chat\",\"comment\":\"大模型将对你提出的问题: @{query} 进行回答。\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"query\",\"title\":\"用户输入\",\"name\":\"query\",\"tip\":\"用户输入的问题。\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"LLMModelTypes\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"model\",\"title\":\"模型选择\",\"name\":\"model\",\"tip\":\"可以选择使用的模型。\",\"options\":[{\"label\":\"DeepSeek-V3\",\"value\":\"deepseek-v3-0324\"},{\"label\":\"DeepSeek-R1\",\"value\":\"claude-4-sonnet\"}],\"default\":\"deepseek-v3-0324\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"single_chat_res\",\"title\":\"答案输出\",\"tip\":\"将大模型生成的答案输出为变量。\"}],\"icon\":\"single-chat\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(18,'ai/aim','ChatAI.chat','{\"key\":\"ChatAI.chat\",\"title\":\"多轮会话\",\"version\":\"1.0.0\",\"src\":\"astronverse.ai.chat.ChatAI().chat\",\"comment\":\"大模型将扮演角色,并进行最多 (@{max_turns}) 问答次数。\",\"inputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_save\",\"title\":\"保存会话\",\"name\":\"is_save\",\"tip\":\"是否在对话结束时保存对话。\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"title\",\"title\":\"窗口标题\",\"name\":\"title\",\"tip\":\"定义对话窗口标题。\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"max_turns\",\"title\":\"最大问答次数\",\"name\":\"max_turns\",\"tip\":\"最大问答次数,完整的Q&A(question & answer)为一次。\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"LLMModelTypes\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"model\",\"title\":\"模型选择\",\"name\":\"model\",\"tip\":\"可以选择使用的模型。\",\"options\":[{\"label\":\"DeepSeek-V3\",\"value\":\"deepseek-v3-0324\"},{\"label\":\"DeepSeek-R1\",\"value\":\"claude-4-sonnet\"}],\"default\":\"deepseek-v3-0324\",\"required\":true}],\"outputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"chat_res\",\"title\":\"对话聊天记录输出\",\"tip\":\"将对话聊天记录输出为变量。\"}],\"icon\":\"multi-chat\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(19,'ai/aim','ChatAI.knowledge_chat','{\"key\":\"ChatAI.knowledge_chat\",\"title\":\"知识问答\",\"version\":\"1.0.0\",\"src\":\"astronverse.ai.chat.ChatAI().knowledge_chat\",\"comment\":\"大模型将读取的文件位于 @{file_path} 。\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"文件路径\",\"name\":\"file_path\",\"tip\":\"请选择需要进行知识问答的文件路径。\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_save\",\"title\":\"保存会话\",\"name\":\"is_save\",\"tip\":\"是否在对话结束时保存对话。\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"max_turns\",\"title\":\"最大问答次数\",\"name\":\"max_turns\",\"tip\":\"最大问答次数,完整的Q&A(question & answer)为一次。\",\"default\":20,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"knowledge_chat_res\",\"title\":\"对话聊天记录输出\",\"tip\":\"将对话聊天记录输出为变量。\"}],\"icon\":\"knowledge-qa\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(20,'ai/aim','ContractAI.get_factors','{\"key\":\"ContractAI.get_factors\",\"title\":\"合同要素提取\",\"version\":\"1.0.0\",\"src\":\"astronverse.ai.contract.ContractAI().get_factors\",\"comment\":\"提取合同 @{contract_content} 中的要素。\",\"inputList\":[{\"types\":\"InputType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"contract_type\",\"title\":\"输入合同方式\",\"name\":\"contract_type\",\"tip\":\"\",\"options\":[{\"label\":\"文件形式\",\"value\":\"file\"},{\"label\":\"文本形式\",\"value\":\"text\"}],\"default\":\"text\",\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"contract_path\",\"title\":\"合同路径\",\"name\":\"contract_path\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.contract_path.show\",\"expression\":\"return $this.contract_type.value == \'file\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"contract_content\",\"title\":\"合同文本内容\",\"name\":\"contract_content\",\"tip\":\"合同内容\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.contract_content.show\",\"expression\":\"return $this.contract_type.value == \'text\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"FACTORELEMENT\",\"params\":{\"code\":3,\"options\":[\"合同名称\",\"合同编号\",\"合同签订日期\",\"合同开始日期\",\"合同结束日期\",\"合同标的\",\"标的数量\",\"单价\",\"税率\",\"税额\",\"合同总金额\",\"付款方式\",\"甲方\",\"乙方\",\"甲方开户行\",\"甲方银行账号\",\"乙方开户行\",\"乙方银行账号\"]}},\"key\":\"custom_factors\",\"title\":\"要素\",\"name\":\"custom_factors\",\"tip\":\"\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"MODALBUTTON\",\"params\":{\"loading\":false}},\"key\":\"contract_validate\",\"title\":\"效果验证\",\"name\":\"contract_validate\",\"tip\":\"\",\"default\":\"\",\"required\":false}],\"outputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"factor_result\",\"title\":\"返回要素结果\",\"tip\":\"\"}],\"icon\":\"contract-element-extraction\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(21,'ai/aim','DocumentAI.theme_expand','{\"key\":\"DocumentAI.theme_expand\",\"title\":\"主题扩写\",\"version\":\"1.0.0\",\"src\":\"astronverse.ai.document.DocumentAI().theme_expand\",\"comment\":\"大模型将根据您给定的主题: @{text} ,对其进行扩写。\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"text\",\"title\":\"主题\",\"name\":\"text\",\"tip\":\"输入您需要扩展的主题。\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"theme_expand_res\",\"title\":\"主题扩展结果输出\",\"tip\":\"将主题扩展结果输出为变量。\"}],\"icon\":\"topic-expand\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(22,'ai/aim','DocumentAI.sentence_expand','{\"key\":\"DocumentAI.sentence_expand\",\"title\":\"段落扩写\",\"version\":\"1.0.0\",\"src\":\"astronverse.ai.document.DocumentAI().sentence_expand\",\"comment\":\"大模型将根据您给定的段落 @{text} ,对其进行扩写。\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"text\",\"title\":\"段落\",\"name\":\"text\",\"tip\":\"输入您需要扩展的段落。\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"sentence_expand_res\",\"title\":\"段落扩展结果输出\",\"tip\":\"将段落扩展结果输出为变量。\"}],\"icon\":\"paragraph-expand\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(23,'ai/aim','DocumentAI.sentence_reduce','{\"key\":\"DocumentAI.sentence_reduce\",\"title\":\"段落缩写\",\"version\":\"1.0.0\",\"src\":\"astronverse.ai.document.DocumentAI().sentence_reduce\",\"comment\":\"大模型将根据您给定的段落 @{text} ,对其进行缩写。\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"text\",\"title\":\"段落\",\"name\":\"text\",\"tip\":\"输入您需要缩写的段落。\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"sentence_reduce_res\",\"title\":\"段落缩写结果输出\",\"tip\":\"将段落缩写结果输出为变量。\"}],\"icon\":\"paragraph-abbreviate\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(24,'ai/aim','RecruitAI.generate_keywords','{\"key\":\"RecruitAI.generate_keywords\",\"title\":\"职位关键词生成\",\"version\":\"1.0.0\",\"src\":\"astronverse.ai.recruit.RecruitAI().generate_keywords\",\"comment\":\"根据职位描述 @{job_description} 生成关键词。\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"job_name\",\"title\":\"职位名称\",\"name\":\"job_name\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_PYTHON_TEXTAREAMODAL_VARIABLE\"},\"key\":\"job_description\",\"title\":\"职位描述\",\"name\":\"job_description\",\"tip\":\"\",\"default\":\"\",\"required\":true},{\"types\":\"JobWebsitesTypes\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"job_website\",\"title\":\"招聘网站\",\"name\":\"job_website\",\"tip\":\"\",\"options\":[{\"label\":\"BOSS直聘\",\"value\":\"boss\"},{\"label\":\"猎聘\",\"value\":\"liepin\"},{\"label\":\"智联招聘\",\"value\":\"zhilian\"}],\"default\":\"boss\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"recruit_keywords\",\"title\":\"职位关键词\",\"tip\":\"\"}],\"icon\":\"job-keyword-generation\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(25,'ai/aim','RecruitAI.rating_resume','{\"key\":\"RecruitAI.rating_resume\",\"title\":\"简历评分\",\"version\":\"1.0.0\",\"src\":\"astronverse.ai.recruit.RecruitAI().rating_resume\",\"comment\":\"根据简历 @{resume_content} 评分。\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"job_name\",\"title\":\"职位名称\",\"name\":\"job_name\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"InputType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"resume_input_type\",\"title\":\"简历输入方式\",\"name\":\"resume_input_type\",\"tip\":\"\",\"options\":[{\"label\":\"文件形式\",\"value\":\"file\"},{\"label\":\"文本形式\",\"value\":\"text\"}],\"default\":\"text\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"resume_file_path\",\"title\":\"简历文件路径\",\"name\":\"resume_file_path\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.resume_file_path.show\",\"expression\":\"return $this.resume_input_type.value == \'file\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"resume_content\",\"title\":\"简历文本内容\",\"name\":\"resume_content\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.resume_content.show\",\"expression\":\"return $this.resume_input_type.value == \'text\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"job_description\",\"title\":\"职位描述\",\"name\":\"job_description\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"RatingSystemTypes\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"rating_system\",\"title\":\"岗位评分体系\",\"name\":\"rating_system\",\"tip\":\"\",\"options\":[{\"label\":\"根据岗位描述生成\",\"value\":\"default\"},{\"label\":\"自定义判断标准\",\"value\":\"custom\"}],\"default\":\"default\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"rating_dimensions\",\"title\":\"岗位评分画像\",\"name\":\"rating_dimensions\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.rating_dimensions.show\",\"expression\":\"return $this.rating_system.value == \'custom\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"recruit_rating\",\"title\":\"简历匹配结果\",\"tip\":\"\"}],\"icon\":\"resume-scoring\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(26,'web','BrowserElement.wait_element','{\"key\":\"BrowserElement.wait_element\",\"title\":\"等待元素(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().wait_element\",\"comment\":\"等待浏览器对象 @{browser_obj} 中元素 @{element_data} 的(@{ele_status})\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择指定的网页元素所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"元素拾取\",\"name\":\"element_data\",\"tip\":\"拾取需要等待的网页元素\",\"required\":true,\"noInput\":true},{\"types\":\"WaitElementForStatusFlag\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"ele_status\",\"title\":\"等待类型\",\"name\":\"ele_status\",\"tip\":\"等待出现或者等待消失\",\"options\":[{\"label\":\"等待元素出现\",\"value\":\"y\"},{\"label\":\"等待元素消失\",\"value\":\"n\"}],\"default\":\"y\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"wait_element\",\"title\":\"等待结果\",\"tip\":\"输出元素是否出现/消失,出现/消失为true,反之为false\"}],\"icon\":\"wait-element-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(27,'web','BrowserElement.click','{\"key\":\"BrowserElement.click\",\"title\":\"点击元素(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().click\",\"comment\":\"通过 @{button_type:点击} 的形式点击浏览器对象 @{browser_obj} 中的元素 @{element_data}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要等待页面所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"拾取元素\",\"name\":\"element_data\",\"tip\":\"拾取需要操作的元素信息\",\"required\":true,\"noInput\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"simulate_flag\",\"title\":\"模拟人工点击\",\"name\":\"simulate_flag\",\"tip\":\"模拟人工点击是模拟人为操作方式点击,否则将根据拾取元素的自动化接口进行点击\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":false},{\"types\":\"ButtonForAssistiveKeyFlag\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"assistive_key\",\"title\":\"辅助按键\",\"name\":\"assistive_key\",\"tip\":\"在点击时需要按下的键盘功能按键\",\"options\":[{\"label\":\"无\",\"value\":\"None\"},{\"label\":\"Alt\",\"value\":\"Alt\"},{\"label\":\"Ctrl\",\"value\":\"Ctrl\"},{\"label\":\"Shift\",\"value\":\"Shift\"},{\"label\":\"Win\",\"value\":\"Win\"}],\"default\":\"None\",\"dynamics\":[{\"key\":\"$this.assistive_key.show\",\"expression\":\"return $this.simulate_flag.value == true\"}],\"required\":true},{\"types\":\"ButtonForClickTypeFlag\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"button_type\",\"title\":\"点击键位\",\"name\":\"button_type\",\"tip\":\"选择模拟鼠标点击的方式\",\"options\":[{\"label\":\"左击\",\"value\":\"click\"},{\"label\":\"双击\",\"value\":\"dbclick\"},{\"label\":\"右击\",\"value\":\"right\"}],\"default\":\"click\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"click-element-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(28,'web','BrowserElement.input','{\"key\":\"BrowserElement.input\",\"title\":\"填写输入框(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().input\",\"comment\":\"在指定的浏览器对象 @{browser_obj} 中拾取输入框 @{element_data} ,以 @{fill_type:键盘输入/剪贴板输入} 的形式输入内容 @{fill_input} ,将执行结果输出至 @{form_input}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要等待页面所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"拾取输入框\",\"name\":\"element_data\",\"tip\":\"拾取需要填写内容的输入框元素\",\"required\":true,\"noInput\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"simulate_flag\",\"title\":\"模拟人工输入\",\"name\":\"simulate_flag\",\"tip\":\"模拟人工输入是模拟人为操作方式输入,否则将根据元素的自动化接口进行输入\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":false},{\"types\":\"FillInputForFillTypeFlag\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"fill_type\",\"title\":\"输入类型\",\"name\":\"fill_type\",\"tip\":\"选择填写输入框的方式\",\"options\":[{\"label\":\"键盘输入\",\"value\":\"text\"},{\"label\":\"剪贴板\",\"value\":\"clipboard\"}],\"default\":\"text\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"fill_input\",\"title\":\"输入内容\",\"name\":\"fill_input\",\"tip\":\"填写输入框的内容\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.fill_input.show\",\"expression\":\"return $this.fill_type.value == \'text\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"focus_time\",\"title\":\"焦点睡眠时间\",\"name\":\"focus_time\",\"tip\":\"焦点停顿时间(ms)\",\"default\":1000,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.focus_time.show\",\"expression\":\"return $this.simulate_flag.value == true\"}],\"required\":false},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"write_gap_time\",\"title\":\"按键输入间隔\",\"name\":\"write_gap_time\",\"tip\":\"输入内容输入的时间间隔(s)\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.write_gap_time.show\",\"expression\":\"return $this.simulate_flag.value == true\"}],\"required\":false},{\"types\":\"FillInputForInputTypeFlag\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"input_type\",\"title\":\"追加输入\",\"name\":\"input_type\",\"tip\":\"是否对输入框进行追加输入\",\"options\":[{\"label\":\"追加\",\"value\":\"append\"},{\"label\":\"覆盖\",\"value\":\"overwrite\"}],\"default\":\"overwrite\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"form_input\",\"title\":\"用户输入内容\",\"tip\":\"\"}],\"icon\":\"fill-input-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(29,'web','BrowserElement.hover_over','{\"key\":\"BrowserElement.hover_over\",\"title\":\"鼠标悬停在元素上(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().hover_over\",\"comment\":\"鼠标悬停在浏览器对象 @{browser_obj} 中的元素 @{element_data} 上\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要等待页面所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"悬停元素拾取\",\"name\":\"element_data\",\"tip\":\"拾取鼠标要悬停的元素\",\"required\":true,\"noInput\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"mouse-hover-element-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(30,'web','BrowserElement.screenshot','{\"key\":\"BrowserElement.screenshot\",\"title\":\"拾取元素截图(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().screenshot\",\"comment\":\"拾取浏览器对象 @{browser_obj} 的元素 @{element_data} 并输出为图片\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择截图元素所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"拾取元素\",\"name\":\"element_data\",\"tip\":\"拾取需要截图的元素\",\"required\":true,\"noInput\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"folder\"}},\"key\":\"file_path\",\"title\":\"截图保存路径\",\"name\":\"file_path\",\"tip\":\"文件夹路径\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"image_name\",\"title\":\"图片名称\",\"name\":\"image_name\",\"tip\":\"携带后缀的名称比如图片.jpg\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"xpath_shot\",\"title\":\"截图文件路径\",\"tip\":\"截图文件路径\"}],\"icon\":\"pick-element-screenshot-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(31,'web','BrowserElement.position_screenshot','{\"key\":\"BrowserElement.position_screenshot\",\"title\":\"元素位置截图(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().position_screenshot\",\"comment\":\"获取浏览器对象 @{browser_obj} 的元素 @{element_data} 位置截图并输出为图片\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"拾取元素\",\"name\":\"element_data\",\"tip\":\"\",\"required\":true,\"noInput\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"folder\"}},\"key\":\"file_path\",\"title\":\"截图保存路径\",\"name\":\"file_path\",\"tip\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"image_name\",\"title\":\"图片名称\",\"name\":\"image_name\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"position_shot\",\"title\":\"截图文件路径\",\"tip\":\"\"}],\"icon\":\"element-position-screenshot-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(32,'web/web.page','BrowserElement.scroll','{\"key\":\"BrowserElement.scroll\",\"title\":\"鼠标滚动网页\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().scroll\",\"comment\":\"通过 @{scroll_direction:横向/纵向} 的方向,从(@{x_scroll_type||y_scroll_type})滚动浏览器对象 @{browser_obj} 的滚动条\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要滑动滚动条的网页所在浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"ScrollbarType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"scrollbar_type\",\"title\":\"滚动目标\",\"name\":\"scrollbar_type\",\"tip\":\"选择网页窗口滚动条或指定网页上某个滚动条元素\",\"options\":[{\"label\":\"窗口\",\"value\":\"window\"},{\"label\":\"自定义目标\",\"value\":\"customEle\"}],\"default\":\"window\",\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"拾取滚动条\",\"name\":\"element_data\",\"tip\":\"拾取需要在网页上滚动操作的滚动条元素\",\"dynamics\":[{\"key\":\"$this.element_data.show\",\"expression\":\"return $this.scrollbar_type.value == \'customEle\'\"}],\"required\":true,\"noInput\":true},{\"types\":\"ScrollDirection\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"scroll_direction\",\"title\":\"滚动方向\",\"name\":\"scroll_direction\",\"tip\":\"\",\"options\":[{\"label\":\"横向\",\"value\":\"horizontal\"},{\"label\":\"纵向\",\"value\":\"vertical\"}],\"default\":\"horizontal\",\"required\":true},{\"types\":\"ScrollbarForXScrollTypeFlag\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"x_scroll_type\",\"title\":\"横向滚动位置\",\"name\":\"x_scroll_type\",\"tip\":\"\",\"options\":[{\"label\":\"最左\",\"value\":\"left\"},{\"label\":\"最右\",\"value\":\"right\"},{\"label\":\"自定义\",\"value\":\"defined\"}],\"default\":\"left\",\"dynamics\":[{\"key\":\"$this.x_scroll_type.show\",\"expression\":\"return $this.scroll_direction.value == \'horizontal\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"x_custom_scroll_dis\",\"title\":\"横向自定义滚动距离\",\"name\":\"x_custom_scroll_dis\",\"tip\":\"单位为屏幕的分辨率像素px,一般为0-9999之间的数值\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.x_custom_scroll_dis.show\",\"expression\":\"return $this.scroll_direction.value == \'horizontal\' && $this.x_scroll_type.value == \'defined\'\"}],\"required\":true},{\"types\":\"ScrollbarForYScrollTypeFlag\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"y_scroll_type\",\"title\":\"纵向滚动位置\",\"name\":\"y_scroll_type\",\"tip\":\"\",\"options\":[{\"label\":\"顶部\",\"value\":\"top\"},{\"label\":\"底部\",\"value\":\"bottom\"},{\"label\":\"自定义\",\"value\":\"defined\"}],\"default\":\"top\",\"dynamics\":[{\"key\":\"$this.y_scroll_type.show\",\"expression\":\"return $this.scroll_direction.value == \'vertical\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"y_custom_scroll_dis\",\"title\":\"纵向自定义滚动距离\",\"name\":\"y_custom_scroll_dis\",\"tip\":\"单位为屏幕的分辨率像素px,一般为0-9999之间的数值\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.y_custom_scroll_dis.show\",\"expression\":\"return $this.scroll_direction.value == \'vertical\' && $this.y_scroll_type.value == \'defined\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.element_timeout.show\",\"expression\":\"return $this.scrollbar_type.value == \'customEle\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"mouse-scroll-webpage\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(33,'web','BrowserElement.scroll_into_view','{\"key\":\"BrowserElement.scroll_into_view\",\"title\":\"元素置于可视区域(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().scroll_into_view\",\"comment\":\"将网页元素 @{element_data} 置于可视区域\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要可视的元素所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"拾取可视目标\",\"name\":\"element_data\",\"tip\":\"拾取需要可视的目标元素\",\"required\":true,\"noInput\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"element-to-visible-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(34,'web','BrowserElement.similar','{\"key\":\"BrowserElement.similar\",\"title\":\"获取相似元素列表(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().similar\",\"comment\":\"获取浏览器对象 @{browser_obj} 中与拾取到的元素 @{element_data} 相似的元素,并将相似元素数组输出至 @{get_similar_ele}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择相似元素所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"相似元素拾取\",\"name\":\"element_data\",\"tip\":\"在网页上拾取不同位置的两个相似元素\",\"required\":true,\"noInput\":true},{\"types\":\"ElementGetAttributeHasSelfTypeFlag\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"get_type\",\"title\":\"元素操作\",\"name\":\"get_type\",\"tip\":\"\",\"options\":[{\"label\":\"获取元素对象\",\"value\":\"getElement\"},{\"label\":\"获取元素文本内容\",\"value\":\"getText\"},{\"label\":\"获取元素源代码\",\"value\":\"getHtml\"},{\"label\":\"获取元素值\",\"value\":\"getValue\"},{\"label\":\"获取元素链接地址\",\"value\":\"getLink\"},{\"label\":\"获取元素属性\",\"value\":\"getAttribute\"},{\"label\":\"获取元素位置\",\"value\":\"getPosition\"},{\"label\":\"获取元素选中状态\",\"value\":\"getSelection\"}],\"default\":\"getElement\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"attribute_name\",\"title\":\"属性名称\",\"name\":\"attribute_name\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.attribute_name.show\",\"expression\":\"return $this.get_type.value == \'getAttribute\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_similar_ele\",\"title\":\"元素信息\",\"tip\":\"\"}],\"icon\":\"get-similar-elements-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(35,'web','BrowserElement.loop_similar','{\"key\":\"BrowserElement.loop_similar\",\"title\":\"循环相似元素列表(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().loop_similar\",\"comment\":\"获取浏览器对象 @{browser_obj} 中与拾取到的元素 @{element_data} 相似的元素,从起始项@{start}到结束项@{end}进行循环操作,输出列表循环至@{item}, 是否输出循环项位置为@{index}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择相似元素所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"相似元素拾取\",\"name\":\"element_data\",\"tip\":\"在网页上拾取不同位置的两个相似元素\",\"required\":true,\"noInput\":true},{\"types\":\"ElementGetAttributeHasSelfTypeFlag\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"get_type\",\"title\":\"元素操作\",\"name\":\"get_type\",\"tip\":\"\",\"options\":[{\"label\":\"获取元素对象\",\"value\":\"getElement\"},{\"label\":\"获取元素文本内容\",\"value\":\"getText\"},{\"label\":\"获取元素源代码\",\"value\":\"getHtml\"},{\"label\":\"获取元素值\",\"value\":\"getValue\"},{\"label\":\"获取元素链接地址\",\"value\":\"getLink\"},{\"label\":\"获取元素属性\",\"value\":\"getAttribute\"},{\"label\":\"获取元素位置\",\"value\":\"getPosition\"},{\"label\":\"获取元素选中状态\",\"value\":\"getSelection\"}],\"default\":\"getElement\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"start\",\"title\":\"起始位置\",\"name\":\"start\",\"tip\":\"下标位置从0开始\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"end\",\"title\":\"结束位置\",\"name\":\"end\",\"tip\":\"下标位置从0开始,-1代表循环至最后一个元素\",\"default\":-1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"attribute_name\",\"title\":\"属性名称\",\"name\":\"attribute_name\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.attribute_name.show\",\"expression\":\"return $this.get_type.value == \'getAttribute\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"index\",\"title\":\"循环项位置\",\"tip\":\"默认变量可修改,用于遍历列表的变量索引数值\"},{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"item\",\"title\":\"循环项\",\"tip\":\"默认变量可修改,用于遍历列表的变量\"}],\"icon\":\"loop-similar-elements-web\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(36,'web','BrowserElement.element_text','{\"key\":\"BrowserElement.element_text\",\"title\":\"获取元素文本内容(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().element_text\",\"comment\":\"获取浏览器对象 @{browser_obj} 网页中拾取的元素 @{element_data} 文本内容,并将结果输出至 @{data_pick}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要获取文本的元素所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"元素拾取\",\"name\":\"element_data\",\"tip\":\"选择要获取文本的元素位置\",\"required\":true,\"noInput\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"data_pick\",\"title\":\"输出变量\",\"tip\":\"输出获取到的当前网页标题字符串\"}],\"icon\":\"get-element-text-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(37,'web','BrowserElement.slider_hover','{\"key\":\"BrowserElement.slider_hover\",\"title\":\"拾取滑块拖拽(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().slider_hover\",\"comment\":\"将滑块 @{element_slider} 从 @{drag_type} 向 @{drag_direction} 拖拽 @{percent_value} %\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"slider_element\",\"name\":\"slider_element\",\"required\":true,\"noInput\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"progress_element\",\"name\":\"progress_element\",\"required\":true,\"noInput\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"percent_value\",\"title\":\"滑块移动比例\",\"name\":\"percent_value\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"ElementDragDirectionTypeFlag\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"drag_direction\",\"title\":\"拖拽方向\",\"name\":\"drag_direction\",\"tip\":\"\",\"options\":[{\"label\":\"左\",\"value\":\"left\"},{\"label\":\"右\",\"value\":\"right\"},{\"label\":\"上\",\"value\":\"up\"},{\"label\":\"下\",\"value\":\"down\"}],\"default\":\"left\",\"required\":true},{\"types\":\"ElementDragTypeFlag\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"drag_type\",\"title\":\"拖拽类型\",\"name\":\"drag_type\",\"tip\":\"\",\"options\":[{\"label\":\"起始位置\",\"value\":\"start\"},{\"label\":\"当前位置\",\"value\":\"current\"}],\"default\":\"start\",\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"duration\",\"title\":\"拖动的持续时间\",\"name\":\"duration\",\"tip\":\"\",\"default\":0.25,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"pick-slider-drag-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(38,'web','BrowserElement.get_select','{\"key\":\"BrowserElement.get_select\",\"title\":\"获取下拉框(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().get_select\",\"comment\":\"在浏览器对象 @{browser_obj} 中获取下拉框 @{element_data}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"拾取下拉框\",\"name\":\"element_data\",\"tip\":\"\",\"required\":true,\"noInput\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"current_content\",\"title\":\"获取当前选中内容\",\"name\":\"current_content\",\"tip\":\"选中内容或者所有内容\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_selected\",\"title\":\"下拉框选中内容\",\"tip\":\"\"}],\"icon\":\"get-dropdown-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(39,'web','BrowserElement.get_checked','{\"key\":\"BrowserElement.get_checked\",\"title\":\"获取复选框(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().get_checked\",\"comment\":\"在浏览器对象 @{browser_obj} 中获取复选框 @{element_data}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"拾取复选框\",\"name\":\"element_data\",\"tip\":\"\",\"required\":true,\"noInput\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_checkbox_checked\",\"title\":\"复选框选中内容\",\"tip\":\"\"}],\"icon\":\"get-checkbox-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(40,'web','BrowserElement.set_select','{\"key\":\"BrowserElement.set_select\",\"title\":\"操作下拉框(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().set_select\",\"comment\":\"在浏览器对象 @{browser_obj} 中获取下拉框 @{element_data} ,通过 @{pattern} 选择 @{value}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"拾取下拉框\",\"name\":\"element_data\",\"tip\":\"\",\"required\":true,\"noInput\":true},{\"types\":\"SelectionPartner\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"pattern\",\"title\":\"匹配模式\",\"name\":\"pattern\",\"tip\":\"\",\"options\":[{\"label\":\"模糊匹配\",\"value\":\"contains\"},{\"label\":\"精准匹配\",\"value\":\"equal\"},{\"label\":\"顺序匹配\",\"value\":\"index\"}],\"default\":\"contains\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"value\",\"title\":\"匹配内容\",\"name\":\"value\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.value.show\",\"expression\":\"return [\'contains\', \'equal\'].includes($this.pattern.value)\"}],\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"solution\",\"title\":\"顺序\",\"name\":\"solution\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.solution.show\",\"expression\":\"return $this.pattern.value == \'index\'\"}],\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"operate-dropdown-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(41,'web','BrowserElement.set_checked','{\"key\":\"BrowserElement.set_checked\",\"title\":\"操作复选框(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().set_checked\",\"comment\":\"在浏览器对象 @{browser_obj} 中获取复选框 @{element_data} 后 @{checked_type}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"拾取复选框\",\"name\":\"element_data\",\"tip\":\"\",\"required\":true,\"noInput\":true},{\"types\":\"ElementCheckedTypeFlag\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"checked_type\",\"title\":\"操作类型\",\"name\":\"checked_type\",\"tip\":\"\",\"options\":[{\"label\":\"勾选\",\"value\":\"checked\"},{\"label\":\"取消勾选\",\"value\":\"unchecked\"},{\"label\":\"反选\",\"value\":\"reversed\"}],\"default\":\"checked\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"operate-checkbox-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(42,'web','BrowserElement.element_operation','{\"key\":\"BrowserElement.element_operation\",\"title\":\"元素操作(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().element_operation\",\"comment\":\"在浏览器对象 @{browser_obj} 中获取 @{element_data} 并 @{operation_type}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"拾取元素\",\"name\":\"element_data\",\"tip\":\"\",\"required\":true,\"noInput\":true},{\"types\":\"ElementAttributeOpTypeFlag\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"operation_type\",\"title\":\"操作类型\",\"name\":\"operation_type\",\"tip\":\"设置-获取-删除信息\",\"options\":[{\"label\":\"获取属性\",\"value\":\"get\"},{\"label\":\"设置属性\",\"value\":\"set\"},{\"label\":\"删除属性\",\"value\":\"del\"}],\"default\":\"get\",\"required\":true},{\"types\":\"ElementGetAttributeTypeFlag\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"get_type\",\"title\":\"信息类型\",\"name\":\"get_type\",\"tip\":\"\",\"options\":[{\"label\":\"获取元素文本内容\",\"value\":\"getText\"},{\"label\":\"获取元素源代码\",\"value\":\"getHtml\"},{\"label\":\"获取元素值\",\"value\":\"getValue\"},{\"label\":\"获取元素链接地址\",\"value\":\"getLink\"},{\"label\":\"获取元素属性\",\"value\":\"getAttribute\"},{\"label\":\"获取元素位置\",\"value\":\"getPosition\"},{\"label\":\"获取元素选中状态\",\"value\":\"getSelection\"}],\"default\":\"getText\",\"dynamics\":[{\"key\":\"$this.get_type.show\",\"expression\":\"return $this.operation_type.value == \'get\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"attribute_name\",\"title\":\"属性名称\",\"name\":\"attribute_name\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.attribute_name.show\",\"expression\":\"return $this.get_type.value == \'getAttribute\' || [\'set\', \'del\'].includes($this.operation_type.value)\"}],\"required\":true},{\"types\":\"RelativePosition\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"position\",\"title\":\"相对位置\",\"name\":\"position\",\"tip\":\"\",\"options\":[{\"label\":\"屏幕左上\",\"value\":\"screenLeft\"},{\"label\":\"页面左上\",\"value\":\"webPageLeft\"}],\"default\":\"screenLeft\",\"dynamics\":[{\"key\":\"$this.position.show\",\"expression\":\"return $this.get_type.value == \'getPosition\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"attribute_value\",\"title\":\"属性值\",\"name\":\"attribute_value\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.attribute_value.show\",\"expression\":\"return $this.operation_type.value == \'set\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_ele_attr\",\"title\":\"元素属性\",\"tip\":\"\",\"dynamics\":[{\"key\":\"$this.get_ele_attr.show\",\"expression\":\"return $this.get_type.value == \'getAttribute\'\"}]},{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_ele_value\",\"title\":\"元素值\",\"tip\":\"\",\"dynamics\":[{\"key\":\"$this.get_ele_value.show\",\"expression\":\"return $this.get_type.value == \'getValue\'\"}]},{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_ele_html\",\"title\":\"元素源代码\",\"tip\":\"\",\"dynamics\":[{\"key\":\"$this.get_ele_html.show\",\"expression\":\"return $this.get_type.value == \'getHtml\'\"}]},{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_ele_link\",\"title\":\"元素链接地址\",\"tip\":\"\",\"dynamics\":[{\"key\":\"$this.get_ele_link.show\",\"expression\":\"return $this.get_type.value == \'getLink\'\"}]},{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_ele_text\",\"title\":\"元素文本内容\",\"tip\":\"\",\"dynamics\":[{\"key\":\"$this.get_ele_text.show\",\"expression\":\"return $this.get_type.value == \'getText\'\"}]},{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_ele_position\",\"title\":\"元素位置\",\"tip\":\"\",\"dynamics\":[{\"key\":\"$this.get_ele_position.show\",\"expression\":\"return $this.get_type.value == \'getPosition\'\"}]},{\"types\":\"Bool\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_ele_selected\",\"title\":\"元素选中状态\",\"tip\":\"\",\"dynamics\":[{\"key\":\"$this.get_ele_selected.show\",\"expression\":\"return $this.get_type.value == \'getSelection\'\"}]}],\"icon\":\"element-operation-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(43,'web','BrowserElement.get_table','{\"key\":\"BrowserElement.get_table\",\"title\":\"获取表格数据(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().get_table\",\"comment\":\"获取浏览器对象 @{browser_obj} 中的表格 @{element_data} ,将结果输出为字典对象 @{table_pick}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要等待页面所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"拾取表格\",\"name\":\"element_data\",\"tip\":\"拾取网页表格中任一单元格元素,无须拾取整个表格\",\"required\":true,\"noInput\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"to_excel\",\"title\":\"存储到表格文档\",\"name\":\"to_excel\",\"tip\":\"可直接存储为excel文档\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\"}},\"key\":\"excel_path\",\"title\":\"表格文档路径\",\"name\":\"excel_path\",\"tip\":\"请选择文档存储路径\",\"dynamics\":[{\"key\":\"$this.excel_path.show\",\"expression\":\"return $this.to_excel.value == true\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"table_pick\",\"title\":\"表格对象\",\"tip\":\"输出获取的表格对象,数据类型:字典\"}],\"icon\":\"get-table-data-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(44,'web','BrowserElement.data_batch','{\"key\":\"BrowserElement.data_batch\",\"title\":\"数据抓取(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().data_batch\",\"comment\":\"在指定的浏览器对象 @{browser_obj} 中抓取 @{batch_data} ,将结果输出为字典对象 @{table_pick}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要等待页面所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"BATCH\"}},\"key\":\"batch_data\",\"title\":\"抓取对象\",\"name\":\"batch_data\",\"tip\":\"拾取需要抓取的元素\",\"required\":true,\"noInput\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"multi_page\",\"title\":\"是否抓取多页\",\"name\":\"multi_page\",\"tip\":\"选择需要是否抓取多页,默认抓取当前页\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page_count\",\"title\":\"抓取页数\",\"name\":\"page_count\",\"tip\":\"填写需要抓取的总页数,例如:抓取10页,则填写10\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.page_count.show\",\"expression\":\"return $this.multi_page.value == true\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page_interval\",\"title\":\"翻页间隔时间,单位:秒\",\"name\":\"page_interval\",\"tip\":\"填写翻页的间隔时间,若间隔时间过短导致页面加载不完全,可适当增加翻页间隔时间\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.page_interval.show\",\"expression\":\"return $this.multi_page.value == true\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"翻页按钮\",\"name\":\"element_data\",\"tip\":\"拾取需要翻页的元素\",\"dynamics\":[{\"key\":\"$this.element_data.show\",\"expression\":\"return $this.multi_page.value == true\"}],\"required\":true,\"noInput\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"simulate_flag\",\"title\":\"模拟人工输入\",\"name\":\"simulate_flag\",\"tip\":\"模拟人工输入是模拟人为操作方式输入,否则将根据元素的自动化接口进行输入\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"dynamics\":[{\"key\":\"$this.simulate_flag.show\",\"expression\":\"return $this.multi_page.value == true\"}],\"required\":false},{\"types\":\"ButtonForClickTypeFlag\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"button_type\",\"title\":\"点击键位\",\"name\":\"button_type\",\"tip\":\"选择模拟鼠标点击的方式\",\"options\":[{\"label\":\"左击\",\"value\":\"click\"},{\"label\":\"双击\",\"value\":\"dbclick\"},{\"label\":\"右击\",\"value\":\"right\"}],\"default\":\"click\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"to_excel\",\"title\":\"存储到表格文档\",\"name\":\"to_excel\",\"tip\":\"可直接存储为excel文档\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\",\"filters\":[\".xlsx\"],\"defaultPath\":\"default.xlsx\"}},\"key\":\"excel_path\",\"title\":\"表格文档路径\",\"name\":\"excel_path\",\"tip\":\"请选择文档存储路径\",\"dynamics\":[{\"key\":\"$this.excel_path.show\",\"expression\":\"return $this.to_excel.value == true\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"TablePickType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"output_type\",\"title\":\"输出类型\",\"name\":\"output_type\",\"tip\":\"选择表格输出类型,默认输出为行\",\"options\":[{\"label\":\"按行输出\",\"value\":\"row\"},{\"label\":\"按列输出\",\"value\":\"column\"}],\"default\":\"row\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"output_head\",\"title\":\"是否输出表头\",\"name\":\"output_head\",\"tip\":\"选择是否输出表头,默认输出表头\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":false}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"table_pick\",\"title\":\"表格对象\",\"tip\":\"输出获取的表格对象,数据类型:字典\"},{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"table_path\",\"title\":\"表格路径\",\"tip\":\"输出保存的表格路径\",\"dynamics\":[{\"key\":\"$this.table_path.show\",\"expression\":\"return $this.to_excel.value == true\"}]}],\"icon\":\"data-scraping-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(45,'web','BrowserElement.create_element','{\"key\":\"BrowserElement.create_element\",\"title\":\"获取元素对象(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().create_element\",\"comment\":\"在指定的浏览器对象 @{browser_obj} 中根据 @{locate_type}获取元素对象 ,将结果输出为元素对象 @{element_obj}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"LocateType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"locate_type\",\"title\":\"定位方式\",\"name\":\"locate_type\",\"tip\":\"选择Xpath或者CssSelector定位方式\",\"options\":[{\"label\":\"xpath\",\"value\":\"xpath\"},{\"label\":\"css选择器\",\"value\":\"cssSelector\"}],\"default\":\"xpath\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"locate_value\",\"title\":\"Xpath/CssSelector\",\"name\":\"locate_value\",\"tip\":\"输入Xpath或者CssSelector\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"element_obj\",\"title\":\"元素对象\",\"tip\":\"输出元素对象,结果为单个对象或列表\"}],\"icon\":\"get-element-object-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(46,'web','BrowserElement.get_relative_element','{\"key\":\"BrowserElement.get_relative_element\",\"title\":\"获取关联元素(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().get_relative_element\",\"comment\":\"在指定的浏览器对象 @{browser_obj} 中获取 @{element_data} 关联的 @{relative_type},将结果输出为元素对象 @{element_obj}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"元素对象\",\"name\":\"element_data\",\"tip\":\"作为锚点的元素,只能是单个元素对象,不能是列表\",\"required\":true,\"noInput\":true},{\"types\":\"RelativeType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"relative_type\",\"title\":\"关联类型\",\"name\":\"relative_type\",\"tip\":\"选择关联类型,例如:兄弟元素、父级元素、子级元素等\",\"options\":[{\"label\":\"子元素\",\"value\":\"child\"},{\"label\":\"父元素\",\"value\":\"parent\"},{\"label\":\"兄弟元素\",\"value\":\"sibling\"}],\"default\":\"child\",\"required\":true},{\"types\":\"ChildElementType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"child_element_type\",\"title\":\"子元素类型\",\"name\":\"child_element_type\",\"tip\":\"选择获取子元素的类型\",\"options\":[{\"label\":\"所有子元素\",\"value\":\"all\"},{\"label\":\"第n个子元素\",\"value\":\"index\"},{\"label\":\"子元素xpath\",\"value\":\"xpath\"},{\"label\":\"最后一个子元素\",\"value\":\"last\"}],\"default\":\"all\",\"dynamics\":[{\"key\":\"$this.child_element_type.show\",\"expression\":\"return $this.relative_type.value == \'child\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"child_element_xpath\",\"title\":\"子元素xpath\",\"name\":\"child_element_xpath\",\"tip\":\"填写子元素的xpath,仅获取单个元素\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.child_element_xpath.show\",\"expression\":\"return $this.child_element_type.value == \'xpath\' && $this.relative_type.value == \'child\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"child_element_index\",\"title\":\"子元素位置\",\"name\":\"child_element_index\",\"tip\":\"填写子元素位置,例如:0表示第一个子元素\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.child_element_index.show\",\"expression\":\"return $this.child_element_type.value == \'index\' && $this.relative_type.value == \'child\'\"}],\"required\":true},{\"types\":\"SiblingElementType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"sibling_element_type\",\"title\":\"兄弟元素类型\",\"name\":\"sibling_element_type\",\"tip\":\"选择获取兄弟元素的类型\",\"options\":[{\"label\":\"所有兄弟元素\",\"value\":\"all\"},{\"label\":\"下一个兄弟元素\",\"value\":\"next\"},{\"label\":\"上一个兄弟元素\",\"value\":\"prev\"}],\"default\":\"all\",\"dynamics\":[{\"key\":\"$this.sibling_element_type.show\",\"expression\":\"return $this.relative_type.value == \'sibling\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"element_timeout\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"element_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"element_obj\",\"title\":\"元素对象\",\"tip\":\"输出元素对象,结果为单个对象或列表\"}],\"icon\":\"get-related-elements-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(47,'web','BrowserElement.element_exist','{\"key\":\"BrowserElement.element_exist\",\"title\":\"元素是否存在(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_element.BrowserElement().element_exist\",\"comment\":\"浏览器对象 @{browser_obj} 中元素 @{element_data} 是否存在\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择指定的网页元素所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"元素拾取\",\"name\":\"element_data\",\"tip\":\"拾取需要等待的网页元素\",\"required\":true,\"noInput\":true}],\"outputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"element_exist\",\"title\":\"元素存在/不存在\",\"tip\":\"输出元素是否存在,存在为true,不存在为false\"}],\"icon\":\"wait-element-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(48,'script','BrowserScript.js_run','{\"key\":\"BrowserScript.js_run\",\"title\":\"Js脚本\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_script.BrowserScript().js_run\",\"comment\":\"通过 @{input_type:在线编辑/外部导入方式} 编辑脚本内容 @{content||file_path} ,执行JavaScript,脚本执行结果保存至 @{program_script}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择js运行的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"InputType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"input_type\",\"title\":\"写入方式\",\"name\":\"input_type\",\"tip\":\"\",\"options\":[{\"label\":\"在线编辑\",\"value\":\"content\"},{\"label\":\"外部导入\",\"value\":\"file\"}],\"default\":\"content\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_PYTHON_TEXTAREAMODAL_VARIABLE\"},\"key\":\"content\",\"title\":\"脚本内容\",\"name\":\"content\",\"tip\":\"编辑要执行的自定义脚本\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.content.show\",\"expression\":\"return $this.input_type.value == \'content\'\"}],\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\",\"filters\":[\".js\"]}},\"key\":\"file_path\",\"title\":\"脚本路径\",\"name\":\"file_path\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.file_path.show\",\"expression\":\"return $this.input_type.value == \'file\'\"}],\"required\":true},{\"types\":\"List\",\"formType\":{\"type\":\"SCRIPTPARAMS\"},\"key\":\"params\",\"title\":\"参数管理\",\"name\":\"params\",\"tip\":\"输入脚本相关的参数管理,注意参数会被序列化,一些不支持序列化的将会报错\",\"need_parse\":\"json_str\",\"required\":false},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"iframe元素对象\",\"name\":\"element_data\",\"tip\":\"对于iframe中执行有问题的,可以获取iframe的元素对象来辅助iframe的脚本执行\",\"required\":false,\"noInput\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"iframe_url\",\"title\":\"iframe地址\",\"name\":\"iframe_url\",\"tip\":\"对于iframe中执行有问题,可以获取iframe的src字段填入此处\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"program_script\",\"title\":\"执行结果\",\"tip\":\"\"}],\"icon\":\"js-script\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(49,'web','BrowserSoftware.browser_open','{\"key\":\"BrowserSoftware.browser_open\",\"title\":\"打开浏览器\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().browser_open\",\"comment\":\"打开 @{browser_type:浏览器} 并进入初始网址 @{url:网址} ,将结果输出为浏览器对象 @{web_open}\",\"inputList\":[{\"types\":\"URL\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"url\",\"title\":\"初始网址\",\"name\":\"url\",\"tip\":\"初始网址\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"CommonForBrowserType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"browser_type\",\"title\":\"浏览器类型\",\"name\":\"browser_type\",\"tip\":\"选择浏览器类型,需安装星火数字员工插件实现网页自动化,路径:设置-插件安装\",\"options\":[{\"label\":\"Chrome\",\"value\":\"chrome\"},{\"label\":\"Edge\",\"value\":\"edge\"},{\"label\":\"360安全浏览器\",\"value\":\"360se\"},{\"label\":\"360极速浏览器X\",\"value\":\"360ChromeX\"},{\"label\":\"Firefox\",\"value\":\"firefox\"},{\"label\":\"内置浏览器\",\"value\":\"chromium\"}],\"default\":\"chrome\",\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\"}},\"key\":\"browser_abs_path\",\"title\":\"浏览器路径\",\"name\":\"browser_abs_path\",\"tip\":\"浏览器软件安装路径\",\"default\":\"\",\"level\":\"normal\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"open_args\",\"title\":\"浏览器启动参数\",\"name\":\"open_args\",\"tip\":\"浏览器启动参数,比如--incognito\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"required\":false},{\"types\":\"Bool\",\"formType\":{\"type\":\"CHECKBOX\"},\"key\":\"open_with_incognito\",\"title\":\"使用隐私模式\",\"name\":\"open_with_incognito\",\"tip\":\"请提前将浏览器中“星火数字员工插件”详情设置为\\\"在无痕模式下启用\\\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"level\":\"advanced\",\"required\":false},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"wait_load_success\",\"title\":\"等待网页加载完成\",\"name\":\"wait_load_success\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"level\":\"normal\",\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"timeout\",\"title\":\"加载延时时间(秒)\",\"name\":\"timeout\",\"tip\":\"\",\"default\":20,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"normal\",\"dynamics\":[{\"key\":\"$this.timeout.show\",\"expression\":\"return $this.wait_load_success.value == true\"}],\"required\":true},{\"types\":\"CommonForTimeoutHandleType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"timeout_handle_type\",\"title\":\"延时超时后执行\",\"name\":\"timeout_handle_type\",\"tip\":\"延时处理方式,终止即停止网页加载,跳过即跳过等待加载,不影响网页加载\",\"options\":[{\"label\":\"终止\",\"value\":\"execError\"},{\"label\":\"跳过\",\"value\":\"stopLoad\"}],\"default\":\"execError\",\"level\":\"normal\",\"dynamics\":[{\"key\":\"$this.timeout_handle_type.show\",\"expression\":\"return $this.wait_load_success.value == true\"}],\"required\":true}],\"outputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"web_open\",\"title\":\"浏览器对象\",\"tip\":\"输出打开的浏览器对象,使用此网页对象可实现网页自动化\"}],\"icon\":\"open-browser\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(50,'web','BrowserSoftware.browser_close','{\"key\":\"BrowserSoftware.browser_close\",\"title\":\"关闭浏览器\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().browser_close\",\"comment\":\"关闭浏览器对象 @{browser_obj}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要关闭的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"close-browser\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(51,'web/web.cookie','BrowserSoftware.set_cookies','{\"key\":\"BrowserSoftware.set_cookies\",\"title\":\"设置Cookie\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().set_cookies\",\"comment\":\"设置浏览器对象 @{browser_obj} 的Cookie值为 @{cookie_input}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要设置Cookies的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"URL\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"url\",\"title\":\"目标url\",\"name\":\"url\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"cookie_name\",\"title\":\"cookie名称\",\"name\":\"cookie_name\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"cookie_val\",\"title\":\"cookie值\",\"name\":\"cookie_val\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page_timeout\",\"title\":\"等待页面加载时间(秒)\",\"name\":\"page_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"cookie_input\",\"title\":\"cookie值\",\"tip\":\"\"}],\"icon\":\"set-cookie\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(52,'web/web.cookie','BrowserSoftware.get_cookies','{\"key\":\"BrowserSoftware.get_cookies\",\"title\":\"获取Cookie\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().get_cookies\",\"comment\":\"获取浏览器对象 @{browser_obj} 的Cookie值,输出至 @{get_cookie}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要获取cookie值的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"URL\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"url\",\"title\":\"目标url\",\"name\":\"url\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"cookie_name\",\"title\":\"cookie名称\",\"name\":\"cookie_name\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page_timeout\",\"title\":\"等待页面加载时间(秒)\",\"name\":\"page_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_cookie\",\"title\":\"cookie值\",\"tip\":\"\"}],\"icon\":\"get-cookie\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(53,'web/web.page','BrowserSoftware.web_open','{\"key\":\"BrowserSoftware.web_open\",\"title\":\"打开新网页\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().web_open\",\"comment\":\"打开浏览器对象 @{browser_obj} 并进入网址 @{new_tab_url:新标签页地址} ,将结果输出为浏览器对象(open_new_tab_1)\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要等待页面所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"URL\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"new_tab_url\",\"title\":\"新标签页网址\",\"name\":\"new_tab_url\",\"tip\":\"新打开标签页所在的网址\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"wait_page\",\"title\":\"等待网页加载完成\",\"name\":\"wait_page\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true}],\"outputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"web_new_page\",\"title\":\"浏览器对象\",\"tip\":\"\"}],\"icon\":\"open-new-webpage\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(54,'web/web.page','BrowserSoftware.web_switch','{\"key\":\"BrowserSoftware.web_switch\",\"title\":\"切换到已存在标签页\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().web_switch\",\"comment\":\"通过 @{switch_type} 的匹配方式切换到浏览器对象 @{browser_obj} 中的指定标签页\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要等待页面所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebSwitchType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"switch_type\",\"title\":\"匹配方式\",\"name\":\"switch_type\",\"tip\":\"选择网址/标题/标签页ID的匹配方式\",\"options\":[{\"label\":\"网址\",\"value\":\"url\"},{\"label\":\"标题\",\"value\":\"title\"},{\"label\":\"标签页ID\",\"value\":\"tabId\"}],\"default\":\"url\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"tab_url\",\"title\":\"网址\",\"name\":\"tab_url\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.tab_url.show\",\"expression\":\"return $this.switch_type.value == \'url\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"tab_title\",\"title\":\"标题\",\"name\":\"tab_title\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.tab_title.show\",\"expression\":\"return $this.switch_type.value == \'title\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"tab_id\",\"title\":\"标签页ID\",\"name\":\"tab_id\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.tab_id.show\",\"expression\":\"return $this.switch_type.value == \'tabId\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"toggle_tab\",\"title\":\"切换到的标签页\",\"tip\":\"\"}],\"icon\":\"switch-existing-tab\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(55,'web/web.page','BrowserSoftware.wait_web_load','{\"key\":\"BrowserSoftware.wait_web_load\",\"title\":\"等待页面加载完成\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().wait_web_load\",\"comment\":\"等待浏览器对象 @{browser_obj} 中页面加载\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要等待页面所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"timeout\",\"title\":\"超时时间(秒)\",\"name\":\"timeout\",\"tip\":\"超过该时间停止等待\",\"default\":20,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"wait-page-load\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(56,'web/web.page','BrowserSoftware.stop_web_load','{\"key\":\"BrowserSoftware.stop_web_load\",\"title\":\"停止加载网页\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().stop_web_load\",\"comment\":\"停止加载网页 @{browser_obj}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要停止加载的网页所在浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"stop-loading-page\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(57,'web/web.page','BrowserSoftware.web_refresh','{\"key\":\"BrowserSoftware.web_refresh\",\"title\":\"刷新当前网页\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().web_refresh\",\"comment\":\"刷新当前网页 @{browser_obj}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要刷新当前网页所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"refresh-current-page\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(58,'web/web.page','BrowserSoftware.web_close','{\"key\":\"BrowserSoftware.web_close\",\"title\":\"关闭网页\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().web_close\",\"comment\":\"关闭浏览器对象 @{browser_obj} 的当前网页\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要关闭的标签页所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"url\",\"title\":\"url\",\"name\":\"url\",\"tip\":\"不填写则关闭当前标签页\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false}],\"outputList\":[],\"icon\":\"close-webpage\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(59,'web/web.page','BrowserSoftware.screenshot','{\"key\":\"BrowserSoftware.screenshot\",\"title\":\"网页截图\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().screenshot\",\"comment\":\"将浏览器对象 @{browser_obj} 截图,并保存至路径 @{web_screen}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要截图网页所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"ScreenShotForShotRangeFlag\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"shot_range\",\"title\":\"截图区域\",\"name\":\"shot_range\",\"tip\":\"选择截图的区域类型,若选择全部区域,会生成整个页面的长图\",\"options\":[{\"label\":\"可视区域\",\"value\":\"visual\"},{\"label\":\"全网页区域\",\"value\":\"all\"}],\"default\":\"visual\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"folder\"}},\"key\":\"image_path\",\"title\":\"截图保存路径\",\"name\":\"image_path\",\"tip\":\"截图保存的本地电脑文件夹路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"image_name\",\"title\":\"图片名称\",\"name\":\"image_name\",\"tip\":\"填写图片名,可以带或不带扩展名\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page_timeout\",\"title\":\"等待页面加载时间(秒)\",\"name\":\"page_timeout\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"web_screen\",\"title\":\"文件路径\",\"tip\":\"\"}],\"icon\":\"webpage-screenshot\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(60,'web/web.page','BrowserSoftware.browser_forward','{\"key\":\"BrowserSoftware.browser_forward\",\"title\":\"网页前进\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().browser_forward\",\"comment\":\"浏览器对象 @{browser_obj} 的当前网页前进\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要网页前进所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"webpage-forward\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(61,'web/web.page','BrowserSoftware.browser_back','{\"key\":\"BrowserSoftware.browser_back\",\"title\":\"网页后退\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().browser_back\",\"comment\":\"浏览器对象 @{browser_obj} 的当前网页后退\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要网页后退所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"webpage-backward\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(62,'web','BrowserSoftware.get_current_obj','{\"key\":\"BrowserSoftware.get_current_obj\",\"title\":\"获取已打开的浏览器对象\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().get_current_obj\",\"comment\":\"获取已经打开的浏览器软件 @{browser_type} 的浏览器对象,并将结果输出至 @{browser_obj}\",\"inputList\":[{\"types\":\"CommonForBrowserType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"browser_type\",\"title\":\"浏览器类型\",\"name\":\"browser_type\",\"tip\":\"选择该浏览器对象所在的浏览器类型\",\"options\":[{\"label\":\"Chrome\",\"value\":\"chrome\"},{\"label\":\"Edge\",\"value\":\"edge\"},{\"label\":\"360安全浏览器\",\"value\":\"360se\"},{\"label\":\"360极速浏览器X\",\"value\":\"360ChromeX\"},{\"label\":\"Firefox\",\"value\":\"firefox\"},{\"label\":\"内置浏览器\",\"value\":\"chromium\"}],\"default\":\"chrome\",\"required\":true}],\"outputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"tip\":\"保存获取的浏览器对象,使用此对象进行网页自动化操作\"}],\"icon\":\"get-open-browser-objects\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(63,'web/web.page','BrowserSoftware.get_current_url','{\"key\":\"BrowserSoftware.get_current_url\",\"title\":\"获取网页URL\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().get_current_url\",\"comment\":\"获取浏览器对象 @{browser_obj} 的URL值,并将结果输出至 @{get_url}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择获取页面URL所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_url\",\"title\":\"网页url\",\"tip\":\"\"}],\"icon\":\"get-webpage-url\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(64,'web/web.page','BrowserSoftware.get_current_title','{\"key\":\"BrowserSoftware.get_current_title\",\"title\":\"获取网页标题\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().get_current_title\",\"comment\":\"获取浏览器对象 @{browser_obj} 的标题,并将结果输出至 @{get_page_title}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择获取页面标题所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_page_title\",\"title\":\"网页标题\",\"tip\":\"\"}],\"icon\":\"get-webpage-title\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(65,'web/web.page','BrowserSoftware.get_current_tab_id','{\"key\":\"BrowserSoftware.get_current_tab_id\",\"title\":\"获取当前标签页ID\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().get_current_tab_id\",\"comment\":\"获取浏览器对象 @{browser_obj}当前标签页的唯一ID,并将结果输出至 @{get_tab_id}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择获取标签页ID所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_tab_id\",\"title\":\"标签页ID\",\"tip\":\"\"}],\"icon\":\"get-current-tab-id\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(66,'web/web.file','BrowserSoftware.download_web_file','{\"key\":\"BrowserSoftware.download_web_file\",\"title\":\"文件下载(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().download_web_file\",\"comment\":\"在网页中点击 @{element_data||link_str} 下载,将其保存至 @{save_path}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要点击下载的网页元素所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"拾取点击目标\",\"name\":\"element_data\",\"tip\":\"选择要点击下载的网页元素\",\"dynamics\":[{\"key\":\"$this.element_data.show\",\"expression\":\"return $this.download_mode.value == \'click\'\"}],\"required\":true,\"noInput\":true},{\"types\":\"DownloadModeForFlag\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"download_mode\",\"title\":\"下载场景\",\"name\":\"download_mode\",\"tip\":\"\",\"options\":[{\"label\":\"点击下载\",\"value\":\"click\"},{\"label\":\"链接下载\",\"value\":\"link\"}],\"default\":\"click\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"link_str\",\"title\":\"下载链接地址\",\"name\":\"link_str\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.link_str.show\",\"expression\":\"return $this.download_mode.value == \'link\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"folder\"}},\"key\":\"save_path\",\"title\":\"保存路径\",\"name\":\"save_path\",\"tip\":\"选择保存文件的文件夹路径\",\"default\":\"\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"custom_flag\",\"title\":\"自定义命名\",\"name\":\"custom_flag\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"file_name\",\"title\":\"自定义文件名\",\"name\":\"file_name\",\"tip\":\"不需要输入扩展名,系统会自动添加扩展名【系统建议打开显示扩展名】\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.file_name.show\",\"expression\":\"return $this.custom_flag.value == true\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"simulate_flag\",\"title\":\"模拟人工点击\",\"name\":\"simulate_flag\",\"tip\":\"模拟人工点击是模拟人为操作方式点击,否则将根据拾取元素的自动化接口进行点击\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"dynamics\":[{\"key\":\"$this.simulate_flag.show\",\"expression\":\"return $this.download_mode.value == \'click\'\"}],\"required\":false},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_wait\",\"title\":\"同步等待\",\"name\":\"is_wait\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"time_out\",\"title\":\"最长等待时间\",\"name\":\"time_out\",\"tip\":\"超过最长等待时间(秒)则停止等待\",\"default\":60,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.time_out.show\",\"expression\":\"return $this.is_wait.value == true\"}],\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"load_file\",\"title\":\"文档路径\",\"tip\":\"\"}],\"icon\":\"file-download-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(67,'web/web.file','BrowserSoftware.upload_web_file','{\"key\":\"BrowserSoftware.upload_web_file\",\"title\":\"文件上传(web)\",\"version\":\"1.0.0\",\"src\":\"astronverse.browser.browser_software.BrowserSoftware().upload_web_file\",\"comment\":\"在网页中点击 @{element_data} ,在弹出的文件选择对话框中输入要上传的文件路径 @{upload_path}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"选择要点击上传的网页元素所在的浏览器对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"element_data\",\"title\":\"拾取点击目标\",\"name\":\"element_data\",\"tip\":\"选择要点击上传的网页元素\",\"required\":true,\"noInput\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\"}},\"key\":\"upload_path\",\"title\":\"上传文件路径\",\"name\":\"upload_path\",\"tip\":\"待上传文件完整路径,若要选择多个文件,切换到Python模式,输入文件列表,例:[\\\"文件1路径\\\", \\\"文件2路径\\\"]\",\"default\":\"\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"simulate_flag\",\"title\":\"模拟人工点击\",\"name\":\"simulate_flag\",\"tip\":\"模拟人工点击是模拟人为操作方式点击,否则将根据拾取元素的自动化接口进行点击\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"download_file\",\"title\":\"文档路径\",\"tip\":\"\"}],\"icon\":\"file-upload-web\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(68,'code','DataProcess.set_variable_value','{\"key\":\"DataProcess.set_variable_value\",\"title\":\"设置变量值\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.data.DataProcess().set_variable_value\",\"comment\":\"赋值 @{value} 给变量 @{variable_var}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"value\",\"title\":\"变量值\",\"name\":\"value\",\"tip\":\"输入需要设置的变量值\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"VariableType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"variable_type\",\"title\":\"变量类型\",\"name\":\"variable_type\",\"tip\":\"选择需要设置的变量类型\",\"options\":[{\"label\":\"字符串\",\"value\":\"str\"},{\"label\":\"整数\",\"value\":\"int\"},{\"label\":\"浮点数\",\"value\":\"float\"},{\"label\":\"布尔值\",\"value\":\"bool\"},{\"label\":\"列表\",\"value\":\"list\"},{\"label\":\"字典\",\"value\":\"dict\"},{\"label\":\"JSON\",\"value\":\"json\"},{\"label\":\"元组\",\"value\":\"tuple\"},{\"label\":\"其他\",\"value\":\"other\"}],\"default\":\"int\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"variable_var\",\"title\":\"设置后的变量值\",\"tip\":\"\",\"dynamics\":[{\"key\":\"$this.variable_var.types\",\"expression\":\"return [\'int\',\'str\', \'float\', \'bool\', \'list\', \'dict\'].includes($this.variable_type.value) ? $this.variable_type.value[0].toUpperCase() + $this.variable_type.value.slice(1) : \'Any\'\"}]}],\"icon\":\"set-variable-value\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(69,'data/data.String','DataConvertProcess.json_convertor','{\"key\":\"DataConvertProcess.json_convertor\",\"title\":\"JSON字符串互转\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.dataconvert.DataConvertProcess().json_convertor\",\"comment\":\"将输入文本 @{input_data} 从JSON格式转换为字符串或从字符串格式转换为JSON格式,返回转换后的文本 @{json_convert_data}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"input_data\",\"title\":\"输入内容\",\"name\":\"input_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"JSONConvertType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"convert_type\",\"title\":\"转换类型\",\"name\":\"convert_type\",\"tip\":\"\",\"options\":[{\"label\":\"JSON转字符串\",\"value\":\"json_to_str\"},{\"label\":\"字符串转JSON\",\"value\":\"str_to_json\"}],\"default\":\"json_to_str\",\"required\":true}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"json_convert_data\",\"title\":\"转换结果\",\"tip\":\"\"}],\"icon\":\"json-string-convert\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(70,'data/data.String','DataConvertProcess.other_to_str','{\"key\":\"DataConvertProcess.other_to_str\",\"title\":\"其他格式转文本\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.dataconvert.DataConvertProcess().other_to_str\",\"comment\":\"将输入内容 @{input_data} 转换为文本(字符串)格式,返回转换后的结果 @{other_convert_str}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"input_data\",\"title\":\"输入内容\",\"name\":\"input_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"other_convert_str\",\"title\":\"转换结果\",\"tip\":\"\"}],\"icon\":\"format-to-text\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(71,'data/data.String','DataConvertProcess.str_to_other','{\"key\":\"DataConvertProcess.str_to_other\",\"title\":\"文本转其他格式\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.dataconvert.DataConvertProcess().str_to_other\",\"comment\":\"将输入文本(字符串) @{input_data} 转换为其他格式,返回转换后的结果 @{str_convert_other}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"input_data\",\"title\":\"输入内容\",\"name\":\"input_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"StringConvertType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"convert_type\",\"title\":\"转换类型\",\"name\":\"convert_type\",\"tip\":\"\",\"options\":[{\"label\":\"字符串转列表\",\"value\":\"str_to_list\"},{\"label\":\"字符串转字典\",\"value\":\"str_to_dict\"},{\"label\":\"字符串转元组\",\"value\":\"str_to_tuple\"},{\"label\":\"字符串转布尔值\",\"value\":\"str_to_bool\"},{\"label\":\"字符串转整数\",\"value\":\"str_to_int\"},{\"label\":\"字符串转浮点数\",\"value\":\"str_to_float\"}],\"default\":\"str_to_int\",\"required\":true}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"str_convert_other\",\"title\":\"转换结果\",\"tip\":\"\"}],\"icon\":\"text-convert-format\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(72,'data/data.Dict','DictProcess.create_new_dict','{\"key\":\"DictProcess.create_new_dict\",\"title\":\"创建新字典\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.dict.DictProcess().create_new_dict\",\"comment\":\"创建一个字典,返回创建的字典 @{created_new_dict_data}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dict_data\",\"title\":\"字典数据\",\"name\":\"dict_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false}],\"outputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"created_new_dict_data\",\"title\":\"新创建的字典\",\"tip\":\"\"}],\"icon\":\"create-new-dict\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(73,'data/data.Dict','DictProcess.set_value_to_dict','{\"key\":\"DictProcess.set_value_to_dict\",\"title\":\"字典设置值\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.dict.DictProcess().set_value_to_dict\",\"comment\":\"设置字典 @{dict_data} 的键为 @{dict_key} ,值为 @{value} ,返回设置后的字典 @{inserted_dict_data}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dict_data\",\"title\":\"字典数据\",\"name\":\"dict_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dict_key\",\"title\":\"键(key)\",\"name\":\"dict_key\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"value\",\"title\":\"值(value)\",\"name\":\"value\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false}],\"outputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"inserted_dict_data\",\"title\":\"设置后的字典\",\"tip\":\"\"}],\"icon\":\"dict-set-value\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(74,'data/data.Dict','DictProcess.delete_value_from_dict','{\"key\":\"DictProcess.delete_value_from_dict\",\"title\":\"字典删除值\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.dict.DictProcess().delete_value_from_dict\",\"comment\":\"从字典 @{dict_data} 中删除键为 @{dict_key} 的值,返回删除后的字典 @{deleted_dict_data}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dict_data\",\"title\":\"字典数据\",\"name\":\"dict_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dict_key\",\"title\":\"键(key)\",\"name\":\"dict_key\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"deleted_dict_data\",\"title\":\"删除后的字典\",\"tip\":\"\"}],\"icon\":\"dict-delete-value\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(75,'data/data.Dict','DictProcess.get_value_from_dict','{\"key\":\"DictProcess.get_value_from_dict\",\"title\":\"字典获取值\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.dict.DictProcess().get_value_from_dict\",\"comment\":\"获取字典 @{dict_data} 的键为 @{dict_key} 的值 @{get_dict_value}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dict_data\",\"title\":\"字典数据\",\"name\":\"dict_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dict_key\",\"title\":\"键(key)\",\"name\":\"dict_key\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"NoKeyOptionType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"fail_option\",\"title\":\"键不存在时处理方式\",\"name\":\"fail_option\",\"tip\":\"键不存在时是否抛出异常或返回默认值\",\"options\":[{\"label\":\"抛出异常\",\"value\":\"raise_error\"},{\"label\":\"返回默认值\",\"value\":\"return_default\"}],\"default\":\"raise_error\",\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"default_value\",\"title\":\"默认值\",\"name\":\"default_value\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.default_value.show\",\"expression\":\"return $this.fail_option.value == \'return_default\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_dict_value\",\"title\":\"字典值\",\"tip\":\"\"}],\"icon\":\"dict-get-value\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(76,'data/data.Dict','DictProcess.get_keys_from_dict','{\"key\":\"DictProcess.get_keys_from_dict\",\"title\":\"获取字典所有键\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.dict.DictProcess().get_keys_from_dict\",\"comment\":\"获取字典 @{dict_data} 的所有键 @{get_dict_keys}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dict_data\",\"title\":\"字典数据\",\"name\":\"dict_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_dict_keys\",\"title\":\"键列表\",\"tip\":\"\"}],\"icon\":\"get-dict-all-keys\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(77,'data/data.Dict','DictProcess.get_values_from_dict','{\"key\":\"DictProcess.get_values_from_dict\",\"title\":\"获取字典所有值\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.dict.DictProcess().get_values_from_dict\",\"comment\":\"获取字典 @{dict_data} 的所有值 @{get_dict_values}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dict_data\",\"title\":\"字典数据\",\"name\":\"dict_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_dict_values\",\"title\":\"值列表\",\"tip\":\"\"}],\"icon\":\"get-dict-all-values\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(78,'data/data.List','ListProcess.create_new_list','{\"key\":\"ListProcess.create_new_list\",\"title\":\"创建新列表\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.list.ListProcess().create_new_list\",\"comment\":\"创建一个 @{list_type} 类型的列表,返回创建的列表 @{created_list_data}\",\"inputList\":[{\"types\":\"ListType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"list_type\",\"title\":\"列表类型\",\"name\":\"list_type\",\"tip\":\"\",\"options\":[{\"label\":\"空列表\",\"value\":\"empty\"},{\"label\":\"相同元素列表\",\"value\":\"same_data\"},{\"label\":\"用户自定义列表\",\"value\":\"user_defined\"}],\"default\":\"empty\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"size\",\"title\":\"列表长度\",\"name\":\"size\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.size.show\",\"expression\":\"return $this.list_type.value == \'same_data\'\"}],\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"value\",\"title\":\"初始值\",\"name\":\"value\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.value.show\",\"expression\":\"return [\'same_data\', \'user_defined\'].includes($this.list_type.value)\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"created_list_data\",\"title\":\"创建的列表\",\"tip\":\"\"}],\"icon\":\"create-new-list\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(79,'data/data.List','ListProcess.clear_list','{\"key\":\"ListProcess.clear_list\",\"title\":\"清空列表\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.list.ListProcess().clear_list\",\"comment\":\"清空列表 @{list_data} ,返回清空后的列表 @{cleared_list_data}\",\"inputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data\",\"title\":\"列表数据\",\"name\":\"list_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"cleared_list_data\",\"title\":\"清空后的列表\",\"tip\":\"\"}],\"icon\":\"list-clear\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(80,'data/data.List','ListProcess.insert_value_to_list','{\"key\":\"ListProcess.insert_value_to_list\",\"title\":\"列表插入值\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.list.ListProcess().insert_value_to_list\",\"comment\":\"将值 @{value} 插入到列表 @{list_data} 的 @{insert_method} 位置 @{index} ,返回插入后的列表 @{inserted_list_data}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data\",\"title\":\"列表数据\",\"name\":\"list_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"value\",\"title\":\"插入值\",\"name\":\"value\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"InsertMethodType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"insert_method\",\"title\":\"插入方式\",\"name\":\"insert_method\",\"tip\":\"\",\"options\":[{\"label\":\"追加\",\"value\":\"append\"},{\"label\":\"指定位置插入\",\"value\":\"index\"}],\"default\":\"append\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"index\",\"title\":\"插入位置\",\"name\":\"index\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.index.show\",\"expression\":\"return $this.insert_method.value == \'index\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"inserted_list_data\",\"title\":\"插入后的列表\",\"tip\":\"\"}],\"icon\":\"list-insert-value\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(81,'data/data.List','ListProcess.change_value_in_list','{\"key\":\"ListProcess.change_value_in_list\",\"title\":\"列表修改值\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.list.ListProcess().change_value_in_list\",\"comment\":\"将列表 @{list_data} 的 @{index} 位置的值修改为 @{new_value} ,返回修改后的列表 @{changed_list_data}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data\",\"title\":\"列表数据\",\"name\":\"list_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"index\",\"title\":\"位置索引\",\"name\":\"index\",\"tip\":\"填写需要修改值的位置索引,从0开始,修改第一个值索引为0,修改第二个值索引为1,以此类推\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"new_value\",\"title\":\"新值\",\"name\":\"new_value\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"changed_list_data\",\"title\":\"修改后的列表\",\"tip\":\"\"}],\"icon\":\"list-modify-value\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(82,'data/data.List','ListProcess.get_list_position','{\"key\":\"ListProcess.get_list_position\",\"title\":\"获取值在列表位置\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.list.ListProcess().get_list_position\",\"comment\":\"获取值 @{value} 在列表 @{list_data} 的位置 @{get_list_position}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data\",\"title\":\"列表数据\",\"name\":\"list_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"value\",\"title\":\"值\",\"name\":\"value\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_list_position\",\"title\":\"位置索引\",\"tip\":\"\"}],\"icon\":\"get-value-position\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(83,'data/data.List','ListProcess.remove_value_from_list','{\"key\":\"ListProcess.remove_value_from_list\",\"title\":\"列表删除值\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.list.ListProcess().remove_value_from_list\",\"comment\":\"以 @{del_mode} 删除@{list_data}@{del_value||del_pos}的内容,返回删除后的列表 @{removed_list_data}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data\",\"title\":\"列表数据\",\"name\":\"list_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"DeleteMethodType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"del_mode\",\"title\":\"删除方式\",\"name\":\"del_mode\",\"tip\":\"\",\"options\":[{\"label\":\"指定位置删除\",\"value\":\"index\"},{\"label\":\"指定值删除\",\"value\":\"value\"}],\"default\":\"index\",\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"del_value\",\"title\":\"删除值\",\"name\":\"del_value\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.del_value.show\",\"expression\":\"return $this.del_mode.value == \'value\'\"}],\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"del_pos\",\"title\":\"删除位置\",\"name\":\"del_pos\",\"tip\":\"可指定单个或多个位置数据,多个位置索引之间用逗号隔开,如:1,3,5\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.del_pos.show\",\"expression\":\"return $this.del_mode.value == \'index\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"removed_list_data\",\"title\":\"删除后的列表\",\"tip\":\"\"}],\"icon\":\"list-remove-value\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(84,'data/data.List','ListProcess.sort_list','{\"key\":\"ListProcess.sort_list\",\"title\":\"列表排序\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.list.ListProcess().sort_list\",\"comment\":\"对列表 @{list_data} 进行 @{sort_method} 排序,返回排序后的列表 @{sorted_list_data}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data\",\"title\":\"列表数据\",\"name\":\"list_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"SortMethodType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"sort_method\",\"title\":\"排序方式\",\"name\":\"sort_method\",\"tip\":\"\",\"options\":[{\"label\":\"升序\",\"value\":\"asc\"},{\"label\":\"降序\",\"value\":\"desc\"}],\"default\":\"desc\",\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"sorted_list_data\",\"title\":\"排序后的列表\",\"tip\":\"\"}],\"icon\":\"list-sort\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(85,'data/data.List','ListProcess.random_shuffle_list','{\"key\":\"ListProcess.random_shuffle_list\",\"title\":\"列表随机打乱顺序\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.list.ListProcess().random_shuffle_list\",\"comment\":\"对列表 @{list_data} 进行随机打乱顺序,返回打乱顺序后的列表 @{shuffled_list_data}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data\",\"title\":\"列表数据\",\"name\":\"list_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"shuffled_list_data\",\"title\":\"打乱顺序后的列表\",\"tip\":\"\"}],\"icon\":\"list-shuffle\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(86,'data/data.List','ListProcess.filter_elements_from_list','{\"key\":\"ListProcess.filter_elements_from_list\",\"title\":\"剔除列表中的多项\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.list.ListProcess().filter_elements_from_list\",\"comment\":\"从列表 @{list_data_1} 中剔除列表 @{list_data_2} 中的元素,返回剔除后的列表 @{filter_list_data}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data_1\",\"title\":\"待处理列表\",\"name\":\"list_data_1\",\"tip\":\"填写需要处理的列表\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data_2\",\"title\":\"剔除元素列表\",\"name\":\"list_data_2\",\"tip\":\"填写需要剔除的元素列表,如果待处理列表中有剔除元素列表中的元素,则剔除\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"filter_list_data\",\"title\":\"剔除后的列表\",\"tip\":\"返回剔除后的列表\"}],\"icon\":\"list-remove-multiple\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(87,'data/data.List','ListProcess.reverse_list','{\"key\":\"ListProcess.reverse_list\",\"title\":\"列表反转\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.list.ListProcess().reverse_list\",\"comment\":\"将列表 @{list_data} 反转,返回反转后的列表 @{reversed_list_data}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data\",\"title\":\"列表数据\",\"name\":\"list_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"reversed_list_data\",\"title\":\"反转后的列表\",\"tip\":\"\"}],\"icon\":\"list-reverse\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(88,'data/data.List','ListProcess.merge_list','{\"key\":\"ListProcess.merge_list\",\"title\":\"列表合并\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.list.ListProcess().merge_list\",\"comment\":\"将列表 @{list_data_1} 和列表 @{list_data_2} 合并为一个列表 @{merged_list_data}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data_1\",\"title\":\"第一个列表\",\"name\":\"list_data_1\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data_2\",\"title\":\"第二个列表\",\"name\":\"list_data_2\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"merged_list_data\",\"title\":\"合并后的列表\",\"tip\":\"\"}],\"icon\":\"list-merge\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(89,'data/data.List','ListProcess.get_unique_list','{\"key\":\"ListProcess.get_unique_list\",\"title\":\"列表去重\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.list.ListProcess().get_unique_list\",\"comment\":\"将列表 @{list_data} 去重,返回去重后的列表 @{unique_list_data}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data\",\"title\":\"列表数据\",\"name\":\"list_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"unique_list_data\",\"title\":\"去重后的列表\",\"tip\":\"\"}],\"icon\":\"list-remove-duplicates\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(90,'data/data.List','ListProcess.get_common_elements_from_list','{\"key\":\"ListProcess.get_common_elements_from_list\",\"title\":\"获取两个列表的重复项\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.list.ListProcess().get_common_elements_from_list\",\"comment\":\"获取列表 @{list_data_1} 和列表 @{list_data_2} 的重复项,返回重复项列表 @{common_list_data}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data_1\",\"title\":\"第一个列表\",\"name\":\"list_data_1\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data_2\",\"title\":\"第二个列表\",\"name\":\"list_data_2\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"common_list_data\",\"title\":\"重复项列表\",\"tip\":\"\"}],\"icon\":\"get-list-duplicates\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(91,'data/data.List','ListProcess.get_value_from_list','{\"key\":\"ListProcess.get_value_from_list\",\"title\":\"根据索引获取列表值\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.list.ListProcess().get_value_from_list\",\"comment\":\"根据索引 @{index} 获取列表 @{list_data} 的值 @{get_list_value}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data\",\"title\":\"列表数据\",\"name\":\"list_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"index\",\"title\":\"索引\",\"name\":\"index\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_list_value\",\"title\":\"值\",\"tip\":\"\"}],\"icon\":\"get-list-value-by-index\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(92,'data/data.List','ListProcess.get_length_of_list','{\"key\":\"ListProcess.get_length_of_list\",\"title\":\"获取列表长度\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.list.ListProcess().get_length_of_list\",\"comment\":\"获取列表 @{list_data} 的长度 @{get_list_length}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data\",\"title\":\"列表数据\",\"name\":\"list_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_list_length\",\"title\":\"长度\",\"tip\":\"\"}],\"icon\":\"get-list-length\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(93,'data/data.Math','MathProcess.generate_random_number','{\"key\":\"MathProcess.generate_random_number\",\"title\":\"生成随机数\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.math.MathProcess().generate_random_number\",\"comment\":\"生成 @{number_type} 类型 @{size} 个随机数,范围为 @{start} 到 @{end} ,返回生成的随机数 @{generated_random_numbers}\",\"inputList\":[{\"types\":\"NumberType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"number_type\",\"title\":\"随机数类型\",\"name\":\"number_type\",\"tip\":\"\",\"options\":[{\"label\":\"整数\",\"value\":\"integer\"},{\"label\":\"浮点数\",\"value\":\"float\"}],\"default\":\"integer\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"size\",\"title\":\"随机数个数\",\"name\":\"size\",\"tip\":\"\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"start\",\"title\":\"开始范围\",\"name\":\"start\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"end\",\"title\":\"结束范围\",\"name\":\"end\",\"tip\":\"\",\"default\":101,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"generated_random_numbers\",\"title\":\"生成的随机数\",\"tip\":\"\"}],\"icon\":\"generate-random-number\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(94,'data/data.Math','MathProcess.get_rounding_number','{\"key\":\"MathProcess.get_rounding_number\",\"title\":\"四舍五入\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.math.MathProcess().get_rounding_number\",\"comment\":\"将数字 @{number} 四舍五入 @{precision} 位,返回四舍五入后的数字 @{rounding_number}\",\"inputList\":[{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"number\",\"title\":\"原有数据\",\"name\":\"number\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"precision\",\"title\":\"精度\",\"name\":\"precision\",\"tip\":\"可填写小数位数,如填写2,则四舍五入到小数点后2位;也支持填写负数和0,如填写-2,则四舍五入到小数点前2位。\",\"default\":2,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"rounding_number\",\"title\":\"四舍五入后的数字\",\"tip\":\"\"}],\"icon\":\"round-number\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(95,'data/data.Math','MathProcess.self_calculation_number','{\"key\":\"MathProcess.self_calculation_number\",\"title\":\"自增自减\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.math.MathProcess().self_calculation_number\",\"comment\":\"对数字 @{number} 自增或自减 @{add_sub_number} ,返回计算后的结果 @{self_calculation_number}\",\"inputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"number\",\"title\":\"原数据\",\"name\":\"number\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"AddSubType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"add_sub\",\"title\":\"自增/自减\",\"name\":\"add_sub\",\"tip\":\"选择是自增还是自减\",\"options\":[{\"label\":\"加\",\"value\":\"add\"},{\"label\":\"减\",\"value\":\"sub\"}],\"default\":\"add\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"add_sub_number\",\"title\":\"自增或自减的数字\",\"name\":\"add_sub_number\",\"tip\":\"\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"self_calculation_number\",\"title\":\"自增自减后的结果\",\"tip\":\"\"}],\"icon\":\"increment-decrement\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(96,'data/data.Math','MathProcess.get_absolute_number','{\"key\":\"MathProcess.get_absolute_number\",\"title\":\"获取绝对值\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.math.MathProcess().get_absolute_number\",\"comment\":\"获取数字 @{raw_number} 的绝对值 @{absolute_number}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"raw_number\",\"title\":\"原数据\",\"name\":\"raw_number\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"absolute_number\",\"title\":\"原数据绝对值\",\"tip\":\"\"}],\"icon\":\"get-absolute-value\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(97,'data/data.Math','MathProcess.calculate_expression','{\"key\":\"MathProcess.calculate_expression\",\"title\":\"数学计算\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.math.MathProcess().calculate_expression\",\"comment\":\"进行基本的数学计算 @{left} @{operator} @{right} ,返回计算结果 @{calculation_number}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"left\",\"title\":\"运算符左侧值\",\"name\":\"left\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"MathOperatorType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"operator\",\"title\":\"运算符\",\"name\":\"operator\",\"tip\":\"\",\"options\":[{\"label\":\"加\",\"value\":\"+\"},{\"label\":\"减\",\"value\":\"-\"},{\"label\":\"乘\",\"value\":\"*\"},{\"label\":\"除\",\"value\":\"/\"}],\"default\":\"+\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"right\",\"title\":\"运算符右侧值\",\"name\":\"right\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"MathRoundType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"handle_method\",\"title\":\"返回值处理方式\",\"name\":\"handle_method\",\"tip\":\"\",\"options\":[{\"label\":\"四舍五入\",\"value\":\"round\"},{\"label\":\"向上取整\",\"value\":\"ceil\"},{\"label\":\"向下取整\",\"value\":\"floor\"},{\"label\":\"不做操作\",\"value\":\"none\"}],\"default\":\"none\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"precision\",\"title\":\"四舍五入保留位数\",\"name\":\"precision\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.precision.show\",\"expression\":\"return $this.handle_method.value == \'round\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"calculation_number\",\"title\":\"计算结果\",\"tip\":\"\"}],\"icon\":\"math-calculation\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(98,'data/data.String','StringProcess.extract_content_from_string','{\"key\":\"StringProcess.extract_content_from_string\",\"title\":\"文本提取内容\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.string.StringProcess().extract_content_from_string\",\"comment\":\"从文本 @{text} 中提取 @{extract_type} 类型的内容\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"text\",\"title\":\"原文本\",\"name\":\"text\",\"tip\":\"输入需要提取内容的文本\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"ExtractType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"extract_type\",\"title\":\"提取类型\",\"name\":\"extract_type\",\"tip\":\"选择需要提取的类型\",\"options\":[{\"label\":\"中国大陆手机号码\",\"value\":\"phone_number\"},{\"label\":\"邮箱地址\",\"value\":\"email\"},{\"label\":\"网址\",\"value\":\"url\"},{\"label\":\"数字\",\"value\":\"digit\"},{\"label\":\"中国大陆身份证号码\",\"value\":\"id_number\"},{\"label\":\"正则表达式\",\"value\":\"regex\"}],\"default\":\"digit\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"regex_formula\",\"title\":\"正则表达式\",\"name\":\"regex_formula\",\"tip\":\"输入正则表达式,例如[\\\\u4e00-\\\\u9fff]用于提取中文,\\\\d用于提取数字,[a-zA-Z]用于提取英文等\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.regex_formula.show\",\"expression\":\"return $this.extract_type.value == \'regex\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"first_flag\",\"title\":\"仅提取第一项匹配内容\",\"name\":\"first_flag\",\"tip\":\"是否仅提取第一项匹配内容\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"extract_from_string\",\"title\":\"提取内容\",\"tip\":\"返回提取的内容\"}],\"icon\":\"text-extract-content\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(99,'data/data.String','StringProcess.replace_content_in_string','{\"key\":\"StringProcess.replace_content_in_string\",\"title\":\"文本替换内容\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.string.StringProcess().replace_content_in_string\",\"comment\":\"将文本 @{text} 中的 @{replace_type} 类型内容替换为 @{new_value}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"text\",\"title\":\"原文本\",\"name\":\"text\",\"tip\":\"输入需要替换内容的文本\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"ReplaceType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"replace_type\",\"title\":\"替换类型\",\"name\":\"replace_type\",\"tip\":\"选择需要替换的类型\",\"options\":[{\"label\":\"字符串\",\"value\":\"string\"},{\"label\":\"中国大陆手机号码\",\"value\":\"phone_number\"},{\"label\":\"邮箱地址\",\"value\":\"email\"},{\"label\":\"网址\",\"value\":\"url\"},{\"label\":\"数字\",\"value\":\"digit\"},{\"label\":\"中国大陆身份证号码\",\"value\":\"id_number\"},{\"label\":\"正则表达式\",\"value\":\"regex\"}],\"default\":\"string\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"replaced_string\",\"title\":\"需要替换的字符串\",\"name\":\"replaced_string\",\"tip\":\"输入需要替换的字符串\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.replaced_string.show\",\"expression\":\"return $this.replace_type.value == \'string\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"regex_formula\",\"title\":\"用正则表达式替换\",\"name\":\"regex_formula\",\"tip\":\"输入正则表达式用于替换内容\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.regex_formula.show\",\"expression\":\"return $this.replace_type.value == \'regex\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"new_value\",\"title\":\"替换为\",\"name\":\"new_value\",\"tip\":\"输入新值\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"first_flag\",\"title\":\"仅替换第一项匹配内容\",\"name\":\"first_flag\",\"tip\":\"是否仅替换第一项匹配内容\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"ignore_case_flag\",\"title\":\"忽略大小写\",\"name\":\"ignore_case_flag\",\"tip\":\"是否忽略大小写\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"replaced_content_string\",\"title\":\"替换后的文本\",\"tip\":\"返回替换后的文本\"}],\"icon\":\"text-replace-content\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(100,'data/data.String','StringProcess.merge_list_to_string','{\"key\":\"StringProcess.merge_list_to_string\",\"title\":\"列表聚合为文本\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.string.StringProcess().merge_list_to_string\",\"comment\":\"将列表 @{list_data} 中的内容聚合为文本 @{merged_string_from_list}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list_data\",\"title\":\"列表数据\",\"name\":\"list_data\",\"tip\":\"输入需要聚合的列表数据\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"separator\",\"title\":\"分隔符\",\"name\":\"separator\",\"tip\":\"输入分隔符\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"merged_string_from_list\",\"title\":\"聚合后的文本\",\"tip\":\"返回聚合后的文本\"}],\"icon\":\"list-to-text\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(101,'data/data.String','StringProcess.split_string_to_list','{\"key\":\"StringProcess.split_string_to_list\",\"title\":\"文本分割为列表\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.string.StringProcess().split_string_to_list\",\"comment\":\"将文本 @{string_data} 按 @{separator} 分割为列表 @{split_list_from_string}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"string_data\",\"title\":\"文本数据\",\"name\":\"string_data\",\"tip\":\"输入需要分割的文本数据\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"separator\",\"title\":\"分隔符\",\"name\":\"separator\",\"tip\":\"输入分隔符\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"split_list_from_string\",\"title\":\"分割后的列表\",\"tip\":\"返回分割后的列表\"}],\"icon\":\"text-split-to-list\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(102,'data/data.String','StringProcess.concatenate_string','{\"key\":\"StringProcess.concatenate_string\",\"title\":\"文本合并\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.string.StringProcess().concatenate_string\",\"comment\":\"将 @{string_data_1} 和 @{string_data_2} 合并为 @{concat_string}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"string_data_1\",\"title\":\"第一个文本\",\"name\":\"string_data_1\",\"tip\":\"输入需要合并的第一个文本\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"string_data_2\",\"title\":\"第二个文本\",\"name\":\"string_data_2\",\"tip\":\"输入需要合并的第二个文本\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"ConcatStringType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"concat_type\",\"title\":\"合并类型\",\"name\":\"concat_type\",\"tip\":\"选择需要合并的类型,可以自定义分隔符\",\"options\":[{\"label\":\"不使用分隔符\",\"value\":\"none\"},{\"label\":\"换行符\",\"value\":\"linebreak\"},{\"label\":\"空格( )\",\"value\":\"space\"},{\"label\":\"连字符(-)\",\"value\":\"hyphen\"},{\"label\":\"下划线(_)\",\"value\":\"underline\"},{\"label\":\"自定义\",\"value\":\"other\"}],\"default\":\"none\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"separator\",\"title\":\"分隔符\",\"name\":\"separator\",\"tip\":\"输入分隔符\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.separator.show\",\"expression\":\"return $this.concat_type.value == \'other\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"concat_string\",\"title\":\"合并后的文本\",\"tip\":\"返回合并后的文本\"}],\"icon\":\"text-merge\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(103,'data/data.String','StringProcess.fill_string_to_length','{\"key\":\"StringProcess.fill_string_to_length\",\"title\":\"文本补齐至固定长度\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.string.StringProcess().fill_string_to_length\",\"comment\":\"将文本 @{string_data} 补齐至 @{total_length} 长度,补齐方式为 @{fill_type}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"string_data\",\"title\":\"文本数据\",\"name\":\"string_data\",\"tip\":\"输入需要补齐的文本数据\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"add_str\",\"title\":\"补齐字符\",\"name\":\"add_str\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"total_length\",\"title\":\"总长度\",\"name\":\"total_length\",\"tip\":\"输入需要补齐的总长度\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"FillStringType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"fill_type\",\"title\":\"补齐方式\",\"name\":\"fill_type\",\"tip\":\"选择补齐方式,可以选择左补齐、右补齐\",\"options\":[{\"label\":\"右补齐\",\"value\":\"right\"},{\"label\":\"左补齐\",\"value\":\"left\"}],\"default\":\"right\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"complete_string\",\"title\":\"补齐后的文本\",\"tip\":\"\"}],\"icon\":\"text-pad-to-length\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(104,'data/data.String','StringProcess.strip_string','{\"key\":\"StringProcess.strip_string\",\"title\":\"文本去除两侧空格\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.string.StringProcess().strip_string\",\"comment\":\"将文本 @{string_data} 两侧的空格去除 @{stripped_string}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"string_data\",\"title\":\"文本数据\",\"name\":\"string_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"StripStringType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"strip_method\",\"title\":\"去除方式\",\"name\":\"strip_method\",\"tip\":\"\",\"options\":[{\"label\":\"左侧\",\"value\":\"left\"},{\"label\":\"右侧\",\"value\":\"right\"},{\"label\":\"两侧\",\"value\":\"both\"}],\"default\":\"both\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"stripped_string\",\"title\":\"去除两侧空格后的文本\",\"tip\":\"\"}],\"icon\":\"text-trim-spaces\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(105,'data/data.String','StringProcess.cut_string_to_length','{\"key\":\"StringProcess.cut_string_to_length\",\"title\":\"截取固定长度文本\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.string.StringProcess().cut_string_to_length\",\"comment\":\"将文本 @{string_data} 截取 @{length} 长度,截取方式为 @{cut_type} ,返回截取后的文本 @{cut_string}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"string_data\",\"title\":\"截取文本\",\"name\":\"string_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"length\",\"title\":\"截取长度\",\"name\":\"length\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"CutStringType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"cut_type\",\"title\":\"截取类型\",\"name\":\"cut_type\",\"tip\":\"\",\"options\":[{\"label\":\"从第一个字符开始截取\",\"value\":\"first\"},{\"label\":\"从指定位置开始截取\",\"value\":\"index\"},{\"label\":\"从指定字符串开始截取\",\"value\":\"string\"}],\"default\":\"first\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"index\",\"title\":\"从第几个字符开始截取\",\"name\":\"index\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.index.show\",\"expression\":\"return $this.cut_type.value == \'index\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"find_str\",\"title\":\"需要检索的字符串\",\"name\":\"find_str\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.find_str.show\",\"expression\":\"return $this.cut_type.value == \'string\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"cut_string\",\"title\":\"截取后的文本\",\"tip\":\"\"}],\"icon\":\"screenshot-fixed-text\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(106,'data/data.String','StringProcess.change_case_of_string','{\"key\":\"StringProcess.change_case_of_string\",\"title\":\"更改文本大小写\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.string.StringProcess().change_case_of_string\",\"comment\":\"将文本 @{string_data} 的大小写更改为 @{case_type} ,返回更改后的文本 @{change_case_string}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"string_data\",\"title\":\"文本数据\",\"name\":\"string_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"CaseChangeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"case_type\",\"title\":\"大小写类型\",\"name\":\"case_type\",\"tip\":\"\",\"options\":[{\"label\":\"全部大写\",\"value\":\"upper\"},{\"label\":\"全部小写\",\"value\":\"lower\"},{\"label\":\"首字母大写\",\"value\":\"caps\"}],\"default\":\"lower\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"change_case_string\",\"title\":\"更改后的文本\",\"tip\":\"\"}],\"icon\":\"change-text-case\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(107,'data/data.String','StringProcess.get_string_length','{\"key\":\"StringProcess.get_string_length\",\"title\":\"获取文本长度\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.string.StringProcess().get_string_length\",\"comment\":\"获取文本 @{string_data} 的长度 @{string_length}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"string_data\",\"title\":\"文本数据\",\"name\":\"string_data\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"string_length\",\"title\":\"文本长度\",\"tip\":\"\"}],\"icon\":\"get-text-length\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(108,'data/data.Time','TimeProcess.get_current_time','{\"key\":\"TimeProcess.get_current_time\",\"title\":\"获取当前时间\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.time.TimeProcess().get_current_time\",\"comment\":\"获取当前时间,格式为 @{time_format},返回当前时间对象 @{current_time}\",\"inputList\":[{\"types\":\"TimeFormatType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"time_format\",\"title\":\"时间格式\",\"name\":\"time_format\",\"tip\":\"\",\"options\":[{\"label\":\"年-月-日\",\"value\":\"%Y-%m-%d\"},{\"label\":\"年-月-日 时:分:秒\",\"value\":\"%Y-%m-%d %H:%M:%S\"},{\"label\":\"年-月-日 时:分\",\"value\":\"%Y-%m-%d %H:%M\"},{\"label\":\"年/月/日\",\"value\":\"%Y/%m/%d\"},{\"label\":\"年/月/日 时:分\",\"value\":\"%Y/%m/%d %H:%M\"},{\"label\":\"年/月/日 时:分:秒\",\"value\":\"%Y/%m/%d %H:%M:%S\"},{\"label\":\"年月日\",\"value\":\"%Y%m%d\"},{\"label\":\"时:分\",\"value\":\"%H:%M\"},{\"label\":\"时:分:秒\",\"value\":\"%H:%M:%S\"},{\"label\":\"一周的第几天\",\"value\":\"%w\"},{\"label\":\"一年的第几天\",\"value\":\"%j\"},{\"label\":\"一年的第几周\",\"value\":\"%W\"},{\"label\":\"XXXX年XX月XX日\",\"value\":\"%Y年%m月%d日\"},{\"label\":\"XXXX年XX月XX日 XX:XX\",\"value\":\"%Y年%m月%d日 %H:%M\"},{\"label\":\"XXXX年XX月XX日 XX:XX:XX\",\"value\":\"%Y年%m月%d日 %H:%M:%S\"}],\"default\":\"%Y-%m-%d %H:%M:%S\",\"required\":true}],\"outputList\":[{\"types\":\"Date\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"current_time\",\"title\":\"当前时间对象\",\"tip\":\"返回值为时间对象,可通过快捷函数或转化原子能力输出字符串形式\"}],\"icon\":\"get-current-time\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(109,'data/data.Time','TimeProcess.set_time','{\"key\":\"TimeProcess.set_time\",\"title\":\"设置时间\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.time.TimeProcess().set_time\",\"comment\":\"设置时间 @{time},设置方式为 @{change_type},返回设置后的时间对象 @{set_time}\",\"inputList\":[{\"types\":\"Date\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_DATETIME\"},\"key\":\"time\",\"title\":\"时间对象\",\"name\":\"time\",\"tip\":\"\",\"required\":true},{\"types\":\"TimeChangeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"change_type\",\"title\":\"日期调整方式\",\"name\":\"change_type\",\"tip\":\"\",\"options\":[{\"label\":\"保持不变\",\"value\":\"maintain\"},{\"label\":\"增加时间\",\"value\":\"add\"},{\"label\":\"减少时间\",\"value\":\"sub\"}],\"default\":\"maintain\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"seconds\",\"title\":\"秒\",\"name\":\"seconds\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.seconds.show\",\"expression\":\"return $this.change_type.value != \'maintain\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"minutes\",\"title\":\"分\",\"name\":\"minutes\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.minutes.show\",\"expression\":\"return $this.change_type.value != \'maintain\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"hours\",\"title\":\"时\",\"name\":\"hours\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.hours.show\",\"expression\":\"return $this.change_type.value != \'maintain\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"days\",\"title\":\"天\",\"name\":\"days\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.days.show\",\"expression\":\"return $this.change_type.value != \'maintain\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"months\",\"title\":\"月\",\"name\":\"months\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.months.show\",\"expression\":\"return $this.change_type.value != \'maintain\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"years\",\"title\":\"年\",\"name\":\"years\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.years.show\",\"expression\":\"return $this.change_type.value != \'maintain\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"Date\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"set_time\",\"title\":\"设置时间对象\",\"tip\":\"\"}],\"icon\":\"set-time\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(110,'data/data.Time','TimeProcess.time_to_timestamp','{\"key\":\"TimeProcess.time_to_timestamp\",\"title\":\"时间对象转时间戳\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.time.TimeProcess().time_to_timestamp\",\"comment\":\"将时间对象 @{time} 转换为 @{timestamp_unit} 精度的时间戳,返回转换后的时间戳 @{converted_timestamp}\",\"inputList\":[{\"types\":\"Date\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_DATETIME\"},\"key\":\"time\",\"title\":\"时间对象\",\"name\":\"time\",\"tip\":\"\",\"required\":true},{\"types\":\"TimestampUnitType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"timestamp_unit\",\"title\":\"时间戳精度\",\"name\":\"timestamp_unit\",\"tip\":\"\",\"options\":[{\"label\":\"秒\",\"value\":\"second\"},{\"label\":\"毫秒\",\"value\":\"millisecond\"},{\"label\":\"微秒\",\"value\":\"microsecond\"}],\"default\":\"second\",\"required\":true}],\"outputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"converted_timestamp\",\"title\":\"时间戳\",\"tip\":\"\"}],\"icon\":\"datetime-to-timestamp\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(111,'data/data.Time','TimeProcess.timestamp_to_time','{\"key\":\"TimeProcess.timestamp_to_time\",\"title\":\"时间戳转时间对象\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.time.TimeProcess().timestamp_to_time\",\"comment\":\"将时间戳 @{timestamp} 转换为时间对象 @{converted_time}\",\"inputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"timestamp\",\"title\":\"时间戳\",\"name\":\"timestamp\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"TimeZoneType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"time_zone\",\"title\":\"选择时区\",\"name\":\"time_zone\",\"tip\":\"\",\"options\":[{\"label\":\"UTC标准时间\",\"value\":\"UTC\"},{\"label\":\"本地时间\",\"value\":\"local\"}],\"default\":\"local\",\"required\":true}],\"outputList\":[{\"types\":\"Date\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"converted_time\",\"title\":\"时间对象\",\"tip\":\"\"}],\"icon\":\"timestamp-to-datetime\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(112,'data/data.Time','TimeProcess.get_time_difference','{\"key\":\"TimeProcess.get_time_difference\",\"title\":\"获取时间差\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.time.TimeProcess().get_time_difference\",\"comment\":\"获取 @{time_1} 和 @{time_2} 之间的时间差,单位为 @{time_unit},返回时间差 @{time_difference}\",\"inputList\":[{\"types\":\"Date\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_DATETIME\"},\"key\":\"time_1\",\"title\":\"时间对象1\",\"name\":\"time_1\",\"tip\":\"\",\"required\":true},{\"types\":\"Date\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_DATETIME\"},\"key\":\"time_2\",\"title\":\"时间对象2\",\"name\":\"time_2\",\"tip\":\"\",\"required\":true},{\"types\":\"TimeUnitType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"time_unit\",\"title\":\"时间单位\",\"name\":\"time_unit\",\"tip\":\"\",\"options\":[{\"label\":\"秒\",\"value\":\"second\"},{\"label\":\"分\",\"value\":\"minute\"},{\"label\":\"时\",\"value\":\"hour\"},{\"label\":\"天\",\"value\":\"day\"},{\"label\":\"月\",\"value\":\"month\"},{\"label\":\"年\",\"value\":\"year\"}],\"default\":\"second\",\"required\":true}],\"outputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"time_difference\",\"title\":\"时间差\",\"tip\":\"\"}],\"icon\":\"get-time-difference\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(113,'data/data.Time','TimeProcess.format_datetime','{\"key\":\"TimeProcess.format_datetime\",\"title\":\"输出指定格式时间文本\",\"version\":\"1.0.0\",\"src\":\"astronverse.dataprocess.time.TimeProcess().format_datetime\",\"comment\":\"将时间对象 @{time} 按照指定格式 @{format_type} 输出文本 @{format_datetime}\",\"inputList\":[{\"types\":\"Date\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_DATETIME\"},\"key\":\"time\",\"title\":\"时间对象\",\"name\":\"time\",\"tip\":\"\",\"required\":true},{\"types\":\"TimeFormatType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"format_type\",\"title\":\"时间格式\",\"name\":\"format_type\",\"tip\":\"\",\"options\":[{\"label\":\"年-月-日\",\"value\":\"%Y-%m-%d\"},{\"label\":\"年-月-日 时:分:秒\",\"value\":\"%Y-%m-%d %H:%M:%S\"},{\"label\":\"年-月-日 时:分\",\"value\":\"%Y-%m-%d %H:%M\"},{\"label\":\"年/月/日\",\"value\":\"%Y/%m/%d\"},{\"label\":\"年/月/日 时:分\",\"value\":\"%Y/%m/%d %H:%M\"},{\"label\":\"年/月/日 时:分:秒\",\"value\":\"%Y/%m/%d %H:%M:%S\"},{\"label\":\"年月日\",\"value\":\"%Y%m%d\"},{\"label\":\"时:分\",\"value\":\"%H:%M\"},{\"label\":\"时:分:秒\",\"value\":\"%H:%M:%S\"},{\"label\":\"一周的第几天\",\"value\":\"%w\"},{\"label\":\"一年的第几天\",\"value\":\"%j\"},{\"label\":\"一年的第几周\",\"value\":\"%W\"},{\"label\":\"XXXX年XX月XX日\",\"value\":\"%Y年%m月%d日\"},{\"label\":\"XXXX年XX月XX日 XX:XX\",\"value\":\"%Y年%m月%d日 %H:%M\"},{\"label\":\"XXXX年XX月XX日 XX:XX:XX\",\"value\":\"%Y年%m月%d日 %H:%M:%S\"}],\"default\":\"%Y-%m-%d %H:%M:%S\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"format_datetime\",\"title\":\"时间文本\",\"tip\":\"\"}],\"icon\":\"output-formatted-time\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(114,'dialog','Dialog.message_box','{\"key\":\"Dialog.message_box\",\"title\":\"消息提示框\",\"version\":\"1.0.0\",\"src\":\"astronverse.dialog.dialog.Dialog().message_box\",\"comment\":\"\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT\"},\"key\":\"box_title\",\"title\":\"对话框标题\",\"name\":\"box_title\",\"tip\":\"用户自定义的对话框上方的显示标题,限制标题内容字符数量为50个字符。不输入则默认标题为“消息提示框”\",\"default\":\"消息提示框\",\"required\":false,\"limitLength\":[-1,50]},{\"types\":\"MessageType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"message_type\",\"title\":\"消息类型\",\"name\":\"message_type\",\"tip\":\"可选消息类型\",\"options\":[{\"label\":\"信息\",\"value\":\"message\"},{\"label\":\"警告\",\"value\":\"warning\"},{\"label\":\"问题\",\"value\":\"question\"},{\"label\":\"错误\",\"value\":\"error\"}],\"default\":\"message\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"message_content\",\"title\":\"消息内容\",\"name\":\"message_content\",\"tip\":\"用户自定义的对话框内的显示内容,限制内容字符数量为120个字符\",\"default\":\"\",\"required\":true,\"limitLength\":[-1,120]},{\"types\":\"ButtonType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"button_type\",\"title\":\"展示按钮\",\"name\":\"button_type\",\"tip\":\"消息框可展示给用户进行选择的按钮,只允许切换,不允许空选状态\",\"options\":[{\"label\":\"确认\",\"value\":\"confirm\"},{\"label\":\"确认-取消\",\"value\":\"confirm_cancel\"},{\"label\":\"是-否\",\"value\":\"yes_no\"},{\"label\":\"是-否-取消\",\"value\":\"yes_no_cancel\"}],\"default\":\"confirm\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\"},\"key\":\"auto_check\",\"title\":\"无操作自动关闭对话框\",\"name\":\"auto_check\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"level\":\"advanced\",\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"wait_time\",\"title\":\"无操作超时等待(秒)\",\"name\":\"wait_time\",\"tip\":\"设置超时等待时间,未识别到用户鼠标移动行为超过该时间则选中默认按钮,默认为60秒\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.wait_time.show\",\"expression\":\"return $this.auto_check.value == true\"}],\"required\":false},{\"types\":\"DefaultButtonC\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"default_button_c\",\"title\":\"超时默认选中按钮\",\"name\":\"default_button_c\",\"tip\":\"\",\"options\":[{\"label\":\"确认\",\"value\":\"confirm\"}],\"default\":\"confirm\",\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.default_button_c.show\",\"expression\":\"return $this.auto_check.value == true && $this.button_type.value == \'confirm\'\"}],\"required\":true},{\"types\":\"DefaultButtonCN\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"default_button_cn\",\"title\":\"超时默认选中按钮\",\"name\":\"default_button_cn\",\"tip\":\"\",\"options\":[{\"label\":\"确认\",\"value\":\"confirm\"},{\"label\":\"取消\",\"value\":\"cancel\"}],\"default\":\"confirm\",\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.default_button_cn.show\",\"expression\":\"return $this.auto_check.value == true && $this.button_type.value == \'confirm_cancel\'\"}],\"required\":true},{\"types\":\"DefaultButtonY\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"default_button_y\",\"title\":\"超时默认选中按钮\",\"name\":\"default_button_y\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":\"yes\"},{\"label\":\"否\",\"value\":\"no\"}],\"default\":\"yes\",\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.default_button_y.show\",\"expression\":\"return $this.auto_check.value == true && $this.button_type.value == \'yes_no\'\"}],\"required\":true},{\"types\":\"DefaultButtonYN\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"default_button_yn\",\"title\":\"超时默认选中按钮\",\"name\":\"default_button_yn\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":\"yes\"},{\"label\":\"否\",\"value\":\"no\"},{\"label\":\"取消\",\"value\":\"cancel\"}],\"default\":\"yes\",\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.default_button_yn.show\",\"expression\":\"return $this.auto_check.value == true && $this.button_type.value == \'yes_no_cancel\'\"}],\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"MODALBUTTON\"},\"key\":\"preview_button\",\"title\":\"预览\",\"name\":\"preview_button\",\"tip\":\"\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"result_button\",\"title\":\"保存用户选择的按钮至\",\"tip\":\"\"}],\"icon\":\"message-dialog\",\"helpManual\":\"打开消息提示对话框,可设定消息提示的内容和标题。\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(115,'dialog','Dialog.input_box','{\"key\":\"Dialog.input_box\",\"title\":\"输入对话框\",\"version\":\"1.0.0\",\"src\":\"astronverse.dialog.dialog.Dialog().input_box\",\"comment\":\"\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT\"},\"key\":\"box_title\",\"title\":\"对话框标题\",\"name\":\"box_title\",\"tip\":\"限制标题内容字符数量为50个字符,不输入则默认标题为“输入对话框”\",\"default\":\"输入对话框\",\"required\":false,\"limitLength\":[-1,50]},{\"types\":\"InputType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"input_type\",\"title\":\"输入框类型\",\"name\":\"input_type\",\"tip\":\"\",\"options\":[{\"label\":\"文本框\",\"value\":\"text\"},{\"label\":\"密码框\",\"value\":\"password\"}],\"default\":\"text\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"input_title\",\"title\":\"输入框标题\",\"name\":\"input_title\",\"tip\":\"\",\"default\":\"输入框标题\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false,\"limitLength\":[-1,60]},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"default_input_text\",\"title\":\"输入框内容默认值\",\"name\":\"default_input_text\",\"tip\":\"填写则在对话框中展示默认文本作为文本提示符,限制内容字符数量为120个字符\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.default_input_text.show\",\"expression\":\"return $this.input_type.value == \'text\'\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"DEFAULTPASSWORD\"},\"key\":\"default_input_pwd\",\"title\":\"输入框内容默认值\",\"name\":\"default_input_pwd\",\"tip\":\"填写则在对话框中展示默认密码,密码长度在4-16位之间\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.default_input_pwd.show\",\"expression\":\"return $this.input_type.value == \'password\'\"}],\"required\":false,\"limitLength\":[4,16]},{\"types\":\"Any\",\"formType\":{\"type\":\"MODALBUTTON\"},\"key\":\"preview_button\",\"title\":\"预览\",\"name\":\"preview_button\",\"tip\":\"\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"input_content\",\"title\":\"保存用户输入内容至\",\"tip\":\"\"}],\"icon\":\"input-dialog\",\"helpManual\":\"打开输入对话框,需用户进行信息输入并确定提交,返回用户在对话框中输入的内容。\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(116,'dialog','Dialog.select_box','{\"key\":\"Dialog.select_box\",\"title\":\"选择对话框\",\"version\":\"1.0.0\",\"src\":\"astronverse.dialog.dialog.Dialog().select_box\",\"comment\":\"\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT\"},\"key\":\"box_title\",\"title\":\"对话框标题\",\"name\":\"box_title\",\"tip\":\"\",\"default\":\"选择对话框\",\"required\":false,\"limitLength\":[-1,50]},{\"types\":\"SelectType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"select_type\",\"title\":\"选择模式\",\"name\":\"select_type\",\"tip\":\"\",\"options\":[{\"label\":\"单选\",\"value\":\"single\"},{\"label\":\"多选\",\"value\":\"multi\"}],\"default\":\"single\",\"required\":true},{\"types\":\"List\",\"formType\":{\"type\":\"OPTIONSLIST\"},\"key\":\"options\",\"title\":\"选项\",\"name\":\"options\",\"tip\":\"\",\"default\":[],\"need_parse\":\"str\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT\"},\"key\":\"options_title\",\"title\":\"选择框标题\",\"name\":\"options_title\",\"tip\":\"\",\"default\":\"\",\"required\":false},{\"types\":\"Any\",\"formType\":{\"type\":\"MODALBUTTON\"},\"key\":\"preview_button\",\"title\":\"预览\",\"name\":\"preview_button\",\"tip\":\"\",\"required\":false}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"select_result\",\"title\":\"保存选择结果至\",\"tip\":\"\"}],\"icon\":\"select-dialog\",\"helpManual\":\"打开选择对话框,保存用户从选择列表中选择的一个或多个选项\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(117,'dialog','Dialog.select_time_box','{\"key\":\"Dialog.select_time_box\",\"title\":\"日期时间选择框\",\"version\":\"1.0.0\",\"src\":\"astronverse.dialog.dialog.Dialog().select_time_box\",\"comment\":\"\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT\"},\"key\":\"box_title\",\"title\":\"对话框标题\",\"name\":\"box_title\",\"tip\":\"\",\"default\":\"日期时间选择框\",\"required\":false,\"limitLength\":[-1,50]},{\"types\":\"TimeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"time_type\",\"title\":\"时间类型\",\"name\":\"time_type\",\"tip\":\"\",\"options\":[{\"label\":\"时间\",\"value\":\"time\"},{\"label\":\"时间段\",\"value\":\"time_range\"}],\"default\":\"time\",\"required\":false},{\"types\":\"TimeFormat\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"time_format\",\"title\":\"时间格式\",\"name\":\"time_format\",\"tip\":\"\",\"options\":[{\"label\":\"年-月-日\",\"value\":\"YYYY-MM-DD\"},{\"label\":\"年-月-日 时:分\",\"value\":\"YYYY-MM-DD HH:mm\"},{\"label\":\"年-月-日 时:分:秒\",\"value\":\"YYYY-MM-DD HH:mm:ss\"},{\"label\":\"年/月/日\",\"value\":\"YYYY/MM/DD\"},{\"label\":\"年/月/日 时:分\",\"value\":\"YYYY/MM/DD HH:mm\"},{\"label\":\"年/月/日 时:分:秒\",\"value\":\"YYYY/MM/DD HH:mm:ss\"}],\"default\":\"YYYY-MM-DD\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"DEFAULTDATEPICKER\",\"params\":{\"format\":\"YYYY-MM-DD\"}},\"key\":\"default_time\",\"title\":\"默认时间\",\"name\":\"default_time\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.default_time.show\",\"expression\":\"return $this.time_type.value == \'time\'\"},{\"key\":\"$this.default_time.formType.params.format\",\"expression\":\"return $this.time_format.value\"}],\"required\":false},{\"types\":\"List\",\"formType\":{\"type\":\"RANGEDATEPICKER\",\"params\":{\"format\":\"YYYY-MM-DD\"}},\"key\":\"default_time_range\",\"title\":\"默认时间\",\"name\":\"default_time_range\",\"tip\":\"\",\"default\":[\"\",\"\"],\"dynamics\":[{\"key\":\"$this.default_time_range.show\",\"expression\":\"return $this.time_type.value == \'time_range\'\"},{\"key\":\"$this.default_time.formType.params.format\",\"expression\":\"return $this.time_format.value\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT\"},\"key\":\"input_title\",\"title\":\"输入框标题\",\"name\":\"input_title\",\"tip\":\"\",\"default\":\"输入框标题\",\"required\":false},{\"types\":\"Bool\",\"formType\":{\"type\":\"MODALBUTTON\"},\"key\":\"preview_button\",\"title\":\"预览\",\"name\":\"preview_button\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"required\":false}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"select_time\",\"title\":\"保存时间选择结果至\",\"tip\":\"\"}],\"icon\":\"datetime-picker\",\"helpManual\":\"打开日期时间选择框,保存用户选择的日期或时间\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(118,'dialog','Dialog.select_file_box','{\"key\":\"Dialog.select_file_box\",\"title\":\"文件选择对话框\",\"version\":\"1.0.0\",\"src\":\"astronverse.dialog.dialog.Dialog().select_file_box\",\"comment\":\"\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT\"},\"key\":\"box_title_file\",\"title\":\"对话框标题\",\"name\":\"box_title_file\",\"tip\":\"\",\"default\":\"文件选择框\",\"dynamics\":[{\"key\":\"$this.box_title_file.show\",\"expression\":\"return $this.open_type.value == \'file\'\"}],\"required\":false,\"limitLength\":[-1,50]},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT\"},\"key\":\"box_title_folder\",\"title\":\"对话框标题\",\"name\":\"box_title_folder\",\"tip\":\"\",\"default\":\"文件夹选择框\",\"dynamics\":[{\"key\":\"$this.box_title_folder.show\",\"expression\":\"return $this.open_type.value == \'folder\'\"}],\"required\":false,\"limitLength\":[-1,50]},{\"types\":\"OpenType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"open_type\",\"title\":\"打开类型\",\"name\":\"open_type\",\"tip\":\"\",\"options\":[{\"label\":\"文件\",\"value\":\"file\"},{\"label\":\"文件夹\",\"value\":\"folder\"}],\"default\":\"file\",\"required\":false},{\"types\":\"FileType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"file_type\",\"title\":\"文件类型\",\"name\":\"file_type\",\"tip\":\"\",\"options\":[{\"label\":\"所有文件\",\"value\":\"*\"},{\"label\":\"Excel文件\",\"value\":\".xls,.xlsx\"},{\"label\":\"Word文件\",\"value\":\".doc,.docx\"},{\"label\":\"文本文件\",\"value\":\".txt\"},{\"label\":\"图像文件\",\"value\":\".png,.jpg,.jpeg,.bmp,.gif\"},{\"label\":\"PPT文件\",\"value\":\".ppt,.pptx\"},{\"label\":\"压缩文件\",\"value\":\".zip,.rar\"}],\"default\":\"*\",\"dynamics\":[{\"key\":\"$this.file_type.show\",\"expression\":\"return $this.open_type.value == \'file\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\"},\"key\":\"multiple_choice\",\"title\":\"是否允许多选\",\"name\":\"multiple_choice\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"dynamics\":[{\"key\":\"$this.multiple_choice.show\",\"expression\":\"return $this.open_type.value == \'file\'\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT\"},\"key\":\"select_title\",\"title\":\"选择框标题\",\"name\":\"select_title\",\"tip\":\"\",\"default\":\"\",\"required\":false,\"limitLength\":[-1,60]},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"default_path\",\"title\":\"默认文件夹\",\"name\":\"default_path\",\"tip\":\"当配置了该参数,则在打开文件选择框时默认解析在该文件夹路径进行下一步选择\",\"default\":\"\",\"level\":\"advanced\",\"required\":false},{\"types\":\"Any\",\"formType\":{\"type\":\"MODALBUTTON\"},\"key\":\"preview_button\",\"title\":\"预览\",\"name\":\"preview_button\",\"tip\":\"\",\"required\":false}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"select_file\",\"title\":\"保存文件选择结果至\",\"tip\":\"保存用户的文件选择结果,如果用户点击取消按钮则返回为空值\"}],\"icon\":\"file-select-dialog\",\"helpManual\":\"打开系统选择文件对话框,保存用户选择的对应的文件/文件夹路径\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(119,'dialog','Dialog.custom_box','{\"key\":\"Dialog.custom_box\",\"title\":\"自定义对话框\",\"version\":\"1.0.0\",\"src\":\"astronverse.dialog.dialog.Dialog().custom_box\",\"comment\":\"\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT\"},\"key\":\"box_title\",\"title\":\"对话框标题\",\"name\":\"box_title\",\"tip\":\"\",\"default\":\"自定义对话框\",\"required\":true,\"limitLength\":[-1,50]},{\"types\":\"Str\",\"formType\":{\"type\":\"MODALBUTTON\"},\"key\":\"design_interface\",\"title\":\"设计对话框界面\",\"name\":\"design_interface\",\"tip\":\"点击按钮则进入对话框设计弹窗界面\",\"need_parse\":\"json_str\",\"required\":false},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\"},\"key\":\"auto_check\",\"title\":\"无操作自动关闭对话框\",\"name\":\"auto_check\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"level\":\"advanced\",\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"wait_time\",\"title\":\"无操作超时等待(秒)\",\"name\":\"wait_time\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.wait_time.show\",\"expression\":\"return $this.auto_check.value == true\"}],\"required\":false},{\"types\":\"DefaultButtonCN\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"default_button\",\"title\":\"超时默认选中按钮\",\"name\":\"default_button\",\"tip\":\"\",\"options\":[{\"label\":\"确认\",\"value\":\"confirm\"},{\"label\":\"取消\",\"value\":\"cancel\"}],\"default\":\"confirm\",\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.default_button.show\",\"expression\":\"return $this.auto_check.value == true\"}],\"required\":true}],\"outputList\":[{\"types\":\"DialogResult\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"dialog_result\",\"title\":\"自定义对话框结果\",\"tip\":\"存储所有表单控件的输出结果以及点击的按钮结果\"}],\"icon\":\"custom-dialog\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(120,'network/email','Email.send_email','{\"key\":\"Email.send_email\",\"title\":\"发送邮件\",\"version\":\"1.0.0\",\"src\":\"astronverse.email.email.Email().send_email\",\"comment\":\"给指定邮箱 @{receiver} 发送邮件\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"receiver\",\"title\":\"收件人邮箱\",\"name\":\"receiver\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"cc\",\"title\":\"抄送邮箱\",\"name\":\"cc\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"subject\",\"title\":\"主题\",\"name\":\"subject\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_html\",\"title\":\"是否为HTML格式\",\"name\":\"is_html\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"CONTENTPASTE\"},\"key\":\"content\",\"title\":\"内容\",\"name\":\"content\",\"tip\":\"\",\"default\":\"\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"files\"}},\"key\":\"attachment_path\",\"title\":\"附件路径\",\"name\":\"attachment_path\",\"tip\":\"\",\"default\":\"\",\"required\":false},{\"types\":\"EmailServerType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"mail_server\",\"title\":\"邮件服务器\",\"name\":\"mail_server\",\"tip\":\"\",\"options\":[{\"label\":\"其他邮箱\",\"value\":\"other\"},{\"label\":\"126\",\"value\":\"126\"},{\"label\":\"163\",\"value\":\"163\"},{\"label\":\"QQ\",\"value\":\"qq\"},{\"label\":\"讯飞邮箱\",\"value\":\"iflytek\"}],\"default\":\"qq\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"other_mail_server\",\"title\":\"其他邮件服务器\",\"name\":\"other_mail_server\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.other_mail_server.show\",\"expression\":\"return $this.mail_server.value == \'other\'\"}],\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"mail_port\",\"title\":\"邮件服务器端口\",\"name\":\"mail_port\",\"tip\":\"\",\"default\":465,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"use_ssl\",\"title\":\"是否使用SSL加密\",\"name\":\"use_ssl\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sender_mail\",\"title\":\"发件人邮箱\",\"name\":\"sender_mail\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"send_name\",\"title\":\"发件人名称\",\"name\":\"send_name\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"password\",\"title\":\"密码/授权码\",\"name\":\"password\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"bcc\",\"title\":\"密送邮箱\",\"name\":\"bcc\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"MODALBUTTON\"},\"key\":\"replace_table\",\"title\":\"智能填充表\",\"name\":\"replace_table\",\"tip\":\"\",\"default\":\"\",\"need_parse\":\"json_str\",\"required\":false}],\"outputList\":[],\"icon\":\"send-email\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(121,'network/email','Email.receive_email','{\"key\":\"Email.receive_email\",\"title\":\"接收邮件\",\"version\":\"1.0.0\",\"src\":\"astronverse.email.email.Email().receive_email\",\"comment\":\"从邮箱(@{user_mail})接收邮件信息\",\"inputList\":[{\"types\":\"EmailServerType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"mail_server\",\"title\":\"邮件服务器地址\",\"name\":\"mail_server\",\"tip\":\"选择一个邮箱类型\",\"options\":[{\"label\":\"其他邮箱\",\"value\":\"other\"},{\"label\":\"126\",\"value\":\"126\"},{\"label\":\"163\",\"value\":\"163\"},{\"label\":\"QQ\",\"value\":\"qq\"},{\"label\":\"讯飞邮箱\",\"value\":\"iflytek\"}],\"default\":\"qq\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"custom_mail_server\",\"title\":\"IMAP服务器地址\",\"name\":\"custom_mail_server\",\"tip\":\"输入指定的IMAP服务器地址\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"normal\",\"dynamics\":[{\"key\":\"$this.custom_mail_server.show\",\"expression\":\"return $this.mail_server.value == \'other\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"custom_mail_port\",\"title\":\"IMAP服务器端口\",\"name\":\"custom_mail_port\",\"tip\":\"输入指定的IMAP服务器端口\",\"default\":993,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"normal\",\"dynamics\":[{\"key\":\"$this.custom_mail_port.show\",\"expression\":\"return $this.mail_server.value == \'other\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"user_mail\",\"title\":\"用户邮件账号\",\"name\":\"user_mail\",\"tip\":\"IMAP服务器身份验证的用户名,通常是邮箱账号,以具体邮件服务商的规范为标准\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"normal\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"user_password\",\"title\":\"授权码\",\"name\":\"user_password\",\"tip\":\"IMAP服务器验证身份的授权码,一般需要短信认证开通,部分邮箱为账号密码,以具体邮件服务商的规范为标准\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"normal\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"max_return_num\",\"title\":\"邮件最大返回数量\",\"name\":\"max_return_num\",\"tip\":\"返回的最大邮件数量\",\"default\":5,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"CHECKBOX\"},\"key\":\"unseen_flag\",\"title\":\"仅未读邮件\",\"name\":\"unseen_flag\",\"tip\":\"仅获取未读邮件或全部邮件\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"level\":\"normal\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"CHECKBOX\"},\"key\":\"save_attachment_flag\",\"title\":\"保存附件\",\"name\":\"save_attachment_flag\",\"tip\":\"是否下载邮件附件\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"level\":\"normal\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"files\"}},\"key\":\"save_attachment_path\",\"title\":\"保存目录\",\"name\":\"save_attachment_path\",\"tip\":\"附件的保存目录\",\"default\":\"\",\"level\":\"normal\",\"dynamics\":[{\"key\":\"$this.save_attachment_path.show\",\"expression\":\"return $this.save_attachment_flag.value == true\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"folder_name\",\"title\":\"文件夹名称\",\"name\":\"folder_name\",\"tip\":\"输入要接收邮件的邮件箱名称,默认为INBOX\",\"default\":\"INBOX\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"CHECKBOX\"},\"key\":\"mask_as_read_flag\",\"title\":\"标记为已读\",\"name\":\"mask_as_read_flag\",\"tip\":\"获取邮件后,将邮件标记为已读状态\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sender_text\",\"title\":\"发件人中包含的内容\",\"name\":\"sender_text\",\"tip\":\"通过发送者包含关键字进行过滤\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"receiver_text\",\"title\":\"收件人中包含的内容\",\"name\":\"receiver_text\",\"tip\":\"通过接收者包含关键字进行过滤\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"theme_text\",\"title\":\"主题中包含的内容\",\"name\":\"theme_text\",\"tip\":\"通过主题包含关键字进行过滤\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"content_text\",\"title\":\"正文中包含的内容\",\"name\":\"content_text\",\"tip\":\"通过内容包含关键字进行过滤\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false}],\"outputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"mail_list\",\"title\":\"保存邮件列表\",\"tip\":\"指定一个变量名称,将返回的邮件列表存储至该变量\"}],\"icon\":\"receive-email\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(122,'os/encrypt','Encrypt.md5_encrypt','{\"key\":\"Encrypt.md5_encrypt\",\"title\":\"MD5加密\",\"version\":\"1.0.0\",\"src\":\"astronverse.encrypt.encrypt.Encrypt().md5_encrypt\",\"comment\":\"对字符串(@{source_str})进行MD5加密\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"source_str\",\"title\":\"需要加密的字符串\",\"name\":\"source_str\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"MD5bitsType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"md5_method\",\"title\":\"加密位数\",\"name\":\"md5_method\",\"tip\":\"\",\"options\":[{\"label\":\"32位\",\"value\":\"32\"},{\"label\":\"16位\",\"value\":\"16\"}],\"default\":\"32\",\"required\":true},{\"types\":\"EncryptCaseType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"case_method\",\"title\":\"大小写选择\",\"name\":\"case_method\",\"tip\":\"\",\"options\":[{\"label\":\"小写字母\",\"value\":\"lower\"},{\"label\":\"大写字母\",\"value\":\"upper\"}],\"default\":\"lower\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"md5_encrypted_result\",\"title\":\"MD5加密结果\",\"tip\":\"\"}],\"icon\":\"md5-encrypt\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(123,'os/encrypt','Encrypt.sha_encrypt','{\"key\":\"Encrypt.sha_encrypt\",\"title\":\"SHA加密\",\"version\":\"1.0.0\",\"src\":\"astronverse.encrypt.encrypt.Encrypt().sha_encrypt\",\"comment\":\"对字符串(@{source_str})进行SHA加密\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"source_str\",\"title\":\"需要加密的字符串\",\"name\":\"source_str\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"SHAType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"sha_method\",\"title\":\"SHA加密方法\",\"name\":\"sha_method\",\"tip\":\"\",\"options\":[{\"label\":\"sha1\",\"value\":\"sha1\"},{\"label\":\"sha224\",\"value\":\"sha224\"},{\"label\":\"sha256\",\"value\":\"sha256\"},{\"label\":\"sha384\",\"value\":\"sha384\"},{\"label\":\"sha512\",\"value\":\"sha512\"},{\"label\":\"sha3_224\",\"value\":\"sha3_224\"},{\"label\":\"sha3_256\",\"value\":\"sha3_256\"},{\"label\":\"sha3_384\",\"value\":\"sha3_384\"},{\"label\":\"sha3_512\",\"value\":\"sha3_512\"}],\"default\":\"sha1\",\"required\":true},{\"types\":\"EncryptCaseType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"case_method\",\"title\":\"大小写选择\",\"name\":\"case_method\",\"tip\":\"\",\"options\":[{\"label\":\"小写字母\",\"value\":\"lower\"},{\"label\":\"大写字母\",\"value\":\"upper\"}],\"default\":\"lower\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"sha_encrypted_result\",\"title\":\"SHA加密结果\",\"tip\":\"\"}],\"icon\":\"sha-encrypt\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(124,'os/encrypt','Encrypt.symmetric_encrypt','{\"key\":\"Encrypt.symmetric_encrypt\",\"title\":\"对称加密\",\"version\":\"1.0.0\",\"src\":\"astronverse.encrypt.encrypt.Encrypt().symmetric_encrypt\",\"comment\":\"对字符串(@{source_str})进行对称加密\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"source_str\",\"title\":\"需要加密的字符串\",\"name\":\"source_str\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"password\",\"title\":\"加密密钥\",\"name\":\"password\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"symmetric_encrypted_result\",\"title\":\"对称加密结果\",\"tip\":\"\"}],\"icon\":\"symmetric-encrypt\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(125,'os/encrypt','Encrypt.symmetric_decrypt','{\"key\":\"Encrypt.symmetric_decrypt\",\"title\":\"对称解密\",\"version\":\"1.0.0\",\"src\":\"astronverse.encrypt.encrypt.Encrypt().symmetric_decrypt\",\"comment\":\"对字符串(@{source_str})进行对称解密\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"source_str\",\"title\":\"需要解密的字符串\",\"name\":\"source_str\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"password\",\"title\":\"解密密钥\",\"name\":\"password\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"symmetric_decrypted_result\",\"title\":\"对称解密结果\",\"tip\":\"\"}],\"icon\":\"symmetric-decrypt\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(126,'os/encrypt','Encrypt.base64_encoding','{\"key\":\"Encrypt.base64_encoding\",\"title\":\"Base64编码\",\"version\":\"1.0.0\",\"src\":\"astronverse.encrypt.encrypt.Encrypt().base64_encoding\",\"comment\":\"读取字符串或图片文件编码为Base64字符串,返回编码后的字符串(@{encoded_string})\",\"inputList\":[{\"types\":\"Base64CodeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"encode_type\",\"title\":\"编码类型\",\"name\":\"encode_type\",\"tip\":\"\",\"options\":[{\"label\":\"字符串\",\"value\":\"string\"},{\"label\":\"图片\",\"value\":\"picture\"}],\"default\":\"string\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"string_data\",\"title\":\"字符串数据\",\"name\":\"string_data\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.string_data.show\",\"expression\":\"return $this.encode_type.value == \'string\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"文件路径\",\"name\":\"file_path\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.file_path.show\",\"expression\":\"return $this.encode_type.value == \'picture\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"encoded_string\",\"title\":\"编码后的字符串\",\"tip\":\"\"}],\"icon\":\"base64-encode\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(127,'os/encrypt','Encrypt.base64_decoding','{\"key\":\"Encrypt.base64_decoding\",\"title\":\"Base64解码\",\"version\":\"1.0.0\",\"src\":\"astronverse.encrypt.encrypt.Encrypt().base64_decoding\",\"comment\":\"读取Base64字符串(@{string_data}),解码为字符串或图片文件\",\"inputList\":[{\"types\":\"Base64CodeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"decode_type\",\"title\":\"解码类型\",\"name\":\"decode_type\",\"tip\":\"\",\"options\":[{\"label\":\"字符串\",\"value\":\"string\"},{\"label\":\"图片\",\"value\":\"picture\"}],\"default\":\"string\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"string_data\",\"title\":\"Base64字符串\",\"name\":\"string_data\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"file_path\",\"title\":\"图片保存文件夹\",\"name\":\"file_path\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.file_path.show\",\"expression\":\"return $this.decode_type.value == \'picture\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"file_name\",\"title\":\"图片文件名\",\"name\":\"file_name\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.file_name.show\",\"expression\":\"return $this.decode_type.value == \'picture\'\"}],\"required\":true},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_handle_type\",\"title\":\"存在同名文件处理方式\",\"name\":\"exist_handle_type\",\"tip\":\"选择存在文件处理方式,支持覆盖原有文件、创建文件副本、取消保存操作\",\"options\":[{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.exist_handle_type.show\",\"expression\":\"return $this.decode_type.value == \'picture\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"decoded_string\",\"title\":\"解码后的字符串/图片绝对路径\",\"tip\":\"\"}],\"icon\":\"base64-decode\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(128,'remote','Enterprise.upload_to_sharefolder','{\"key\":\"Enterprise.upload_to_sharefolder\",\"title\":\"上传文件至共享文件夹\",\"version\":\"1.0.0\",\"src\":\"astronverse.enterprise.enterprise.Enterprise().upload_to_sharefolder\",\"comment\":\"上传 @{file_path} 的文件,返回上传结果 @{upload_result}\",\"inputList\":[{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"上传文件路径\",\"name\":\"file_path\",\"tip\":\"\",\"default\":\"\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"upload_result\",\"title\":\"上传文件结果\",\"tip\":\"\"}],\"icon\":\"\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(129,'remote','Enterprise.download_from_sharefolder','{\"key\":\"Enterprise.download_from_sharefolder\",\"title\":\"从共享文件夹下载文件\",\"version\":\"1.0.0\",\"src\":\"astronverse.enterprise.enterprise.Enterprise().download_from_sharefolder\",\"comment\":\"下载 @{file_path} 的文件到 @{save_folder},返回下载结果 @{download_result}\",\"inputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"REMOTEFOLDERS\"},\"key\":\"file_path\",\"title\":\"共享文件夹文件\",\"name\":\"file_path\",\"tip\":\"\",\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"save_folder\",\"title\":\"文件保存路径\",\"name\":\"save_folder\",\"tip\":\"\",\"default\":\"\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"download_result\",\"title\":\"下载结果\",\"tip\":\"\"}],\"icon\":\"\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(130,'remote','Enterprise.get_shared_variable','{\"key\":\"Enterprise.get_shared_variable\",\"title\":\"获取共享变量\",\"version\":\"1.0.0\",\"src\":\"astronverse.enterprise.enterprise.Enterprise().get_shared_variable\",\"comment\":\"获取共享变量 @{shared_variable} 给变量 @{variable_data}\",\"inputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"REMOTEPARAMS\"},\"key\":\"shared_variable\",\"title\":\"共享变量名\",\"name\":\"shared_variable\",\"tip\":\"选择需要的共享变量\",\"required\":true}],\"outputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"variable_data\",\"title\":\"保存共享变量至\",\"tip\":\"\"}],\"icon\":\"get-shared-variable\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(131,'document/document.Excel','Excel.open_excel','{\"key\":\"Excel.open_excel\",\"title\":\"打开Excel文件\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().open_excel\",\"comment\":\"打开路径为 @{file_path} 的Excel文件,返回Excel对象 @{open_excel_obj}\",\"inputList\":[{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[\".xlsx\",\".xls\"],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"文件路径\",\"name\":\"file_path\",\"tip\":\"输入文件路径\",\"default\":\"\",\"required\":true},{\"types\":\"ApplicationType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"default_application\",\"title\":\"默认创建程序\",\"name\":\"default_application\",\"tip\":\"选择默认创建程序,可选Excel或WPS\",\"options\":[{\"label\":\"Excel\",\"value\":\"Excel\"},{\"label\":\"WPS\",\"value\":\"WPS\"},{\"label\":\"系统自动选择\",\"value\":\"Default\"}],\"default\":\"Default\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"visible_flag\",\"title\":\"是否可视化\",\"name\":\"visible_flag\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"password\",\"title\":\"密码\",\"name\":\"password\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"required\":false},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"update_links\",\"title\":\"自动更新外部链接\",\"name\":\"update_links\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true}],\"outputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"open_excel_obj\",\"title\":\"打开的Excel对象\",\"tip\":\"\"}],\"icon\":\"excel-open-file\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(132,'document/document.Excel','Excel.get_excel','{\"key\":\"Excel.get_excel\",\"title\":\"获取已打开的Excel对象\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().get_excel\",\"comment\":\"获取文件名为 @{file_name} 的Excel对象,返回Excel对象 @{get_excel_obj}\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"file_name\",\"title\":\"文件名\",\"name\":\"file_name\",\"tip\":\"输入文件名,不需要输入前序打开Excel的变量\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_excel_obj\",\"title\":\"获取的Excel对象\",\"tip\":\"\"}],\"icon\":\"get-open-excel-objects\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(133,'document/document.Excel','Excel.create_excel','{\"key\":\"Excel.create_excel\",\"title\":\"创建Excel文件\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().create_excel\",\"comment\":\"在路径为 @{file_path} 下创建文件名为 @{file_name} 的Excel文件,返回Excel对象 @{create_excel_obj}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"file_path\",\"title\":\"保存文件夹路径\",\"name\":\"file_path\",\"tip\":\"\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"file_name\",\"title\":\"保存文件名\",\"name\":\"file_name\",\"tip\":\"输入文件名\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"ApplicationType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"default_application\",\"title\":\"默认创建程序\",\"name\":\"default_application\",\"tip\":\"选择默认创建程序,可选Excel或WPS\",\"options\":[{\"label\":\"Excel\",\"value\":\"Excel\"},{\"label\":\"WPS\",\"value\":\"WPS\"},{\"label\":\"系统自动选择\",\"value\":\"Default\"}],\"default\":\"Excel\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"visible_flag\",\"title\":\"是否可视化\",\"name\":\"visible_flag\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_handle_type\",\"title\":\"文件名存在处理方式\",\"name\":\"exist_handle_type\",\"tip\":\"选择文件存在处理方式,可选覆盖、重命名、取消保存\",\"options\":[{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"password\",\"title\":\"文件打开密码\",\"name\":\"password\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"required\":false}],\"outputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"create_excel_obj\",\"title\":\"创建的Excel对象\",\"tip\":\"\"},{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"excel_path\",\"title\":\"创建的Excel文件路径\",\"tip\":\"\"}],\"icon\":\"excel-create-file\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(134,'document/document.Excel','Excel.save_excel','{\"key\":\"Excel.save_excel\",\"title\":\"保存Excel文件\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().save_excel\",\"comment\":\"保存Excel对象 @{excel} ,保存方式为 @{save_type}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"输入Excel对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"SaveType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"save_type\",\"title\":\"保存类型\",\"name\":\"save_type\",\"tip\":\"选择保存类型,可选保存或另存为\",\"options\":[{\"label\":\"保存\",\"value\":\"save\"},{\"label\":\"另存为\",\"value\":\"save_as\"},{\"label\":\"不保存\",\"value\":\"abort\"}],\"default\":\"save\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"file_path\",\"title\":\"文件路径\",\"name\":\"file_path\",\"tip\":\"输入文件路径\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.file_path.show\",\"expression\":\"return $this.save_type.value == \'save_as\'\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"file_name\",\"title\":\"文件名\",\"name\":\"file_name\",\"tip\":\"输入文件名\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.file_name.show\",\"expression\":\"return $this.save_type.value == \'save_as\'\"}],\"required\":false},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_handle_type\",\"title\":\"文件名存在处理方式\",\"name\":\"exist_handle_type\",\"tip\":\"选择文件存在处理方式,可选覆盖、重命名、取消保存\",\"options\":[{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"dynamics\":[{\"key\":\"$this.exist_handle_type.show\",\"expression\":\"return $this.save_type.value == \'save_as\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"close_flag\",\"title\":\"是否关闭文件\",\"name\":\"close_flag\",\"tip\":\"选择保存后是否关闭文件,可选关闭或不关闭\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true}],\"outputList\":[],\"icon\":\"excel-save-file\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(135,'document/document.Excel','Excel.close_excel','{\"key\":\"Excel.close_excel\",\"title\":\"关闭Excel文件\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().close_excel\",\"comment\":\"关闭 @{close_range_flag},当前Excel对象 @{excel},保存类型为 @{save_type_one||save_type_all}\",\"inputList\":[{\"types\":\"CloseRangeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"close_range_flag\",\"title\":\"关闭文档范围\",\"name\":\"close_range_flag\",\"tip\":\"选择关闭文档的范围,如关闭当前文档或关闭所有文档\",\"options\":[{\"label\":\"当前文档\",\"value\":\"one\"},{\"label\":\"所有文档\",\"value\":\"all\"}],\"default\":\"one\",\"required\":true},{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"输入Excel对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.excel.show\",\"expression\":\"return $this.close_range_flag.value == \'one\'\"}],\"required\":true},{\"types\":\"SaveType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"save_type_one\",\"title\":\"保存类型\",\"name\":\"save_type_one\",\"tip\":\"选择保存类型,可选保存,另存为或不保存\",\"options\":[{\"label\":\"保存\",\"value\":\"save\"},{\"label\":\"另存为\",\"value\":\"save_as\"},{\"label\":\"不保存\",\"value\":\"abort\"}],\"default\":\"save\",\"dynamics\":[{\"key\":\"$this.save_type_one.show\",\"expression\":\"return $this.close_range_flag.value == \'one\'\"}],\"required\":true},{\"types\":\"SaveTypeAll\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"save_type_all\",\"title\":\"保存类型\",\"name\":\"save_type_all\",\"tip\":\"选择保存类型,可选保存或不保存\",\"options\":[{\"label\":\"save\",\"value\":\"save\"},{\"label\":\"abort\",\"value\":\"abort\"}],\"default\":\"save\",\"dynamics\":[{\"key\":\"$this.save_type_all.show\",\"expression\":\"return $this.close_range_flag.value == \'all\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"file_path\",\"title\":\"文件路径\",\"name\":\"file_path\",\"tip\":\"输入文件路径\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.file_path.show\",\"expression\":\"return $this.save_type_one.value == \'save_as\' && $this.close_range_flag.value == \'one\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"file_name\",\"title\":\"文件名\",\"name\":\"file_name\",\"tip\":\"输入文件名\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.file_name.show\",\"expression\":\"return $this.save_type_one.value == \'save_as\'\"}],\"required\":true},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_handle_type\",\"title\":\"文件名存在处理方式\",\"name\":\"exist_handle_type\",\"tip\":\"选择文件存在处理方式,可选覆盖、重命名、取消保存\",\"options\":[{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"dynamics\":[{\"key\":\"$this.exist_handle_type.show\",\"expression\":\"return $this.close_range_flag.value == \'one\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"pkill_flag\",\"title\":\"是否关闭进程\",\"name\":\"pkill_flag\",\"tip\":\"选择是否关闭进程,可选关闭或不关闭\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"dynamics\":[{\"key\":\"$this.pkill_flag.show\",\"expression\":\"return $this.close_range_flag.value == \'all\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-close-file\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(136,'document/document.Excel','Excel.edit_excel','{\"key\":\"Excel.edit_excel\",\"title\":\"写入Excel文件\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().edit_excel\",\"comment\":\"编辑Excel对象 @{excel} ,写入内容 @{value}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"输入Excel对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"EditRangeType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"edit_range\",\"title\":\"编辑范围\",\"name\":\"edit_range\",\"tip\":\"选择编辑范围,可选行、列、区域\",\"options\":[{\"label\":\"行\",\"value\":\"row\"},{\"label\":\"列\",\"value\":\"column\"},{\"label\":\"区域\",\"value\":\"area\"},{\"label\":\"单元格\",\"value\":\"cell\"}],\"default\":\"row\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"start_col\",\"title\":\"起始列\",\"name\":\"start_col\",\"tip\":\"输入要编辑的起始列位置,支持字母(如\'A\')或数字(如1)格式。\",\"default\":\"A\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"start_row\",\"title\":\"起始行\",\"name\":\"start_row\",\"tip\":\"输入要编辑的起始行号,从1开始计数。当选择列(COLUMN)时可不填,当选择行(ROW)或区域(AREA)时必填\",\"default\":\"1\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"value\",\"title\":\"插入内容\",\"name\":\"value\",\"tip\":\"修改的内容以列表方式输入,当选择行或列时输入列表如[1,2,3],表示在指定行依次写入1,2,3;当选择区域时输入列表如[[1,1],[2,2]],表示在指定区域按行写入数据\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-write-file\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(137,'document/document.Excel','Excel.read_excel','{\"key\":\"Excel.read_excel\",\"title\":\"读取Excel文件内容\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().read_excel\",\"comment\":\"读取Excel对象 @{excel} 中工作表 @{sheet_name} 的Excel文件内容\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"输入Excel对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"ReadRangeType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"read_range\",\"title\":\"读取范围\",\"name\":\"read_range\",\"tip\":\"选择读取范围,可选单元格、行、列、区域、已编辑区域\",\"options\":[{\"label\":\"单元格\",\"value\":\"cell\"},{\"label\":\"行\",\"value\":\"row\"},{\"label\":\"列\",\"value\":\"column\"},{\"label\":\"区域\",\"value\":\"area\"},{\"label\":\"已编辑区域\",\"value\":\"all\"}],\"default\":\"cell\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"start_col\",\"title\":\"起始列\",\"name\":\"start_col\",\"tip\":\"输入起始列\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.start_col.show\",\"expression\":\"return $this.read_range.value == \'area\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"end_col\",\"title\":\"结束列\",\"name\":\"end_col\",\"tip\":\"输入结束列\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.end_col.show\",\"expression\":\"return $this.read_range.value == \'area\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"cell\",\"title\":\"单元格\",\"name\":\"cell\",\"tip\":\"输入待读取单元格,如A1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.cell.show\",\"expression\":\"return $this.read_range.value == \'cell\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"row\",\"title\":\"行\",\"name\":\"row\",\"tip\":\"输入整数代表行号,从1开始\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.row.show\",\"expression\":\"return $this.read_range.value == \'row\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"column\",\"title\":\"列\",\"name\":\"column\",\"tip\":\"输入列名,支持输入字符A或者整数1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.column.show\",\"expression\":\"return $this.read_range.value == \'column\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"start_row\",\"title\":\"起始行\",\"name\":\"start_row\",\"tip\":\"输入整数代表行号,从1开始\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.start_row.show\",\"expression\":\"return $this.read_range.value == \'area\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"end_row\",\"title\":\"结束行\",\"name\":\"end_row\",\"tip\":\"输入整数代表行号,-n代表倒数第n行\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.end_row.show\",\"expression\":\"return $this.read_range.value == \'area\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"read_display\",\"title\":\"读取单元格显示内容\",\"name\":\"read_display\",\"tip\":\"选择是否读取单元格显示的内容,可选是或否\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"trim_spaces\",\"title\":\"去除空格\",\"name\":\"trim_spaces\",\"tip\":\"选择是否去除空格,可选是或否\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"replace_none\",\"title\":\"替换空值\",\"name\":\"replace_none\",\"tip\":\"选择是否将空值(None)替换为空字符串,可选是或否\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"read_excel_contents\",\"title\":\"读取的Excel内容\",\"tip\":\"读取的Excel内容以列表方式返回\"}],\"icon\":\"excel-read-content\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(138,'document/document.Excel','Excel.design_cell_type','{\"key\":\"Excel.design_cell_type\",\"title\":\"设置单元格格式\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().design_cell_type\",\"comment\":\"设置 @{excel} 中工作表 @{sheet_name} 的单元格格式,字体大小为 @{font_size},字体名称为 @{font_name},字体颜色为 @{font_color},背景颜色 @{bg_color}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名称\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"ReadRangeType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"design_type\",\"title\":\"设置范围\",\"name\":\"design_type\",\"tip\":\"选择设置范围,可选单元格、行、列、区域\",\"options\":[{\"label\":\"单元格\",\"value\":\"cell\"},{\"label\":\"行\",\"value\":\"row\"},{\"label\":\"列\",\"value\":\"column\"},{\"label\":\"区域\",\"value\":\"area\"},{\"label\":\"已编辑区域\",\"value\":\"all\"}],\"default\":\"cell\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"cell_position\",\"title\":\"单元格位置\",\"name\":\"cell_position\",\"tip\":\"输入单元格位置,如A1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.cell_position.show\",\"expression\":\"return $this.design_type.value == \'cell\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"range_position\",\"title\":\"范围位置\",\"name\":\"range_position\",\"tip\":\"输入单元格范围,如A1:B2\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.range_position.show\",\"expression\":\"return $this.design_type.value == \'area\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"col\",\"title\":\"列\",\"name\":\"col\",\"tip\":\"输入列名,支持输入字符A或者整数1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.col.show\",\"expression\":\"return $this.design_type.value == \'column\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"row\",\"title\":\"行\",\"name\":\"row\",\"tip\":\"输入整数代表行号,从1开始\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.row.show\",\"expression\":\"return $this.design_type.value == \'row\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"col_width\",\"title\":\"列宽\",\"name\":\"col_width\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_COLOR\"},\"key\":\"bg_color\",\"title\":\"背景颜色\",\"name\":\"bg_color\",\"tip\":\"\",\"default\":\"\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_COLOR\"},\"key\":\"font_color\",\"title\":\"字体颜色\",\"name\":\"font_color\",\"tip\":\"\",\"default\":\"\",\"required\":false},{\"types\":\"FontType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"font_type\",\"title\":\"字体类型\",\"name\":\"font_type\",\"tip\":\"\",\"options\":[{\"label\":\"维持原状\",\"value\":\"no_change\"},{\"label\":\"粗体\",\"value\":\"bold\"},{\"label\":\"斜体\",\"value\":\"italic\"},{\"label\":\"粗斜体\",\"value\":\"bold_italic\"},{\"label\":\"常规\",\"value\":\"normal\"}],\"default\":\"no_change\",\"required\":true},{\"types\":\"FontNameType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"font_name\",\"title\":\"字体名称\",\"name\":\"font_name\",\"tip\":\"\",\"options\":[{\"label\":\"维持原状\",\"value\":\"维持原状\"},{\"label\":\"黑体\",\"value\":\"黑体\"},{\"label\":\"仿宋\",\"value\":\"仿宋\"},{\"label\":\"宋体\",\"value\":\"宋体\"},{\"label\":\"微软雅黑\",\"value\":\"微软雅黑\"},{\"label\":\"微软雅黑 Light\",\"value\":\"微软雅黑 Light\"},{\"label\":\"华文中宋\",\"value\":\"华文中宋\"},{\"label\":\"华文仿宋\",\"value\":\"华文仿宋\"},{\"label\":\"华文宋体\",\"value\":\"华文宋体\"},{\"label\":\"华文彩云\",\"value\":\"华文彩云\"},{\"label\":\"华文新魏\",\"value\":\"华文新魏\"},{\"label\":\"华文楷体\",\"value\":\"华文楷体\"},{\"label\":\"华文琥珀\",\"value\":\"华文琥珀\"},{\"label\":\"华文细黑\",\"value\":\"华文细黑\"},{\"label\":\"华文行楷\",\"value\":\"华文行楷\"},{\"label\":\"华文隶书\",\"value\":\"华文隶书\"},{\"label\":\"幼圆\",\"value\":\"幼圆\"},{\"label\":\"隶书\",\"value\":\"隶书\"},{\"label\":\"方正姚体\",\"value\":\"方正姚体\"},{\"label\":\"方正舒体\",\"value\":\"方正舒体\"},{\"label\":\"新宋体\",\"value\":\"新宋体\"},{\"label\":\"微軟正黑體 Light\",\"value\":\"微軟正黑體 Light\"},{\"label\":\"微軟正黑體\",\"value\":\"微軟正黑體\"},{\"label\":\"細明體_HKSCS-ExtB\",\"value\":\"細明體_HKSCS-ExtB\"},{\"label\":\"等线\",\"value\":\"等线\"},{\"label\":\"等线 Light\",\"value\":\"等线 Light\"},{\"label\":\"楷体\",\"value\":\"楷体\"},{\"label\":\"細明置-ExtB\",\"value\":\"細明置-ExtB\"},{\"label\":\"新細明置-ExtB\",\"value\":\"新細明置-ExtB\"},{\"label\":\"Onyx\",\"value\":\"Onyx\"},{\"label\":\"Myanmar Text\",\"value\":\"Myanmar Text\"},{\"label\":\"Niagara Engraved\",\"value\":\"Niagara Engraved\"},{\"label\":\"Niagara Solid\",\"value\":\"Niagara Solid\"},{\"label\":\"Nirmala Ul\",\"value\":\"Nirmala Ul\"},{\"label\":\"Nirmala Ul Semilight\",\"value\":\"Nirmala Ul Semilight\"},{\"label\":\"OCR A Extended\",\"value\":\"OCR A Extended\"},{\"label\":\"Old English Text MT\",\"value\":\"Old English Text MT\"},{\"label\":\"Palace Script MT\",\"value\":\"Palace Script MT\"},{\"label\":\"Poor Richard\",\"value\":\"Poor Richard\"},{\"label\":\"Papyrus\",\"value\":\"Papyrus\"},{\"label\":\"Parchment\",\"value\":\"Parchment\"},{\"label\":\"Perpetua\",\"value\":\"Perpetua\"},{\"label\":\"Perpetua Tilting MT\",\"value\":\"Perpetua Tilting MT\"},{\"label\":\"Playbill\",\"value\":\"Playbill\"},{\"label\":\"MV Boli\",\"value\":\"MV Boli\"},{\"label\":\"Pristina\",\"value\":\"Pristina\"},{\"label\":\"Rage Italic\",\"value\":\"Rage Italic\"},{\"label\":\"Ravie\",\"value\":\"Ravie\"},{\"label\":\"Palatino Linotype\",\"value\":\"Palatino Linotype\"},{\"label\":\"MT Extra\",\"value\":\"MT Extra\"},{\"label\":\"MS Gothic\",\"value\":\"MS Gothic\"},{\"label\":\"MS Reference Specialty\",\"value\":\"MS Reference Specialty\"},{\"label\":\"Marlett\",\"value\":\"Marlett\"},{\"label\":\"Matura MT Script Capitals\",\"value\":\"Matura MT Script Capitals\"},{\"label\":\"Microsoft Himalaya\",\"value\":\"Microsoft Himalaya\"},{\"label\":\"Microsoft JhengHei UI\",\"value\":\"Microsoft JhengHei UI\"},{\"label\":\"Microsoft JhengHei UI Light\",\"value\":\"Microsoft JhengHei UI Light\"},{\"label\":\"Microsoft New Tai Lue\",\"value\":\"Microsoft New Tai Lue\"},{\"label\":\"Microsoft PhagsPa\",\"value\":\"Microsoft PhagsPa\"},{\"label\":\"Microsoft Sans Serif\",\"value\":\"Microsoft Sans Serif\"},{\"label\":\"Microsoft Tai Le\",\"value\":\"Microsoft Tai Le\"},{\"label\":\"Microsoft Uighur\",\"value\":\"Microsoft Uighur\"},{\"label\":\"Microsoft Yahei Ul\",\"value\":\"Microsoft Yahei Ul\"},{\"label\":\"Microsoft YaHei Ul Light\",\"value\":\"Microsoft YaHei Ul Light\"},{\"label\":\"Microsoft Yi Baiti\",\"value\":\"Microsoft Yi Baiti\"},{\"label\":\"Mistral\",\"value\":\"Mistral\"},{\"label\":\"Modern No.20\",\"value\":\"Modern No.20\"},{\"label\":\"Mogolian Baiti\",\"value\":\"Mogolian Baiti\"}],\"default\":\"维持原状\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"font_size\",\"title\":\"字体大小\",\"name\":\"font_size\",\"tip\":\"\",\"default\":11,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"NumberFormatType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"numberformat\",\"title\":\"数字格式\",\"name\":\"numberformat\",\"tip\":\"\",\"options\":[{\"label\":\"维持原状\",\"value\":\"no_change\"},{\"label\":\"常规\",\"value\":\"G/通用格式\"},{\"label\":\"数字\",\"value\":\"0.00\"},{\"label\":\"货币\",\"value\":\"¥#,##0.00\"},{\"label\":\"_(¥* #,##0.00_);_(¥* (#,##0.00);_(¥* -_0_0_);_(@_)\",\"value\":\"_(¥* #,##0.00_);_(¥* (#,##0.00);_(¥* -_0_0_);_(@_)\"},{\"label\":\"短日期\",\"value\":\"yyyy/m/d\"},{\"label\":\"长日期\",\"value\":\"yyyy年mm月dd日\"},{\"label\":\"时间\",\"value\":\"h:mm:ss AM/PM\"},{\"label\":\"百分比\",\"value\":\"0.00%\"},{\"label\":\"分数\",\"value\":\"# ?/?\"},{\"label\":\"科学记数\",\"value\":\"0.00E+00\"},{\"label\":\"@\",\"value\":\"@\"},{\"label\":\"自定义\",\"value\":\"other\"}],\"default\":\"no_change\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"numberformat_other\",\"title\":\"自定义数字格式\",\"name\":\"numberformat_other\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.numberformat_other.show\",\"expression\":\"return $this.numberformat.value == \'other\'\"}],\"required\":false},{\"types\":\"HorizontalAlign\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"horizontal_align\",\"title\":\"水平对齐\",\"name\":\"horizontal_align\",\"tip\":\"\",\"options\":[{\"label\":\"维持原状\",\"value\":\"no_change\"},{\"label\":\"默认常规\",\"value\":\"default\"},{\"label\":\"左对齐\",\"value\":\"left-aligned\"},{\"label\":\"右对齐\",\"value\":\"right-aligned\"},{\"label\":\"居中对齐\",\"value\":\"center\"},{\"label\":\"填充\",\"value\":\"padding\"},{\"label\":\"两端对齐\",\"value\":\"aligned_both_sides\"},{\"label\":\"跨列居中\",\"value\":\"center_cross_column\"},{\"label\":\"分散对齐\",\"value\":\"distributed_align\"}],\"default\":\"no_change\",\"required\":true},{\"types\":\"VerticalAlign\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"vertical_align\",\"title\":\"垂直对齐\",\"name\":\"vertical_align\",\"tip\":\"\",\"options\":[{\"label\":\"维持原状\",\"value\":\"no_change\"},{\"label\":\"靠上\",\"value\":\"up\"},{\"label\":\"居中\",\"value\":\"middle\"},{\"label\":\"靠下\",\"value\":\"down\"},{\"label\":\"两端对齐\",\"value\":\"aligned_both_sides\"},{\"label\":\"分散对齐\",\"value\":\"distributed_align\"}],\"default\":\"no_change\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"wrap_text\",\"title\":\"自动换行\",\"name\":\"wrap_text\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"auto_row_height\",\"title\":\"自动行高\",\"name\":\"auto_row_height\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"dynamics\":[{\"key\":\"$this.auto_row_height.show\",\"expression\":\"return $this.design_type.value == \'row\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"auto_column_width\",\"title\":\"自动列宽\",\"name\":\"auto_column_width\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"dynamics\":[{\"key\":\"$this.auto_column_width.show\",\"expression\":\"return $this.design_type.value == \'column\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-set-cell-format\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(139,'document/document.Excel','Excel.copy_excel','{\"key\":\"Excel.copy_excel\",\"title\":\"复制Excel单元格\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().copy_excel\",\"comment\":\"复制Excel对象 @{excel} 中工作表 @{sheet_name} 的单元格,返回复制内容的字符串格式 @{copy_excel_contents}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"ReadRangeType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"copy_range_type\",\"title\":\"复制范围\",\"name\":\"copy_range_type\",\"tip\":\"\",\"options\":[{\"label\":\"单元格\",\"value\":\"cell\"},{\"label\":\"行\",\"value\":\"row\"},{\"label\":\"列\",\"value\":\"column\"},{\"label\":\"区域\",\"value\":\"area\"},{\"label\":\"已编辑区域\",\"value\":\"all\"}],\"default\":\"cell\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"cell_position\",\"title\":\"单元格位置\",\"name\":\"cell_position\",\"tip\":\"填写单元格位置,如A1\",\"default\":\"A1\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.cell_position.show\",\"expression\":\"return $this.copy_range_type.value == \'cell\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"row\",\"title\":\"行\",\"name\":\"row\",\"tip\":\"输入整数代表行号,从1开始\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.row.show\",\"expression\":\"return $this.copy_range_type.value == \'row\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"col\",\"title\":\"列\",\"name\":\"col\",\"tip\":\"输入列名,支持输入字符A或者整数1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.col.show\",\"expression\":\"return $this.copy_range_type.value == \'column\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"range_position\",\"title\":\"单元格范围\",\"name\":\"range_position\",\"tip\":\"填写单元格范围,如A1:B2\",\"default\":\"A1:B5\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.range_position.show\",\"expression\":\"return $this.copy_range_type.value == \'area\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"copy_excel_contents\",\"title\":\"Excel复制内容\",\"tip\":\"\"}],\"icon\":\"excel-copy-cell\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(140,'document/document.Excel','Excel.paste_excel','{\"key\":\"Excel.paste_excel\",\"title\":\"粘贴Excel单元格\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().paste_excel\",\"comment\":\"向Excel对象 @{excel} 中工作表 @{sheet_name} 粘贴单元格\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"PasteType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"paste_type\",\"title\":\"粘贴类型\",\"name\":\"paste_type\",\"tip\":\"\",\"options\":[{\"label\":\"默认全部粘贴\",\"value\":\"all\"},{\"label\":\"值和数字格式\",\"value\":\"value_and_format\"},{\"label\":\"仅格式\",\"value\":\"format\"},{\"label\":\"边框除外\",\"value\":\"exclude_frame\"},{\"label\":\"仅列宽\",\"value\":\"col_width_only\"},{\"label\":\"仅公式\",\"value\":\"formula_only\"},{\"label\":\"公式和数字格式\",\"value\":\"formula_and_format\"},{\"label\":\"粘贴值\",\"value\":\"paste_value\"}],\"default\":\"all\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"start_location\",\"title\":\"起始位置\",\"name\":\"start_location\",\"tip\":\"输入起始单元格位置,如A1\",\"default\":\"A1\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"skip_blanks\",\"title\":\"是否跳过空白行\",\"name\":\"skip_blanks\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"transpose\",\"title\":\"是否转置\",\"name\":\"transpose\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true}],\"outputList\":[],\"icon\":\"excel-paste-cell\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(141,'document/document.Excel','Excel.delete_excel_cell','{\"key\":\"Excel.delete_excel_cell\",\"title\":\"删除Excel单元格\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().delete_excel_cell\",\"comment\":\"删除Excel对象 @{excel} 中工作表 @{sheet_name} 的单元格\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"ReadRangeType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"delete_range_excel\",\"title\":\"删除范围\",\"name\":\"delete_range_excel\",\"tip\":\"\",\"options\":[{\"label\":\"单元格\",\"value\":\"cell\"},{\"label\":\"行\",\"value\":\"row\"},{\"label\":\"列\",\"value\":\"column\"},{\"label\":\"区域\",\"value\":\"area\"},{\"label\":\"已编辑区域\",\"value\":\"all\"}],\"default\":\"cell\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"coordinate\",\"title\":\"单元格位置\",\"name\":\"coordinate\",\"tip\":\"输入单元格位置,如A1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.coordinate.show\",\"expression\":\"return $this.delete_range_excel.value == \'cell\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"row\",\"title\":\"行\",\"name\":\"row\",\"tip\":\"输入整数代表行号,从1开始\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.row.show\",\"expression\":\"return $this.delete_range_excel.value == \'row\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"col\",\"title\":\"列\",\"name\":\"col\",\"tip\":\"输入列名,支持输入字符A或者整数1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.col.show\",\"expression\":\"return $this.delete_range_excel.value == \'column\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"data_region\",\"title\":\"单元格范围\",\"name\":\"data_region\",\"tip\":\"输入单元格范围,如A1:B2\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.data_region.show\",\"expression\":\"return $this.delete_range_excel.value == \'area\'\"}],\"required\":true},{\"types\":\"DeleteCellDirection\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"direction\",\"title\":\"剩余数据填充方向\",\"name\":\"direction\",\"tip\":\"\",\"options\":[{\"label\":\"下方单元格上移\",\"value\":\"lower_move_up\"},{\"label\":\"右侧单元格左移\",\"value\":\"right_move_left\"}],\"default\":\"lower_move_up\",\"dynamics\":[{\"key\":\"$this.direction.show\",\"expression\":\"return [\'cell\', \'area\'].includes($this.delete_range_excel.value)\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-delete-cell\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(142,'document/document.Excel','Excel.clear_excel_content','{\"key\":\"Excel.clear_excel_content\",\"title\":\"清除Excel区域内容\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().clear_excel_content\",\"comment\":\"清除Excel对象 @{excel} 中工作表 @{sheet_name} 的单元格内容\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"ReadRangeType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"select_type\",\"title\":\"区域选择\",\"name\":\"select_type\",\"tip\":\"选择需要删除的区域内容\",\"options\":[{\"label\":\"单元格\",\"value\":\"cell\"},{\"label\":\"行\",\"value\":\"row\"},{\"label\":\"列\",\"value\":\"column\"},{\"label\":\"区域\",\"value\":\"area\"},{\"label\":\"已编辑区域\",\"value\":\"all\"}],\"default\":\"cell\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"cell_location\",\"title\":\"单元格位置\",\"name\":\"cell_location\",\"tip\":\"输入单元格位置,如A1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.cell_location.show\",\"expression\":\"return $this.select_type.value == \'cell\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"row\",\"title\":\"行\",\"name\":\"row\",\"tip\":\"输入整数代表行号,从1开始\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.row.show\",\"expression\":\"return $this.select_type.value == \'row\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"col\",\"title\":\"列\",\"name\":\"col\",\"tip\":\"输入列名,支持输入字符A或者整数1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.col.show\",\"expression\":\"return $this.select_type.value == \'column\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"data_range\",\"title\":\"单元格范围\",\"name\":\"data_range\",\"tip\":\"输入连续的单元格范围,如A1:B2\",\"default\":\"A1:B5\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.data_range.show\",\"expression\":\"return $this.select_type.value == \'area\'\"}],\"required\":true},{\"types\":\"ClearType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"clear_type\",\"title\":\"清除类型\",\"name\":\"clear_type\",\"tip\":\"\",\"options\":[{\"label\":\"清除内容\",\"value\":\"content\"},{\"label\":\"清除格式\",\"value\":\"style\"},{\"label\":\"清除内容和格式\",\"value\":\"all\"}],\"default\":\"content\",\"required\":true}],\"outputList\":[],\"icon\":\"excel-clear-range\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(143,'document/document.Excel','Excel.insert_excel_row_or_column','{\"key\":\"Excel.insert_excel_row_or_column\",\"title\":\"插入Excel行或列\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().insert_excel_row_or_column\",\"comment\":\"向Excel对象 @{excel} 中工作表 @{sheet_name} 插入行或列\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"EnhancedInsertType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"insert_type\",\"title\":\"插入类型\",\"name\":\"insert_type\",\"tip\":\"\",\"options\":[{\"label\":\"指定行号插入\",\"value\":\"row\"},{\"label\":\"指定列号插入\",\"value\":\"column\"},{\"label\":\"在最后一行后插入\",\"value\":\"add_rows\"},{\"label\":\"在最后一列后插入\",\"value\":\"add_columns\"}],\"default\":\"row\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"row\",\"title\":\"行\",\"name\":\"row\",\"tip\":\"输入整数代表行号,从1开始\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.row.show\",\"expression\":\"return $this.insert_type.value == \'row\'\"}],\"required\":true},{\"types\":\"RowDirectionType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"row_direction\",\"title\":\"插入行方向\",\"name\":\"row_direction\",\"tip\":\"\",\"options\":[{\"label\":\"向上插入\",\"value\":\"upper\"},{\"label\":\"向下插入\",\"value\":\"lower\"}],\"default\":\"lower\",\"dynamics\":[{\"key\":\"$this.row_direction.show\",\"expression\":\"return $this.insert_type.value == \'row\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"col\",\"title\":\"列\",\"name\":\"col\",\"tip\":\"输入列名,支持输入字符A或者整数1\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.col.show\",\"expression\":\"return $this.insert_type.value == \'column\'\"}],\"required\":true},{\"types\":\"ColumnDirectionType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"col_direction\",\"title\":\"插入列方向\",\"name\":\"col_direction\",\"tip\":\"\",\"options\":[{\"label\":\"向左插入\",\"value\":\"left\"},{\"label\":\"向右插入\",\"value\":\"right\"}],\"default\":\"right\",\"dynamics\":[{\"key\":\"$this.col_direction.show\",\"expression\":\"return $this.insert_type.value == \'column\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"blank_rows\",\"title\":\"是否只插入空行/空列\",\"name\":\"blank_rows\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"insert_num\",\"title\":\"插入行数\",\"name\":\"insert_num\",\"tip\":\"\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.insert_num.show\",\"expression\":\"return $this.blank_rows.value == true\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"insert_content\",\"title\":\"插入内容\",\"name\":\"insert_content\",\"tip\":\"插入单行或多行时,插入内容需为多维列表,字符需使用单引号\'\',例:插入1行,写入内容:[[123,24,32]],插入2行,写入内容:[[123,123],[\'aaa\']],则实际写入excel内容为:第一行:123 123;第二行:aaa;写入内容:[[123,123],\'aaa\'],则实际写入excel内容为:第一行:123 123;第二行:a a a;如果插入的行或列超过数据长度,多余的单元格将保持为空\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.insert_content.show\",\"expression\":\"return $this.blank_rows.value == false\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-insert-row-column\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(144,'document/document.Excel','Excel.get_excel_row_num','{\"key\":\"Excel.get_excel_row_num\",\"title\":\"获取Excel行数\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().get_excel_row_num\",\"comment\":\"获取Excel对象 @{excel} 中工作表 @{sheet_name} 的行数,返回行数 @{excel_row_num}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"ColumnType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"get_col_type\",\"title\":\"获取类型\",\"name\":\"get_col_type\",\"tip\":\"\",\"options\":[{\"label\":\"所有列\",\"value\":\"all\"},{\"label\":\"单列\",\"value\":\"one_column\"}],\"default\":\"all\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"col\",\"title\":\"列\",\"name\":\"col\",\"tip\":\"输入列名,支持输入字符A或者整数1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.col.show\",\"expression\":\"return $this.get_col_type.value == \'one_column\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"excel_row_num\",\"title\":\"Excel行数\",\"tip\":\"\"}],\"icon\":\"excel-get-row-count\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(145,'document/document.Excel','Excel.get_excel_col_num','{\"key\":\"Excel.get_excel_col_num\",\"title\":\"获取Excel列数\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().get_excel_col_num\",\"comment\":\"获取Excel对象 @{excel} 中工作表 @{sheet_name} 的列数,返回列数 @{excel_col_num}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"RowType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"get_row_type\",\"title\":\"获取类型\",\"name\":\"get_row_type\",\"tip\":\"\",\"options\":[{\"label\":\"所有行\",\"value\":\"all\"},{\"label\":\"单行\",\"value\":\"one_row\"}],\"default\":\"all\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"row\",\"title\":\"行\",\"name\":\"row\",\"tip\":\"输入整数代表行号,从1开始\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.row.show\",\"expression\":\"return $this.get_row_type.value == \'one_row\'\"}],\"required\":true},{\"types\":\"ColumnOutputType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"output_type\",\"title\":\"输出格式\",\"name\":\"output_type\",\"tip\":\"\",\"options\":[{\"label\":\"字母列号\",\"value\":\"letter\"},{\"label\":\"数字列号\",\"value\":\"number\"}],\"default\":\"number\",\"required\":true}],\"outputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"excel_col_num\",\"title\":\"Excel列数\",\"tip\":\"\"}],\"icon\":\"excel-get-column-count\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(146,'document/document.Excel','Excel.get_excel_first_available_row','{\"key\":\"Excel.get_excel_first_available_row\",\"title\":\"获取Excel第一个可用行\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().get_excel_first_available_row\",\"comment\":\"获取Excel对象 @{excel} 中工作表 @{sheet_name} 的第一个可用行,返回可用行 @{get_first_available_row}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false}],\"outputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_first_available_row\",\"title\":\"第一个可用行\",\"tip\":\"\"}],\"icon\":\"excel-get-first-available-row\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(147,'document/document.Excel','Excel.get_excel_first_available_col','{\"key\":\"Excel.get_excel_first_available_col\",\"title\":\"获取Excel第一个可用列\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().get_excel_first_available_col\",\"comment\":\"获取Excel对象 @{excel} 中工作表 @{sheet_name} 的第一个可用列,返回可用列 @{get_first_available_col}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"ColumnOutputType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"output_type\",\"title\":\"输出格式\",\"name\":\"output_type\",\"tip\":\"\",\"options\":[{\"label\":\"字母列号\",\"value\":\"letter\"},{\"label\":\"数字列号\",\"value\":\"number\"}],\"default\":\"letter\",\"required\":true}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_first_available_col\",\"title\":\"第一个可用列\",\"tip\":\"\"}],\"icon\":\"excel-get-first-available-column\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(148,'document/document.Excel','Excel.loop_excel_content','{\"key\":\"Excel.loop_excel_content\",\"title\":\"循环Excel内容\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().loop_excel_content\",\"comment\":\"循环Excel对象 @{excel} 中指定 @{select_type} 的内容,输出循环项位置至@{key} 输出循环项至@{value}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"SearchRangeType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"select_type\",\"title\":\"循环范围\",\"name\":\"select_type\",\"tip\":\"\",\"options\":[{\"label\":\"已编辑区域\",\"value\":\"all\"},{\"label\":\"行\",\"value\":\"row\"},{\"label\":\"列\",\"value\":\"column\"},{\"label\":\"区域\",\"value\":\"area\"}],\"default\":\"row\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"start_row\",\"title\":\"起始行\",\"name\":\"start_row\",\"tip\":\"输入起始行编号,从1开始\",\"default\":\"1\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.start_row.show\",\"expression\":\"return [\'row\', \'area\'].includes($this.select_type.value)\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"end_row\",\"title\":\"结束行\",\"name\":\"end_row\",\"tip\":\"输入结束行编号,-n代表倒数第n行\",\"default\":\"-1\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.end_row.show\",\"expression\":\"return [\'row\', \'area\'].includes($this.select_type.value)\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"start_col\",\"title\":\"起始列\",\"name\":\"start_col\",\"tip\":\"输入起始列编号,如A或1\",\"default\":\"A\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.start_col.show\",\"expression\":\"return [\'column\', \'area\'].includes($this.select_type.value)\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"end_col\",\"title\":\"结束列\",\"name\":\"end_col\",\"tip\":\"输入结束列编号,-n代表倒数第n列\",\"default\":\"-1\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.end_col.show\",\"expression\":\"return [\'column\', \'area\'].includes($this.select_type.value)\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"real_text\",\"title\":\"是否获取可见值\",\"name\":\"real_text\",\"tip\":\"Excel的可见值为打开所见到的值,真实值可能是隐藏的公式等,选择否获取真实值\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"cell_strip\",\"title\":\"是否去除空格\",\"name\":\"cell_strip\",\"tip\":\"是否去除前后空格以及换行符\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"key\",\"title\":\"循环项位置\",\"tip\":\"例如 A, B\"},{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"value\",\"title\":\"循环项\",\"tip\":\"例如 [1.0, None]\"}],\"icon\":\"excel-loop-content\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(149,'document/document.Excel','Excel.excel_get_cell_color','{\"key\":\"Excel.excel_get_cell_color\",\"title\":\"获取Excel单元格颜色\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().excel_get_cell_color\",\"comment\":\"获取Excel对象 @{excel} 中工作表 @{sheet_name} 的单元格 @{coordinate} 的颜色,返回颜色 @{get_cell_color}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"coordinate\",\"title\":\"单元格位置\",\"name\":\"coordinate\",\"tip\":\"输入单元格位置,如A1\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_cell_color\",\"title\":\"单元格颜色\",\"tip\":\"\"}],\"icon\":\"excel-get-cell-color\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(150,'document/document.Excel','Excel.merge_split_excel_cell','{\"key\":\"Excel.merge_split_excel_cell\",\"title\":\"合并或拆分Excel单元格\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().merge_split_excel_cell\",\"comment\":\"合并或拆分Excel对象 @{excel} 中工作表 @{sheet_name} 的单元格\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"MergeOrSplitType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"job_type\",\"title\":\"合并或拆分类型\",\"name\":\"job_type\",\"tip\":\"\",\"options\":[{\"label\":\"合并\",\"value\":\"merge\"},{\"label\":\"拆分\",\"value\":\"split\"}],\"default\":\"merge\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"merge_cell_range\",\"title\":\"合并单元格范围\",\"name\":\"merge_cell_range\",\"tip\":\"输入需合并的连续单元格范围,如A1:B2\",\"default\":\"A1:B2\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.merge_cell_range.show\",\"expression\":\"return $this.job_type.value == \'merge\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"split_cell_range\",\"title\":\"拆分单元格范围\",\"name\":\"split_cell_range\",\"tip\":\"输入需拆分的连续单元格范围,如A1:B2\",\"default\":\"A1:B2\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.split_cell_range.show\",\"expression\":\"return $this.job_type.value == \'split\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-split-cell\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(151,'document/document.Excel','Excel.add_excel_worksheet','{\"key\":\"Excel.add_excel_worksheet\",\"title\":\"添加Excel工作表\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().add_excel_worksheet\",\"comment\":\"向Excel对象 @{excel} 中添加工作表 @{sheet_name}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"SheetInsertType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"insert_type\",\"title\":\"插入位置\",\"name\":\"insert_type\",\"tip\":\"\",\"options\":[{\"label\":\"新表成为第一个工作表\",\"value\":\"first\"},{\"label\":\"新表成为最后一个工作表\",\"value\":\"last\"},{\"label\":\"新表插入到...表之前\",\"value\":\"before\"},{\"label\":\"新表插入到...表之后\",\"value\":\"after\"}],\"default\":\"first\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"relative_sheet_name\",\"title\":\"在...表之前/之后插入\",\"name\":\"relative_sheet_name\",\"tip\":\"输入相对位置相关的工作表名称,如\'Sheet1\'\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.relative_sheet_name.show\",\"expression\":\"return $this.insert_type.value == \'before\' || $this.insert_type.value == \'after\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"add-excel-worksheet\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(152,'document/document.Excel','Excel.move_excel_worksheet','{\"key\":\"Excel.move_excel_worksheet\",\"title\":\"移动Excel工作表\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().move_excel_worksheet\",\"comment\":\"移动Excel对象 @{excel} 中工作表 @{move_sheet} ,移动方式为 @{move_type}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"MoveSheetType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"move_type\",\"title\":\"移动方式\",\"name\":\"move_type\",\"tip\":\"\",\"options\":[{\"label\":\"移动到目标工作表之后\",\"value\":\"move_after\"},{\"label\":\"移动到目标工作表之前\",\"value\":\"move_before\"},{\"label\":\"移动到第一个工作表\",\"value\":\"move_to_first\"},{\"label\":\"移动到最后一个工作表\",\"value\":\"move_to_last\"}],\"default\":\"move_after\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"move_sheet\",\"title\":\"要移动的工作表\",\"name\":\"move_sheet\",\"tip\":\"工作表可以填写名称或序号,如\'Sheet1\'或\'1\',序号从1开始\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"move_to_sheet\",\"title\":\"目标工作表\",\"name\":\"move_to_sheet\",\"tip\":\"工作表可以填写名称或序号,如\'Sheet1\'或\'1\',序号从1开始\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.move_to_sheet.show\",\"expression\":\"return [\'move_after\', \'move_before\'].includes($this.move_type.value)\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-move-sheet\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(153,'document/document.Excel','Excel.delete_excel_worksheet','{\"key\":\"Excel.delete_excel_worksheet\",\"title\":\"删除Excel工作表\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().delete_excel_worksheet\",\"comment\":\"删除Excel对象 @{excel} 中工作表 @{del_sheet_name}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"del_sheet_name\",\"title\":\"删除工作表\",\"name\":\"del_sheet_name\",\"tip\":\"工作表可以填写名称或序号,如\'Sheet1\'或\'1\',序号从1开始\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-delete-sheet\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(154,'document/document.Excel','Excel.rename_excel_worksheet','{\"key\":\"Excel.rename_excel_worksheet\",\"title\":\"重命名Excel工作表\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().rename_excel_worksheet\",\"comment\":\"重命名Excel对象 @{excel} 中工作表 @{source_sheet_name} 为 @{new_sheet_name}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"source_sheet_name\",\"title\":\"原工作表\",\"name\":\"source_sheet_name\",\"tip\":\"工作表可以填写名称或序号,如\'Sheet1\'或\'1\',序号从1开始\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"new_sheet_name\",\"title\":\"新工作表名\",\"name\":\"new_sheet_name\",\"tip\":\"工作表可以填写名称或序号,如\'Sheet1\'或\'1\',序号从1开始\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-rename-sheet\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(155,'document/document.Excel','Excel.copy_excel_worksheet','{\"key\":\"Excel.copy_excel_worksheet\",\"title\":\"复制Excel工作表\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().copy_excel_worksheet\",\"comment\":\"复制Excel对象 @{excel} 中工作表 @{source_sheet_name} ,复制类型为 @{copy_type}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"source_sheet_name\",\"title\":\"原工作表\",\"name\":\"source_sheet_name\",\"tip\":\"工作表可以填写名称或序号,如\'Sheet1\'或\'1\',序号从1开始\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"new_sheet_name\",\"title\":\"新工作表名\",\"name\":\"new_sheet_name\",\"tip\":\"工作表可以填写名称或序号,如\'Sheet1\'或\'1\',序号从1开始\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"CopySheetLocationType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"location\",\"title\":\"复制位置\",\"name\":\"location\",\"tip\":\"\",\"options\":[{\"label\":\"复制到当前工作表之前\",\"value\":\"before\"},{\"label\":\"复制到当前工作表之后\",\"value\":\"after\"},{\"label\":\"复制到第一个工作表\",\"value\":\"first\"},{\"label\":\"复制到最后一个工作表\",\"value\":\"last\"}],\"default\":\"last\",\"required\":true},{\"types\":\"CopySheetType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"copy_type\",\"title\":\"复制类型\",\"name\":\"copy_type\",\"tip\":\"\",\"options\":[{\"label\":\"当前工作簿\",\"value\":\"current_workbook\"},{\"label\":\"其他工作簿\",\"value\":\"other_workbook\"}],\"default\":\"current_workbook\",\"required\":true},{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"other_excel_obj\",\"title\":\"其他Excel对象\",\"name\":\"other_excel_obj\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.other_excel_obj.show\",\"expression\":\"return $this.copy_type.value == \'other_workbook\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_cover\",\"title\":\"是否覆盖\",\"name\":\"is_cover\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true}],\"outputList\":[],\"icon\":\"excel-copy-sheet\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(156,'document/document.Excel','Excel.get_excel_worksheet_names','{\"key\":\"Excel.get_excel_worksheet_names\",\"title\":\"获取Excel工作表名称\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().get_excel_worksheet_names\",\"comment\":\"获取Excel对象 @{excel} 中工作表名称,返回工作表名称列表 @{sheet_names}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"SheetRangeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"sheet_range\",\"title\":\"工作表范围\",\"name\":\"sheet_range\",\"tip\":\"\",\"options\":[{\"label\":\"当前激活工作表\",\"value\":\"activated\"},{\"label\":\"所有工作表\",\"value\":\"all\"}],\"default\":\"activated\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"sheet_names\",\"title\":\"工作表名称\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\"}],\"icon\":\"excel-get-sheet-names\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(157,'document/document.Excel','Excel.search_and_replace_excel_content','{\"key\":\"Excel.search_and_replace_excel_content\",\"title\":\"查找或替换Excel内容\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().search_and_replace_excel_content\",\"comment\":\"查找或替换Excel对象 @{excel} 中 @{search_range} 范围内 @{find_str} ,返回查找结果 @{search_excel_result}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"find_str\",\"title\":\"查找内容\",\"name\":\"find_str\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"replace_flag\",\"title\":\"是否替换\",\"name\":\"replace_flag\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"replace_str\",\"title\":\"替换内容\",\"name\":\"replace_str\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.replace_str.show\",\"expression\":\"return $this.replace_flag.value == true\"}],\"required\":true},{\"types\":\"SearchSheetType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"lookup_range_excel\",\"title\":\"查找范围\",\"name\":\"lookup_range_excel\",\"tip\":\"\",\"options\":[{\"label\":\"全部工作表\",\"value\":\"all\"},{\"label\":\"单个工作表\",\"value\":\"one\"}],\"default\":\"all\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.sheet_name.show\",\"expression\":\"return $this.lookup_range_excel.value == \'one\'\"}],\"required\":false},{\"types\":\"SearchRangeType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"search_range\",\"title\":\"工作表内查找范围\",\"name\":\"search_range\",\"tip\":\"\",\"options\":[{\"label\":\"已编辑区域\",\"value\":\"all\"},{\"label\":\"行\",\"value\":\"row\"},{\"label\":\"列\",\"value\":\"column\"},{\"label\":\"区域\",\"value\":\"area\"}],\"default\":\"all\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"row\",\"title\":\"行\",\"name\":\"row\",\"tip\":\"输入整数代表行号,从1开始\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.row.show\",\"expression\":\"return $this.search_range.value == \'row\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"col\",\"title\":\"列\",\"name\":\"col\",\"tip\":\"输入列名,支持输入字符A或者整数1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.col.show\",\"expression\":\"return $this.search_range.value == \'column\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"start_row\",\"title\":\"起始行\",\"name\":\"start_row\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.start_row.show\",\"expression\":\"return $this.search_range.value == \'area\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"end_row\",\"title\":\"结束行\",\"name\":\"end_row\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.end_row.show\",\"expression\":\"return $this.search_range.value == \'area\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"start_col\",\"title\":\"起始列\",\"name\":\"start_col\",\"tip\":\"输入列名,支持输入字符A或者整数1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.start_col.show\",\"expression\":\"return $this.search_range.value == \'area\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"end_col\",\"title\":\"结束列\",\"name\":\"end_col\",\"tip\":\"输入列名,支持输入字符A或者整数1,-n代表倒数第n列\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.end_col.show\",\"expression\":\"return $this.search_range.value == \'area\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"exact_match\",\"title\":\"是否精确匹配\",\"name\":\"exact_match\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"case_flag\",\"title\":\"是否区分大小写\",\"name\":\"case_flag\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"MatchCountType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"match_range\",\"title\":\"匹配数量\",\"name\":\"match_range\",\"tip\":\"\",\"options\":[{\"label\":\"所有结果\",\"value\":\"all\"},{\"label\":\"第一个结果\",\"value\":\"first\"}],\"default\":\"all\",\"required\":true},{\"types\":\"SearchResultType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"output_type\",\"title\":\"输出类型\",\"name\":\"output_type\",\"tip\":\"默认返回单元格位置,比如[\'A1\', \'B2\'],也可以选择分开返回行列号,比如[[\'A\', 1], [\'B\', 2]]\",\"options\":[{\"label\":\"返回单元格位置\",\"value\":\"cell\"},{\"label\":\"返回列号和行号\",\"value\":\"col_and_row\"}],\"default\":\"cell\",\"required\":true}],\"outputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"search_excel_result\",\"title\":\"查找结果\",\"tip\":\"选择单工作表查找是返回单元格位置列表,比如[\'A1\', \'B2\'],选择多工作表查找是返回工作表名称和单元格位置列表字典,比如{\'Sheet1\': [\'A1\', \'B2\'], \'Sheet2\': [\'C3\', \'D4\']}\"}],\"icon\":\"excel-find-replace\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(158,'document/document.Excel','Excel.insert_pic','{\"key\":\"Excel.insert_pic\",\"title\":\"插入Excel图片\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().insert_pic\",\"comment\":\"向Excel对象 @{excel} 中工作表 @{sheet_name} 插入图片 @{pic_path} ,插入类型为 @{pic_size_type}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"insert_pos\",\"title\":\"插入位置\",\"name\":\"insert_pos\",\"tip\":\"可填写单元格位置,如\'A1\';也可填写范围位置,如\'A1:B2\'\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"pic_path\",\"title\":\"图片路径\",\"name\":\"pic_path\",\"tip\":\"\",\"required\":true},{\"types\":\"ImageSizeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"pic_size_type\",\"title\":\"图片大小控制\",\"name\":\"pic_size_type\",\"tip\":\"\",\"options\":[{\"label\":\"调整缩放比例\",\"value\":\"scale\"},{\"label\":\"调整高度和宽度数值\",\"value\":\"number\"},{\"label\":\"自动调整大小匹配范围\",\"value\":\"auto\"}],\"default\":\"auto\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"pic_height\",\"title\":\"图片高度\",\"name\":\"pic_height\",\"tip\":\"\",\"default\":300,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.pic_height.show\",\"expression\":\"return $this.pic_size_type.value == \'number\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"pic_width\",\"title\":\"图片宽度\",\"name\":\"pic_width\",\"tip\":\"\",\"default\":400,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.pic_width.show\",\"expression\":\"return $this.pic_size_type.value == \'number\'\"}],\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"pic_scale\",\"title\":\"图片缩放比例\",\"name\":\"pic_scale\",\"tip\":\"\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.pic_scale.show\",\"expression\":\"return $this.pic_size_type.value == \'scale\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-insert-image\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(159,'document/document.Excel','Excel.insert_formula','{\"key\":\"Excel.insert_formula\",\"title\":\"插入Excel公式\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().insert_formula\",\"comment\":\"向Excel对象 @{excel} 中工作表 @{sheet_name} 插入公式 @{formula}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"InsertFormulaDirectionType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"insert_direction\",\"title\":\"公式插入方向\",\"name\":\"insert_direction\",\"tip\":\"\",\"options\":[{\"label\":\"向下插入\",\"value\":\"down\"},{\"label\":\"向右插入\",\"value\":\"right\"}],\"default\":\"down\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"col\",\"title\":\"列\",\"name\":\"col\",\"tip\":\"输入列名,支持输入字符A或者整数1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.col.show\",\"expression\":\"return $this.insert_direction.value == \'down\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"start_row\",\"title\":\"起始行\",\"name\":\"start_row\",\"tip\":\"输入整数代表行号,从1开始\",\"default\":\"1\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.start_row.show\",\"expression\":\"return $this.insert_direction.value == \'down\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"end_row\",\"title\":\"结束行\",\"name\":\"end_row\",\"tip\":\"输入整数代表行号,-n代表倒数第n行\",\"default\":\"-1\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.end_row.show\",\"expression\":\"return $this.insert_direction.value == \'down\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"row\",\"title\":\"行\",\"name\":\"row\",\"tip\":\"输入整数代表行号,从1开始\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.row.show\",\"expression\":\"return $this.insert_direction.value == \'right\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"start_col\",\"title\":\"起始列\",\"name\":\"start_col\",\"tip\":\"输入列名,支持输入字符A或者整数1\",\"default\":\"A\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.start_col.show\",\"expression\":\"return $this.insert_direction.value == \'right\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"end_col\",\"title\":\"结束列\",\"name\":\"end_col\",\"tip\":\"输入列名,支持输入字符A或者整数1,-n代表倒数第n列\",\"default\":\"-1\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.end_col.show\",\"expression\":\"return $this.insert_direction.value == \'right\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"formula\",\"title\":\"插入公式\",\"name\":\"formula\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-insert-formula\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(160,'document/document.Excel','Excel.create_excel_comment','{\"key\":\"Excel.create_excel_comment\",\"title\":\"创建Excel批注\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().create_excel_comment\",\"comment\":\"向Excel对象 @{excel} 中插入批注 @{comment}\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"CreateCommentType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"comment_type\",\"title\":\"批注插入方式\",\"name\":\"comment_type\",\"tip\":\"可以指定单元格插入,也可以搜索内容插入\",\"options\":[{\"label\":\"按照单元格位置插入\",\"value\":\"position\"},{\"label\":\"按照内容搜索插入\",\"value\":\"content\"}],\"default\":\"position\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"comment\",\"title\":\"批注内容\",\"name\":\"comment\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.sheet_name.show\",\"expression\":\"return $this.comment_range.value == \'one\' || $this.comment_type.value == \'position\'\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"cell_position\",\"title\":\"单元格位置\",\"name\":\"cell_position\",\"tip\":\"输入单元格位置,如A1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.cell_position.show\",\"expression\":\"return $this.comment_type.value == \'position\'\"}],\"required\":true},{\"types\":\"SearchSheetType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"comment_range\",\"title\":\"搜索范围\",\"name\":\"comment_range\",\"tip\":\"\",\"options\":[{\"label\":\"全部工作表\",\"value\":\"all\"},{\"label\":\"单个工作表\",\"value\":\"one\"}],\"default\":\"one\",\"dynamics\":[{\"key\":\"$this.comment_range.show\",\"expression\":\"return $this.comment_type.value == \'content\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"find_str\",\"title\":\"搜索内容\",\"name\":\"find_str\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.find_str.show\",\"expression\":\"return $this.comment_type.value == \'content\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"comment_all\",\"title\":\"是否批注所有匹配内容\",\"name\":\"comment_all\",\"tip\":\"选择是将会对所有匹配内容进行批注,选择否只会对第一个匹配内容进行批注\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"dynamics\":[{\"key\":\"$this.comment_all.show\",\"expression\":\"return $this.comment_type.value == \'content\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-create-comment\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(161,'document/document.Excel','Excel.delete_excel_comment','{\"key\":\"Excel.delete_excel_comment\",\"title\":\"删除Excel批注\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().delete_excel_comment\",\"comment\":\"删除Excel对象 @{excel} 中批注\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel\",\"title\":\"Excel对象\",\"name\":\"excel\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"delete_all\",\"title\":\"是否删除所有批注\",\"name\":\"delete_all\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"cell_position\",\"title\":\"单元格位置\",\"name\":\"cell_position\",\"tip\":\"输入单元格位置,如A1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.cell_position.show\",\"expression\":\"return $this.delete_all.value == false\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-delete-comment\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(162,'document/document.Excel','Excel.excel_text_to_number','{\"key\":\"Excel.excel_text_to_number\",\"title\":\"Excel区域文本转数字\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().excel_text_to_number\",\"comment\":\"将Excel对象 @{excel_obj} 中工作表 @{sheet_name} 中的区域文本转化为数字格式\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel_obj\",\"title\":\"Excel对象\",\"name\":\"excel_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"ReadRangeType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"select_type\",\"title\":\"区域选择\",\"name\":\"select_type\",\"tip\":\"\",\"options\":[{\"label\":\"单元格\",\"value\":\"cell\"},{\"label\":\"行\",\"value\":\"row\"},{\"label\":\"列\",\"value\":\"column\"},{\"label\":\"区域\",\"value\":\"area\"},{\"label\":\"已编辑区域\",\"value\":\"all\"}],\"default\":\"cell\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"cell_position\",\"title\":\"单元格位置\",\"name\":\"cell_position\",\"tip\":\"输入单元格位置,如A1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.cell_position.show\",\"expression\":\"return $this.select_type.value == \'cell\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"row\",\"title\":\"行\",\"name\":\"row\",\"tip\":\"输入整数代表行号,从1开始\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.row.show\",\"expression\":\"return $this.select_type.value == \'row\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"col\",\"title\":\"列\",\"name\":\"col\",\"tip\":\"输入列名,支持输入字符A或者整数1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.col.show\",\"expression\":\"return $this.select_type.value == \'column\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"range_location\",\"title\":\"单元格范围\",\"name\":\"range_location\",\"tip\":\"输入单元格范围,如A1:B2\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.range_location.show\",\"expression\":\"return $this.select_type.value == \'area\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-text-to-number\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(163,'document/document.Excel','Excel.excel_number_to_text','{\"key\":\"Excel.excel_number_to_text\",\"title\":\"Excel区域数字转文本\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().excel_number_to_text\",\"comment\":\"将Excel对象 @{excel_obj} 中工作表 @{sheet_name} 中的区域数字转化为文本格式\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel_obj\",\"title\":\"Excel对象\",\"name\":\"excel_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"ReadRangeType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"select_type\",\"title\":\"区域选择\",\"name\":\"select_type\",\"tip\":\"\",\"options\":[{\"label\":\"单元格\",\"value\":\"cell\"},{\"label\":\"行\",\"value\":\"row\"},{\"label\":\"列\",\"value\":\"column\"},{\"label\":\"区域\",\"value\":\"area\"},{\"label\":\"已编辑区域\",\"value\":\"all\"}],\"default\":\"cell\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"cell_position\",\"title\":\"单元格位置\",\"name\":\"cell_position\",\"tip\":\"输入单元格位置,如A1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.cell_position.show\",\"expression\":\"return $this.select_type.value == \'cell\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"row\",\"title\":\"行\",\"name\":\"row\",\"tip\":\"输入整数代表行号,从1开始\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.row.show\",\"expression\":\"return $this.select_type.value == \'row\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"col\",\"title\":\"列\",\"name\":\"col\",\"tip\":\"输入列名,支持输入字符A或者整数1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.col.show\",\"expression\":\"return $this.select_type.value == \'column\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"range_location\",\"title\":\"单元格范围\",\"name\":\"range_location\",\"tip\":\"输入单元格范围,如A1:B2\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.range_location.show\",\"expression\":\"return $this.select_type.value == \'area\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-number-to-text\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(164,'document/document.Excel','Excel.excel_set_col_width','{\"key\":\"Excel.excel_set_col_width\",\"title\":\"设置Excel列宽\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().excel_set_col_width\",\"comment\":\"设置Excel对象 @{excel_obj} 工作表 @{sheet_name} 中 @{col} 的列宽\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel_obj\",\"title\":\"Excel对象\",\"name\":\"excel_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"SetType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"set_type\",\"title\":\"设置类型\",\"name\":\"set_type\",\"tip\":\"\",\"options\":[{\"label\":\"设置值\",\"value\":\"value\"},{\"label\":\"自动调整\",\"value\":\"auto\"}],\"default\":\"auto\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"col\",\"title\":\"列\",\"name\":\"col\",\"tip\":\"输入列名,支持输入字符A或者整数1\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"width\",\"title\":\"列宽\",\"name\":\"width\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.width.show\",\"expression\":\"return $this.set_type.value == \'value\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-set-column-width\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(165,'document/document.Excel','Excel.excel_set_row_height','{\"key\":\"Excel.excel_set_row_height\",\"title\":\"设置Excel行高\",\"version\":\"1.0.0\",\"src\":\"astronverse.excel.excel.Excel().excel_set_row_height\",\"comment\":\"设置Excel对象 @{excel_obj} 工作表 @{sheet_name} 中 @{row} 的行高\",\"inputList\":[{\"types\":\"ExcelObj\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel_obj\",\"title\":\"Excel对象\",\"name\":\"excel_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"sheet_name\",\"title\":\"工作表名\",\"name\":\"sheet_name\",\"tip\":\"输入需编辑的工作表名称,如\'Sheet1\',为空默认使用Excel文件中的第一个工作表对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"SetType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"set_type\",\"title\":\"设置类型\",\"name\":\"set_type\",\"tip\":\"\",\"options\":[{\"label\":\"设置值\",\"value\":\"value\"},{\"label\":\"自动调整\",\"value\":\"auto\"}],\"default\":\"auto\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"row\",\"title\":\"行\",\"name\":\"row\",\"tip\":\"输入整数代表行号,从1开始\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"height\",\"title\":\"行高\",\"name\":\"height\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.height.show\",\"expression\":\"return $this.set_type.value == \'value\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"excel-set-row-height\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(166,'keyboard','Gui.keyboard','{\"key\":\"Gui.keyboard\",\"title\":\"键盘输入\",\"version\":\"1.0.0\",\"src\":\"astronverse.input.gui_key.GuiKeyBoard().keyboard\",\"comment\":\"通过(@{keyboard_type})方式模拟键盘输入(@{message})\",\"inputList\":[{\"types\":\"KeyboardType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"keyboard_type\",\"title\":\"输入方式\",\"name\":\"keyboard_type\",\"tip\":\"普通输入:windows键盘消息的方式来模拟按键输入;剪切板输入:获取剪切板内容并粘贴输入;按键组合:使用插入键盘符号组合快捷输入;驱动输入:使用驱动来模拟按键输入,一般用于网银密码框输入场景或其它普通输入方式无法输入的场景\",\"options\":[{\"label\":\"普通输入\",\"value\":\"normal\"},{\"label\":\"驱动输入\",\"value\":\"driver\"},{\"label\":\"剪贴板输入\",\"value\":\"clip\"},{\"label\":\"ghost输入\",\"value\":\"gblid\"}],\"default\":\"normal\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\",\"params\":{\"size\":\"middle\"}},\"key\":\"message\",\"title\":\"输入内容\",\"name\":\"message\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.message.show\",\"expression\":\"return [\'normal\', \'driver\', \'gblid\'].includes($this.keyboard_type.value)\"}],\"required\":true},{\"types\":\"Simulate_flag\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"simulate_flag\",\"title\":\"模拟人工输入\",\"name\":\"simulate_flag\",\"tip\":\"模拟人工方式操作键盘逐个输入字符,默认为否\",\"options\":[{\"label\":\"是\",\"value\":\"yes\"},{\"label\":\"否\",\"value\":\"no\"}],\"default\":\"no\",\"dynamics\":[{\"key\":\"$this.simulate_flag.show\",\"expression\":\"return $this.keyboard_type.value == \'normal\'\"}],\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"interval\",\"title\":\"输入间隔\",\"name\":\"interval\",\"tip\":\"设置输入间隔,单位为秒\",\"default\":0.1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.interval.show\",\"expression\":\"return [\'normal\', \'driver\'].includes($this.keyboard_type.value)\"}],\"required\":true}],\"outputList\":[],\"icon\":\"keyboard-input\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(167,'keyboard','Gui.key_input','{\"key\":\"Gui.key_input\",\"title\":\"键盘模拟按键\",\"version\":\"1.0.0\",\"src\":\"astronverse.input.gui_key.GuiKeyBoard().key_input\",\"comment\":\"使用键盘模拟按键(@{keys_str})(@{key_model})\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"KEYBOARD\"},\"key\":\"keys_str\",\"title\":\"按键组合\",\"name\":\"keys_str\",\"tip\":\"设置按键组合\",\"default\":\"\",\"required\":true},{\"types\":\"KeyModel\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"key_model\",\"title\":\"按键方式\",\"name\":\"key_model\",\"tip\":\"设置按键方式\",\"options\":[{\"label\":\"单击\",\"value\":\"click\"},{\"label\":\"按下\",\"value\":\"down\"},{\"label\":\"弹起\",\"value\":\"up\"}],\"default\":\"click\",\"required\":true}],\"outputList\":[],\"icon\":\"keyboard-simulate-key\",\"helpManual\":\"通过设置键盘按键进行输入\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(168,'keyboard','Gui.mouse','{\"key\":\"Gui.mouse\",\"title\":\"鼠标点击\",\"version\":\"1.0.0\",\"src\":\"astronverse.input.gui_mouse.GuiMouse().mouse\",\"comment\":\"模拟鼠标(@{btn_type:左键/右键/中键}) (@{btn_model:按下/弹起/单机/双击}))\",\"inputList\":[{\"types\":\"BtnType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"btn_type\",\"title\":\"鼠标按键\",\"name\":\"btn_type\",\"tip\":\"选择点击鼠标上的键位\",\"options\":[{\"label\":\"左键\",\"value\":\"left\"},{\"label\":\"中键\",\"value\":\"middle\"},{\"label\":\"右键\",\"value\":\"right\"}],\"default\":\"left\",\"required\":true},{\"types\":\"BtnModel\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"btn_model\",\"title\":\"点击方式\",\"name\":\"btn_model\",\"tip\":\"选择操作鼠标的点击方式\",\"options\":[{\"label\":\"单击\",\"value\":\"click\"},{\"label\":\"双击\",\"value\":\"double_click\"},{\"label\":\"按下\",\"value\":\"down\"},{\"label\":\"弹起\",\"value\":\"up\"}],\"default\":\"click\",\"required\":true},{\"types\":\"ControlType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"ctrl_type\",\"title\":\"键盘辅助按键\",\"name\":\"ctrl_type\",\"tip\":\"选择键盘辅助按键,默认为无\",\"options\":[{\"label\":\"无\",\"value\":\"none\"},{\"label\":\"ctrl\",\"value\":\"ctrl\"},{\"label\":\"alt\",\"value\":\"alt\"},{\"label\":\"shift\",\"value\":\"shift\"},{\"label\":\"win\",\"value\":\"win\"},{\"label\":\"space\",\"value\":\"space\"}],\"default\":\"none\",\"level\":\"advanced\",\"required\":true}],\"outputList\":[],\"icon\":\"mouse-click\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(169,'keyboard','Gui.mouse_wheel','{\"key\":\"Gui.mouse_wheel\",\"title\":\"鼠标滚动\",\"version\":\"1.0.0\",\"src\":\"astronverse.input.gui_mouse.GuiMouse().mouse_wheel\",\"comment\":\"模拟鼠标(@{scroll_type})滚动(@{scroll_px||times}),滚动方向为:(@{direction})\",\"inputList\":[{\"types\":\"ScrollType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"scroll_type\",\"title\":\"滚动方式\",\"name\":\"scroll_type\",\"tip\":\"\",\"options\":[{\"label\":\"按次数\",\"value\":\"time\"},{\"label\":\"按像素\",\"value\":\"px\"}],\"default\":\"time\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"times\",\"title\":\"自定义次数\",\"name\":\"times\",\"tip\":\"输入鼠标滚动的次数,默认滚动一次距离为120个网页像素\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.times.show\",\"expression\":\"return $this.scroll_type.value == \'time\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"scroll_px\",\"title\":\"自定义像素\",\"name\":\"scroll_px\",\"tip\":\"输入自定义像素,单位为px,一般为0-9999之间的数值\",\"default\":120,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.scroll_px.show\",\"expression\":\"return $this.scroll_type.value == \'px\'\"}],\"required\":true},{\"types\":\"Direction\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"direction\",\"title\":\"滚动方向\",\"name\":\"direction\",\"tip\":\"\",\"options\":[{\"label\":\"向上\",\"value\":\"up\"},{\"label\":\"向下\",\"value\":\"down\"}],\"default\":\"down\",\"required\":true},{\"types\":\"ControlType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"ctrl_type\",\"title\":\"键盘辅助按键\",\"name\":\"ctrl_type\",\"tip\":\"选择键盘辅助按键,默认为无\",\"options\":[{\"label\":\"无\",\"value\":\"none\"},{\"label\":\"ctrl\",\"value\":\"ctrl\"},{\"label\":\"alt\",\"value\":\"alt\"},{\"label\":\"shift\",\"value\":\"shift\"},{\"label\":\"win\",\"value\":\"win\"},{\"label\":\"space\",\"value\":\"space\"}],\"default\":\"none\",\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.ctrl_type.show\",\"expression\":\"return [\'px\', \'time\'].includes($this.scroll_type.value)\"}],\"required\":true}],\"outputList\":[],\"icon\":\"mouse-scroll-webpage\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(170,'keyboard','Gui.mouse_move','{\"key\":\"Gui.mouse_move\",\"title\":\"鼠标移动\",\"version\":\"1.0.0\",\"src\":\"astronverse.input.gui_mouse.GuiMouse().mouse_move\",\"comment\":\"在(@{window_type})上模拟鼠标移动到(@{position_x}, @{position_y})\",\"inputList\":[{\"types\":\"WindowType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"window_type\",\"title\":\"窗口类型\",\"name\":\"window_type\",\"tip\":\"整个屏幕:以屏幕左上角为坐标相对位置;激活窗口:以激活窗口左上角为相对坐标位置\",\"options\":[{\"label\":\"整个屏幕\",\"value\":\"fullscreen\"},{\"label\":\"激活窗口\",\"value\":\"active_window\"}],\"default\":\"fullscreen\",\"required\":true},{\"types\":\"List\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\",\"params\":{\"size\":\"middle\"}},\"key\":\"window_position\",\"title\":\"窗口左上角位置\",\"name\":\"window_position\",\"tip\":\"\",\"dynamics\":[{\"key\":\"$this.window_position.show\",\"expression\":\"return $this.window_type.value == \'active_window\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"MOUSEPOSITION\",\"params\":{\"size\":\"middle\"}},\"key\":\"get_mouse_position\",\"title\":\"获取鼠标位置\",\"name\":\"get_mouse_position\",\"tip\":\"\",\"default\":\"\",\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\",\"params\":{\"size\":\"middle\"}},\"key\":\"position_x\",\"title\":\"鼠标x位置\",\"name\":\"position_x\",\"tip\":\"\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\",\"params\":{\"size\":\"middle\"}},\"key\":\"position_y\",\"title\":\"鼠标y位置\",\"name\":\"position_y\",\"tip\":\"\",\"required\":true},{\"types\":\"MoveType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"move_type\",\"title\":\"鼠标移动方式\",\"name\":\"move_type\",\"tip\":\"选择鼠标移动方式\",\"options\":[{\"label\":\"匀速直线移动\",\"value\":\"linear\"},{\"label\":\"模拟人工方式\",\"value\":\"simulation\"},{\"label\":\"瞬时移动\",\"value\":\"teleportation\"}],\"default\":\"linear\",\"required\":true},{\"types\":\"Speed\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"move_speed\",\"title\":\"鼠标移动速度\",\"name\":\"move_speed\",\"tip\":\"\",\"options\":[{\"label\":\"慢速\",\"value\":\"slow\"},{\"label\":\"正常\",\"value\":\"normal\"},{\"label\":\"快速\",\"value\":\"fast\"}],\"default\":\"normal\",\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.move_speed.show\",\"expression\":\"return [\'linear\', \'simulation\'].includes($this.move_type.value)\"}],\"required\":true}],\"outputList\":[],\"icon\":\"mouse-move\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(171,'keyboard','Gui.mouse_drag','{\"key\":\"Gui.mouse_drag\",\"title\":\"鼠标拖拽\",\"version\":\"1.0.0\",\"src\":\"astronverse.input.gui_mouse.GuiMouse().mouse_drag\",\"comment\":\"模拟鼠标从起点位置(@{start_pos_x}, @{start_pos_y})拖拽到终点位置(@{end_pos_x}, @{end_pos_y})\",\"inputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\",\"params\":{\"size\":\"middle\"}},\"key\":\"start_pos_x\",\"title\":\"鼠标起点x位置\",\"name\":\"start_pos_x\",\"tip\":\"\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\",\"params\":{\"size\":\"middle\"}},\"key\":\"start_pos_y\",\"title\":\"鼠标起点y位置\",\"name\":\"start_pos_y\",\"tip\":\"\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\",\"params\":{\"size\":\"middle\"}},\"key\":\"end_pos_x\",\"title\":\"鼠标终点x位置\",\"name\":\"end_pos_x\",\"tip\":\"\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\",\"params\":{\"size\":\"middle\"}},\"key\":\"end_pos_y\",\"title\":\"鼠标终点y位置\",\"name\":\"end_pos_y\",\"tip\":\"\",\"required\":true},{\"types\":\"BtnType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"btn_type\",\"title\":\"鼠标按键\",\"name\":\"btn_type\",\"tip\":\"拖拽时按下的鼠标键位\",\"options\":[{\"label\":\"左键\",\"value\":\"left\"},{\"label\":\"中键\",\"value\":\"middle\"},{\"label\":\"右键\",\"value\":\"right\"}],\"default\":\"left\",\"required\":true},{\"types\":\"MoveType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"move_type\",\"title\":\"移动方式\",\"name\":\"move_type\",\"tip\":\"选择鼠标移动方式\",\"options\":[{\"label\":\"匀速直线移动\",\"value\":\"linear\"},{\"label\":\"模拟人工方式\",\"value\":\"simulation\"},{\"label\":\"瞬时移动\",\"value\":\"teleportation\"}],\"default\":\"linear\",\"required\":true},{\"types\":\"Speed\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"move_speed\",\"title\":\"移动速度\",\"name\":\"move_speed\",\"tip\":\"选择鼠标移动速度\",\"options\":[{\"label\":\"慢速\",\"value\":\"slow\"},{\"label\":\"正常\",\"value\":\"normal\"},{\"label\":\"快速\",\"value\":\"fast\"}],\"default\":\"normal\",\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.move_speed.show\",\"expression\":\"return [\'linear\', \'simulation\'].includes($this.move_type.value)\"}],\"required\":true},{\"types\":\"ControlType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"ctrl_type\",\"title\":\"键盘辅助按键\",\"name\":\"ctrl_type\",\"tip\":\"选择鼠标拖拽时的键盘辅助按键,默认为无\",\"options\":[{\"label\":\"无\",\"value\":\"none\"},{\"label\":\"ctrl\",\"value\":\"ctrl\"},{\"label\":\"alt\",\"value\":\"alt\"},{\"label\":\"shift\",\"value\":\"shift\"},{\"label\":\"win\",\"value\":\"win\"},{\"label\":\"space\",\"value\":\"space\"}],\"default\":\"none\",\"level\":\"advanced\",\"required\":true}],\"outputList\":[],\"icon\":\"mouse-drag\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(172,'keyboard','Gui.mouse_position','{\"key\":\"Gui.mouse_position\",\"title\":\"获取鼠标位置\",\"version\":\"1.0.0\",\"src\":\"astronverse.input.gui_mouse.GuiMouse().mouse_position\",\"comment\":\"获取当前鼠标位置并输出至(@{point_x}, @{point_y})\",\"inputList\":[],\"outputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"point_x\",\"title\":\"鼠标x位置\",\"tip\":\"\"},{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"point_y\",\"title\":\"鼠标y位置\",\"tip\":\"\"}],\"icon\":\"get-mouse-position\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(173,'network/ftp','Network.ftp_create','{\"key\":\"Network.ftp_create\",\"title\":\"创建FTP连接\",\"version\":\"1.0.0\",\"src\":\"astronverse.network.ftp.FTP().ftp_create\",\"comment\":\"建立与地址(@{host}),端口(@{port})的FTP连接,输出为(@{ftp_instance})\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"host\",\"title\":\"服务器地址\",\"name\":\"host\",\"tip\":\"FTP服务器地址\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"port\",\"title\":\"服务器端口号\",\"name\":\"port\",\"tip\":\"FTP服务器端口号\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"name\",\"title\":\"用户名\",\"name\":\"name\",\"tip\":\"文件服务器提供的可登录账号\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"password\",\"title\":\"用户密码\",\"name\":\"password\",\"tip\":\"文件服务器提供的可登录账号的密码\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"ftp_instance\",\"title\":\"保存FTP连接对象至\",\"tip\":\"将创建的FTP连接对象保存至指定变量中\"}],\"icon\":\"ftp-create-connection\",\"helpManual\":\"建立一个文件服务器的FTP连接,并返回连接对象\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(174,'network/ftp','Network.ftp_close','{\"key\":\"Network.ftp_close\",\"title\":\"关闭FTP连接\",\"version\":\"1.0.0\",\"src\":\"astronverse.network.ftp.FTP().ftp_close\",\"comment\":\"断开与(@{ftp_instance})的FTP连接,并将结果输出至变量(@{close_ftp})\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"ftp_instance\",\"title\":\"FTP对象\",\"name\":\"ftp_instance\",\"tip\":\"待断开的FTP连接对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"close_ftp\",\"title\":\"断开结果保存至\",\"tip\":\"FTP连接是否成功断开的布尔值\"}],\"icon\":\"ftp-close-connection\",\"helpManual\":\"断开一个FTP连接,并返回断开结果\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(175,'network/ftp','Network.get_work_dir','{\"key\":\"Network.get_work_dir\",\"title\":\"获取工作目录(FTP)\",\"version\":\"1.0.0\",\"src\":\"astronverse.network.ftp.FTP().get_work_dir\",\"comment\":\"获取(@{ftp_instance})当前的工作目录,输出为(@{get_work_dir})\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"ftp_instance\",\"title\":\"FTP连接对象\",\"name\":\"ftp_instance\",\"tip\":\"当前FTP连接对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_work_dir\",\"title\":\"工作目录保存至\",\"tip\":\"输出获取到的工作目录\"}],\"icon\":\"get-work-directory\",\"helpManual\":\"获取FTP对象当前工作目录\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(176,'network/ftp','Network.change_working_dir','{\"key\":\"Network.change_working_dir\",\"title\":\"切换工作目录(FTP)\",\"version\":\"1.0.0\",\"src\":\"astronverse.network.ftp.FTP().change_working_dir\",\"comment\":\"切换FTP连接(@{ftp_instance})的工作目录为(@{new_work_dir}),并保存切换后工作目录到(@{change_work_dir})中\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"ftp_instance\",\"title\":\"FTP连接对象\",\"name\":\"ftp_instance\",\"tip\":\"需要切换工作目录的FTP连接对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"new_work_dir\",\"title\":\"工作目录\",\"name\":\"new_work_dir\",\"tip\":\"需要切换到的新的工作目录\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"change_work_dir\",\"title\":\"切换后工作目录\",\"tip\":\"输出切换后当前工作目录\"}],\"icon\":\"change-work-directory\",\"helpManual\":\"切换FTP连接当前工作目录到指定路径\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(177,'network/ftp','Network.create_folder','{\"key\":\"Network.create_folder\",\"title\":\"创建文件夹(FTP)\",\"version\":\"1.0.0\",\"src\":\"astronverse.network.ftp.FTP().create_folder\",\"comment\":\"在指定FTP连接(@{ftp_instance})下创建文件夹(@{folder_name}),并保存新文件夹路径到(@{new_folder})中\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"ftp_instance\",\"title\":\"FTP连接对象\",\"name\":\"ftp_instance\",\"tip\":\"需要创建文件夹的FTP连接对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"folder_name\",\"title\":\"新文件夹名称\",\"name\":\"folder_name\",\"tip\":\"需要创建的文件夹名称\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"exist_type\",\"title\":\"文件夹存在时\",\"name\":\"exist_type\",\"tip\":\"当FTP连接下存在同名文件夹时需要执行的操作\",\"options\":[{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"new_folder\",\"title\":\"创建后文件夹路径\",\"tip\":\"将创建后的文件夹路径保存至变量\"}],\"icon\":\"create-folder\",\"helpManual\":\"在指定FTP连接下创建文件夹\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(178,'network/ftp','Network.get_ftp_list','{\"key\":\"Network.get_ftp_list\",\"title\":\"获取文件/文件夹(FTP)\",\"version\":\"1.0.0\",\"src\":\"astronverse.network.ftp.FTP().get_ftp_list\",\"comment\":\"获取指定FTP连接(@{ftp_instance})下的(@{file_type})列表,并保存到(@{get_ftp_list})中\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"ftp_instance\",\"title\":\"FTP连接对象\",\"name\":\"ftp_instance\",\"tip\":\"需要获取文件和文件夹信息的FTP连接对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"ListType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"file_type\",\"title\":\"获取对象\",\"name\":\"file_type\",\"tip\":\"选择需要获取的对象\",\"options\":[{\"label\":\"全部\",\"value\":\"all\"},{\"label\":\"文件\",\"value\":\"file\"},{\"label\":\"文件夹\",\"value\":\"folder\"}],\"default\":\"file\",\"required\":false}],\"outputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_ftp_list\",\"title\":\"获取的文件/文件夹列表\",\"tip\":\"将FTP连接下的文件/文件夹列表输出至变量\"}],\"icon\":\"get-folder\",\"helpManual\":\"获取指定FTP连接下的全部文件/文件夹列表\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(179,'network/ftp','Network.ftp_rename','{\"key\":\"Network.ftp_rename\",\"title\":\"重命名文件/文件夹(FTP)\",\"version\":\"1.0.0\",\"src\":\"astronverse.network.ftp.FTP().ftp_rename\",\"comment\":\"重命名(@{ftp_instance})中(@{file_type})(@{cur_file_name||cur_folder_name})为新名称(@{new_file_name||new_folder_name}),并将重命名后路径保存至变量(@{rename_ftp_path})\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"ftp_instance\",\"title\":\"FTP连接对象\",\"name\":\"ftp_instance\",\"tip\":\"执行文件/文件夹重命名操作的FTP连接对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"FileType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"file_type\",\"title\":\"重命名对象\",\"name\":\"file_type\",\"tip\":\"\",\"options\":[{\"label\":\"文件\",\"value\":\"file\"},{\"label\":\"文件夹\",\"value\":\"folder\"}],\"default\":\"file\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"cur_file_name\",\"title\":\"原文件名称\",\"name\":\"cur_file_name\",\"tip\":\"输入待重命名文件\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.cur_file_name.show\",\"expression\":\"return $this.file_type.value == \'file\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"new_file_name\",\"title\":\"新文件名称(不包含文件扩展名)\",\"name\":\"new_file_name\",\"tip\":\"输入新文件名称,不包含文件扩展名\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.new_file_name.show\",\"expression\":\"return $this.file_type.value == \'file\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"cur_folder_name\",\"title\":\"原文件夹名称\",\"name\":\"cur_folder_name\",\"tip\":\"输入待重命名文件夹\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.cur_folder_name.show\",\"expression\":\"return $this.file_type.value == \'folder\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"new_folder_name\",\"title\":\"新文件夹名称\",\"name\":\"new_folder_name\",\"tip\":\"输入新文件夹名称\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.new_folder_name.show\",\"expression\":\"return $this.file_type.value == \'folder\'\"}],\"required\":true},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"exist_type\",\"title\":\"重命名对象存在时\",\"name\":\"exist_type\",\"tip\":\"重命名后对象已存在时执行的操作\",\"options\":[{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"rename_ftp_path\",\"title\":\"重命名后路径\",\"tip\":\"保存重命名后(@{file_type})路径至变量\"}],\"icon\":\"rename-folder\",\"helpManual\":\"重命名FTP服务器上文件/文件夹\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(180,'network/ftp','Network.ftp_upload','{\"key\":\"Network.ftp_upload\",\"title\":\"上传文件/文件夹(FTP)\",\"version\":\"1.0.0\",\"src\":\"astronverse.network.ftp.FTP().ftp_upload\",\"comment\":\"上传(@{file_path||folder_path})至FTP指定目录(@{ftp_pwd}),并将上传后路径结果保存到(@{upload_ftp_list})中\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"ftp_instance\",\"title\":\"FTP连接对象\",\"name\":\"ftp_instance\",\"tip\":\"需要上传文件/文件夹的FTP连接对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"FileType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"file_type\",\"title\":\"上传对象\",\"name\":\"file_type\",\"tip\":\"\",\"options\":[{\"label\":\"文件\",\"value\":\"file\"},{\"label\":\"文件夹\",\"value\":\"folder\"}],\"default\":\"file\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"ftp_pwd\",\"title\":\"远程工作目录\",\"name\":\"ftp_pwd\",\"tip\":\"文件/文件夹上传的远程工作目录,默认为空,上传至当前工作路径\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"files\"}},\"key\":\"file_path\",\"title\":\"待上传文件\",\"name\":\"file_path\",\"tip\":\"支持单个或多个文件上传,多个文件名之间用逗号隔开,如:test1.txt,test2.txt,test3.txt\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.file_path.show\",\"expression\":\"return $this.file_type.value == \'file\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"folder_path\",\"title\":\"待上传文件夹\",\"name\":\"folder_path\",\"tip\":\"支持单个或多个文件夹上传,多个文件夹之间用逗号隔开,如:folder1,folder2,folder3\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.folder_path.show\",\"expression\":\"return $this.file_type.value == \'folder\'\"}],\"required\":true},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"exist_type\",\"title\":\"上传对象已存在时\",\"name\":\"exist_type\",\"tip\":\"要上传的文件/文件夹在FTP服务器上已存在时的处理方式\",\"options\":[{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"required\":false}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"upload_ftp_list\",\"title\":\"上传列表\",\"tip\":\"输出已上传文件/文件夹在FTP服务器上的路径信息至变量,数据类型为列表\"}],\"icon\":\"upload-folder\",\"helpManual\":\"将本地一个或多个文件/文件夹上传到至FTP指定目录下\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(181,'network/ftp','Network.ftp_download','{\"key\":\"Network.ftp_download\",\"title\":\"下载文件/文件夹(FTP)\",\"version\":\"1.0.0\",\"src\":\"astronverse.network.ftp.FTP().ftp_download\",\"comment\":\"下载(@{download_file_name||download_folder_name})至本地目录(@{dst_path}),并将下载后路径保存到变量(@{download_ftp_path})\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"ftp_instance\",\"title\":\"FTP连接对象\",\"name\":\"ftp_instance\",\"tip\":\"执行下载文件/文件夹的FTP服务器连接对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"FileType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"file_type\",\"title\":\"下载对象\",\"name\":\"file_type\",\"tip\":\"\",\"options\":[{\"label\":\"文件\",\"value\":\"file\"},{\"label\":\"文件夹\",\"value\":\"folder\"}],\"default\":\"file\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"download_file_name\",\"title\":\"待下载文件\",\"name\":\"download_file_name\",\"tip\":\"支持单个或多个文件下载,多个文件名之间用逗号隔开,如:test1.txt,test2.txt,test3.txt\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.download_file_name.show\",\"expression\":\"return $this.file_type.value == \'file\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"download_folder_name\",\"title\":\"待下载文件夹\",\"name\":\"download_folder_name\",\"tip\":\"支持单个或多个文件夹下载,多个文件夹之间用逗号隔开,如:folder1,folder2,folder3\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.download_folder_name.show\",\"expression\":\"return $this.file_type.value == \'folder\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"dst_path\",\"title\":\"下载至\",\"name\":\"dst_path\",\"tip\":\"本地存储路径\",\"default\":\"\",\"required\":true},{\"types\":\"StateType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"state_type\",\"title\":\"本地路径不存在时\",\"name\":\"state_type\",\"tip\":\"当本地存储路径不存在时执行的操作\",\"options\":[{\"label\":\"新建\",\"value\":\"create\"},{\"label\":\"提示并报错\",\"value\":\"error\"}],\"default\":\"create\",\"required\":false},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"exist_type\",\"title\":\"下载对象存在时\",\"name\":\"exist_type\",\"tip\":\"下载文件/文件夹存在时执行的操作\",\"options\":[{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"required\":false}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"download_ftp_path\",\"title\":\"下载列表\",\"tip\":\"输出已下载的文件/文件夹路径列表至变量,数据类型为列表\"}],\"icon\":\"download-folder\",\"helpManual\":\"将FTP服务器上的多个文件/文件夹下载至本地\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(182,'network/ftp','Network.ftp_delete','{\"key\":\"Network.ftp_delete\",\"title\":\"删除文件/文件夹(FTP)\",\"version\":\"1.0.0\",\"src\":\"astronverse.network.ftp.FTP().ftp_delete\",\"comment\":\"删除(@{ftp_instance})上(@{delete_file_name||delete_folder_name}),并输出删除结果至变量(@{delete_ftp_result})\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"ftp_instance\",\"title\":\"FTP连接对象\",\"name\":\"ftp_instance\",\"tip\":\"执行文件/文件夹删除操作的FTP连接对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"FileType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"file_type\",\"title\":\"删除对象\",\"name\":\"file_type\",\"tip\":\"\",\"options\":[{\"label\":\"文件\",\"value\":\"file\"},{\"label\":\"文件夹\",\"value\":\"folder\"}],\"default\":\"file\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"delete_file_name\",\"title\":\"待删除文件\",\"name\":\"delete_file_name\",\"tip\":\"支持单个或多个文件删除,多个文件名之间使用逗号隔开,如:test1.txt,test2.txt,test3.txt\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.delete_file_name.show\",\"expression\":\"return $this.file_type.value == \'file\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"delete_folder_name\",\"title\":\"待删除文件夹\",\"name\":\"delete_folder_name\",\"tip\":\"支持单个或多个文件夹删除,多个文件夹之间用逗号隔开,如:folder1,folder2,folder3\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.delete_folder_name.show\",\"expression\":\"return $this.file_type.value == \'folder\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"delete_ftp_result\",\"title\":\"删除结果\",\"tip\":\"输出删除结果到变量,数据类型为布尔值\"}],\"icon\":\"delete-folder-ftp\",\"helpManual\":\"删除FTP服务器中指定文件/文件夹\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(183,'network/http','Network.http_request','{\"key\":\"Network.http_request\",\"title\":\"HTTP请求\",\"version\":\"1.0.0\",\"src\":\"astronverse.network.network.Network().http_request\",\"comment\":\"向URL(@{url})发送HTTP请求(@{request_type}), 请求头(@{headers}), 请求体(@{body}), 并保存响应结果到{@{http_response}}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"url\",\"title\":\"URL\",\"name\":\"url\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"RequestType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"request_type\",\"title\":\"请求类型\",\"name\":\"request_type\",\"tip\":\"\",\"options\":[{\"label\":\"post\",\"value\":\"post\"},{\"label\":\"get\",\"value\":\"get\"},{\"label\":\"connect\",\"value\":\"connect\"},{\"label\":\"put\",\"value\":\"put\"},{\"label\":\"patch\",\"value\":\"patch\"},{\"label\":\"delete\",\"value\":\"delete\"},{\"label\":\"options\",\"value\":\"options\"},{\"label\":\"head\",\"value\":\"head\"},{\"label\":\"trace\",\"value\":\"trace\"}],\"default\":\"post\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"headers\",\"title\":\"请求头\",\"name\":\"headers\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"body\",\"title\":\"请求体\",\"name\":\"body\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.body.show\",\"expression\":\"return [\'post\', \'put\'].includes($this.request_type.value)\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"待上传文件路径\",\"name\":\"file_path\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.file_path.show\",\"expression\":\"return $this.request_type.value == \'post\'\"}],\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"time_out\",\"title\":\"超时时间\",\"name\":\"time_out\",\"tip\":\"\",\"default\":60,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"SaveType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"save_type\",\"title\":\"响应结果保存到文件\",\"name\":\"save_type\",\"tip\":\"将响应结果保存到指定文本文件中\",\"options\":[{\"label\":\"保存\",\"value\":\"yes\"},{\"label\":\"删除\",\"value\":\"no\"}],\"default\":\"no\",\"level\":\"advanced\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"save_path\",\"title\":\"文档保存目录\",\"name\":\"save_path\",\"tip\":\"输入文件保存目录\",\"default\":\"\",\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.save_path.show\",\"expression\":\"return $this.save_type.value == \'yes\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"save_name\",\"title\":\"文件名称\",\"name\":\"save_name\",\"tip\":\"输入保存文件名称,默认为文本文件\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.save_name.show\",\"expression\":\"return $this.save_type.value == \'yes\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"http_response\",\"title\":\"保存响应结果到\",\"tip\":\"\"}],\"icon\":\"http-request\",\"helpManual\":\"向指定url发送HTTP请求\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(184,'network/http','Network.http_download','{\"key\":\"Network.http_download\",\"title\":\"HTTP下载\",\"version\":\"1.0.0\",\"src\":\"astronverse.network.network.Network().http_download\",\"comment\":\"HTTP下载\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"url\",\"title\":\"下载地址\",\"name\":\"url\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"dst_dir\",\"title\":\"文件保存目录\",\"name\":\"dst_dir\",\"tip\":\"\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"rename\",\"title\":\"指定文件名\",\"name\":\"rename\",\"tip\":\"不指定自动沿用下载路径中的默认文件名,没有默认文件名则报错\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.rename.show\",\"expression\":\"return $this.state_type.value == \'create\'\"}],\"required\":false},{\"types\":\"StateType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"state_type\",\"title\":\"目录不存在时\",\"name\":\"state_type\",\"tip\":\"设置文件保存目录不存在时的处理方式\",\"options\":[{\"label\":\"新建\",\"value\":\"create\"},{\"label\":\"提示并报错\",\"value\":\"error\"}],\"default\":\"create\",\"required\":false},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"exist_type\",\"title\":\"文件存在时\",\"name\":\"exist_type\",\"tip\":\"设置目标文件已存在时的处理方式\",\"options\":[{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"http_download_path\",\"title\":\"下载文件保存到\",\"tip\":\"将下载文件路径保存到变量中\"}],\"icon\":\"http-download\",\"helpManual\":\"下载指定URL(@{url})的文件保存到指定目录(@{dst_dir})中,并保存下载路径到变量(@{http_download_path})\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(185,'ai/ocr','OpenApi.id_card','{\"key\":\"OpenApi.id_card\",\"title\":\"身份证识别\",\"version\":\"1.0.0\",\"src\":\"astronverse.openapi.openapi.OpenApi().id_card\",\"comment\":\"身份证识别\",\"inputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_multi\",\"title\":\"批量处理\",\"name\":\"is_multi\",\"tip\":\"批量处理选择“否”则每次单个处理一份图片文件,选择“是”则默认按文件夹类文件顺序依次进行处理\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\",\"filters\":[\".jpeg\",\".jpg\",\".png\",\".gif\",\".bmp\"]}},\"key\":\"src_file\",\"title\":\"图像文件\",\"name\":\"src_file\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.src_file.show\",\"expression\":\"return $this.is_multi.value == false\"}],\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"folder\"}},\"key\":\"src_dir\",\"title\":\"图像文件夹\",\"name\":\"src_dir\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.src_dir.show\",\"expression\":\"return $this.is_multi.value == true\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_save\",\"title\":\"输出文档\",\"name\":\"is_save\",\"tip\":\"批量处理选择“否”则每次单个处理一份图片文件,选择“是”则默认按文件夹类文件顺序依次进行处理,默认保存为excel文档,不支持修改\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\",\"filters\":[\".xlsx\",\".xls\",\".csv\"],\"defaultPath\":\"未命名.xls\"}},\"key\":\"dst_file\",\"title\":\"文档输出路径\",\"name\":\"dst_file\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.dst_file.show\",\"expression\":\"return $this.is_save.value == true\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dst_file_name\",\"title\":\"文档输出文件名\",\"name\":\"dst_file_name\",\"tip\":\"选择文档输出文件名\",\"default\":\"id_card\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"id_card\",\"title\":\"身份证识别结果对象\",\"tip\":\"输出身份证识别结果\"}],\"icon\":\"id-card-recognition\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(186,'ai/ocr','OpenApi.business_license','{\"key\":\"OpenApi.business_license\",\"title\":\"营业执照识别\",\"version\":\"1.0.0\",\"src\":\"astronverse.openapi.openapi.OpenApi().business_license\",\"comment\":\"营业执照识别\",\"inputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_multi\",\"title\":\"批量处理\",\"name\":\"is_multi\",\"tip\":\"批量处理选择“否”则每次单个处理一份图片文件,选择“是”则默认按文件夹类文件顺序依次进行处理\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\",\"filters\":[\".jpeg\",\".jpg\",\".png\",\".gif\",\".bmp\"]}},\"key\":\"src_file\",\"title\":\"图像文件\",\"name\":\"src_file\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.src_file.show\",\"expression\":\"return $this.is_multi.value == false\"}],\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"folder\"}},\"key\":\"src_dir\",\"title\":\"图像文件夹\",\"name\":\"src_dir\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.src_dir.show\",\"expression\":\"return $this.is_multi.value == true\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_save\",\"title\":\"输出文档\",\"name\":\"is_save\",\"tip\":\"批量处理选择“否”则每次单个处理一份图片文件,选择“是”则默认按文件夹类文件顺序依次进行处理,默认保存为excel文档,不支持修改\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\",\"filters\":[\".xlsx\",\".xls\",\".csv\"],\"defaultPath\":\"未命名.xls\"}},\"key\":\"dst_file\",\"title\":\"文档输出路径\",\"name\":\"dst_file\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.dst_file.show\",\"expression\":\"return $this.is_save.value == true\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dst_file_name\",\"title\":\"文档输出文件名\",\"name\":\"dst_file_name\",\"tip\":\"选择文档输出文件名\",\"default\":\"business_license\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"business_license\",\"title\":\"营业执照结果对象\",\"tip\":\"输出营业执照结果对象\"}],\"icon\":\"business-license-recognition\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(187,'ai/ocr','OpenApi.vat_invoice','{\"key\":\"OpenApi.vat_invoice\",\"title\":\"增值税发票识别\",\"version\":\"1.0.0\",\"src\":\"astronverse.openapi.openapi.OpenApi().vat_invoice\",\"comment\":\"增值税发票识别\",\"inputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_multi\",\"title\":\"批量处理\",\"name\":\"is_multi\",\"tip\":\"批量处理选择“否”则每次单个处理一份图片文件,选择“是”则默认按文件夹类文件顺序依次进行处理\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\",\"filters\":[\".jpeg\",\".jpg\",\".png\",\".gif\",\".bmp\"],\"defaultPath\":\"未命名.xls\"}},\"key\":\"src_file\",\"title\":\"图像文件\",\"name\":\"src_file\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.src_file.show\",\"expression\":\"return $this.is_multi.value == false\"}],\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"folder\"}},\"key\":\"src_dir\",\"title\":\"图像文件夹\",\"name\":\"src_dir\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.src_dir.show\",\"expression\":\"return $this.is_multi.value == true\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_save\",\"title\":\"输出文档\",\"name\":\"is_save\",\"tip\":\"批量处理选择“否”则每次单个处理一份图片文件,选择“是”则默认按文件夹类文件顺序依次进行处理,默认保存为excel文档,不支持修改\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\",\"filters\":[\".xlsx\",\".xls\",\".csv\"]}},\"key\":\"dst_file\",\"title\":\"文档输出路径\",\"name\":\"dst_file\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.dst_file.show\",\"expression\":\"return $this.is_save.value == true\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dst_file_name\",\"title\":\"文档输出文件名\",\"name\":\"dst_file_name\",\"tip\":\"选择文档输出文件名\",\"default\":\"vat_invoice\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"vat_invoice\",\"title\":\"增值税发票识别结果对象\",\"tip\":\"输出增值税发票识别结果对象\"}],\"icon\":\"vat-invoice-recognition\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(188,'ai/ocr','OpenApi.train_ticket','{\"key\":\"OpenApi.train_ticket\",\"title\":\"火车票识别\",\"version\":\"1.0.0\",\"src\":\"astronverse.openapi.openapi.OpenApi().train_ticket\",\"comment\":\"火车票识别\",\"inputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_multi\",\"title\":\"批量处理\",\"name\":\"is_multi\",\"tip\":\"批量处理选择“否”则每次单个处理一份图片文件,选择“是”则默认按文件夹类文件顺序依次进行处理\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\",\"filters\":[\".jpeg\",\".jpg\",\".png\",\".gif\",\".bmp\"]}},\"key\":\"src_file\",\"title\":\"图像文件\",\"name\":\"src_file\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.src_file.show\",\"expression\":\"return $this.is_multi.value == false\"}],\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"folder\"}},\"key\":\"src_dir\",\"title\":\"图像文件夹\",\"name\":\"src_dir\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.src_dir.show\",\"expression\":\"return $this.is_multi.value == true\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_save\",\"title\":\"输出文档\",\"name\":\"is_save\",\"tip\":\"批量处理选择“否”则每次单个处理一份图片文件,选择“是”则默认按文件夹类文件顺序依次进行处理,默认保存为excel文档,不支持修改\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\",\"filters\":[\".xlsx\",\".xls\",\".csv\"],\"defaultPath\":\"未命名.xls\"}},\"key\":\"dst_file\",\"title\":\"文档输出路径\",\"name\":\"dst_file\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.dst_file.show\",\"expression\":\"return $this.is_save.value == true\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dst_file_name\",\"title\":\"文档输出文件名\",\"name\":\"dst_file_name\",\"tip\":\"选择文档输出文件名\",\"default\":\"train_ticket\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"train_ticket\",\"title\":\"火车票识别结果对象\",\"tip\":\"火车票识别结果对象\"}],\"icon\":\"train-ticket-recognition\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(189,'ai/ocr','OpenApi.taxi_ticket','{\"key\":\"OpenApi.taxi_ticket\",\"title\":\"出租车发票识别\",\"version\":\"1.0.0\",\"src\":\"astronverse.openapi.openapi.OpenApi().taxi_ticket\",\"comment\":\"出租车发票识别\",\"inputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_multi\",\"title\":\"批量处理\",\"name\":\"is_multi\",\"tip\":\"批量处理选择“否”则每次单个处理一份图片文件,选择“是”则默认按文件夹类文件顺序依次进行处理\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\",\"filters\":[\".jpeg\",\".jpg\",\".png\",\".gif\",\".bmp\"]}},\"key\":\"src_file\",\"title\":\"图像文件\",\"name\":\"src_file\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.src_file.show\",\"expression\":\"return $this.is_multi.value == false\"}],\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"folder\"}},\"key\":\"src_dir\",\"title\":\"图像文件夹\",\"name\":\"src_dir\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.src_dir.show\",\"expression\":\"return $this.is_multi.value == true\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_save\",\"title\":\"输出文档\",\"name\":\"is_save\",\"tip\":\"批量处理选择“否”则每次单个处理一份图片文件,选择“是”则默认按文件夹类文件顺序依次进行处理,默认保存为excel文档,不支持修改\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\",\"filters\":[\".xlsx\",\".xls\",\".csv\"],\"defaultPath\":\"未命名.xls\"}},\"key\":\"dst_file\",\"title\":\"文档输出路径\",\"name\":\"dst_file\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.dst_file.show\",\"expression\":\"return $this.is_save.value == true\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dst_file_name\",\"title\":\"文档输出文件名\",\"name\":\"dst_file_name\",\"tip\":\"选择文档输出文件名\",\"default\":\"taxi_ticket\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"taxi_ticket\",\"title\":\"出租车发票识别结果对象\",\"tip\":\"出租车发票识别结果对象\"}],\"icon\":\"taxi-invoice-recognition\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(190,'ai/ocr','OpenApi.common_ocr','{\"key\":\"OpenApi.common_ocr\",\"title\":\"通用文字识别\",\"version\":\"1.0.0\",\"src\":\"astronverse.openapi.openapi.OpenApi().common_ocr\",\"comment\":\"通用文字识别\",\"inputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_multi\",\"title\":\"批量处理\",\"name\":\"is_multi\",\"tip\":\"批量处理选择“否”则每次单个处理一份图片文件,选择“是”则默认按文件夹类文件顺序依次进行处理\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\",\"filters\":[\".jpeg\",\".jpg\",\".png\",\".gif\",\".bmp\"]}},\"key\":\"src_file\",\"title\":\"图像文件\",\"name\":\"src_file\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.src_file.show\",\"expression\":\"return $this.is_multi.value == false\"}],\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"folder\"}},\"key\":\"src_dir\",\"title\":\"图像文件夹\",\"name\":\"src_dir\",\"tip\":\"\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.src_dir.show\",\"expression\":\"return $this.is_multi.value == true\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"is_save\",\"title\":\"输出文档\",\"name\":\"is_save\",\"tip\":\"批量处理选择“否”则每次单个处理一份图片文件,选择“是”则默认按文件夹类文件顺序依次进行处理,默认保存为excel文档,不支持修改\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"folder\"}},\"key\":\"dst_file\",\"title\":\"文档输出路径\",\"name\":\"dst_file\",\"tip\":\"选择文档输出文件夹\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.dst_file.show\",\"expression\":\"return $this.is_save.value == true\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dst_file_name\",\"title\":\"文档输出文件名\",\"name\":\"dst_file_name\",\"tip\":\"选择文档输出文件名\",\"default\":\"common_ocr\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"common_ocr\",\"title\":\"通用文字识别结果对象\",\"tip\":\"输出通用文字识别结果对象\"}],\"icon\":\"general-text-recognition\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(191,'document/document.PDF','PDF.get_pages_num','{\"key\":\"PDF.get_pages_num\",\"title\":\"获取PDF文档页数\",\"version\":\"1.0.0\",\"src\":\"astronverse.pdf.pdf.PDF().get_pages_num\",\"comment\":\"获取路径为 @{file_path} 的PDF文档页数 @{pdf_pages_num}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"PDF文件路径\",\"name\":\"file_path\",\"tip\":\"输入PDF文件路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"password\",\"title\":\"PDF文件密码\",\"name\":\"password\",\"tip\":\"输入PDF文件密码,如果没有密码则留空\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"required\":false}],\"outputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"pdf_pages_num\",\"title\":\"PDF文档页数\",\"tip\":\"返回PDF文档页数\"}],\"icon\":\"pdf-get-page-count\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(192,'document/document.PDF','PDF.get_pdf_text','{\"key\":\"PDF.get_pdf_text\",\"title\":\"提取PDF文档文本\",\"version\":\"1.0.0\",\"src\":\"astronverse.pdf.pdf.PDF().get_pdf_text\",\"comment\":\"提取路径为 @{file_path} 的PDF文档文本,返回为字符串或列表 @{pdf_text}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[]}},\"key\":\"file_path\",\"title\":\"PDF文件路径\",\"name\":\"file_path\",\"tip\":\"输入PDF文件路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"password\",\"title\":\"PDF文件密码\",\"name\":\"password\",\"tip\":\"输入PDF文件密码,如果没有密码则留空\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"required\":false},{\"types\":\"SelectRangeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"select_range\",\"title\":\"选择范围\",\"name\":\"select_range\",\"tip\":\"选择范围,支持全部页面和指定页面范围\",\"options\":[{\"label\":\"所有页面\",\"value\":\"all\"},{\"label\":\"指定页面\",\"value\":\"part\"}],\"default\":\"all\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page_range\",\"title\":\"指定页面范围\",\"name\":\"page_range\",\"tip\":\"输入页面范围,格式为1-3,5,7-9,11,表示从1到3页,5页,7到9页,11页\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.page_range.show\",\"expression\":\"return $this.select_range.value == \'part\'\"}],\"required\":true},{\"types\":\"TextSaveType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"text_save_type\",\"title\":\"是否保存为文件\",\"name\":\"text_save_type\",\"tip\":\"选择是否保存提取的文本为文件,可保存为Word或文本文件格式\",\"options\":[{\"label\":\"不保存\",\"value\":\"none\"},{\"label\":\"Word文件\",\"value\":\"word\"},{\"label\":\"文本文件\",\"value\":\"txt\"},{\"label\":\"Word文件和文本文件\",\"value\":\"word_and_txt\"}],\"default\":\"none\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"save_dir\",\"title\":\"保存文件路径\",\"name\":\"save_dir\",\"tip\":\"选择保存文件的文件夹路径\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.save_dir.show\",\"expression\":\"return [\'txt\', \'word_and_txt\', \'word\'].includes($this.text_save_type.value)\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"save_file_name\",\"title\":\"保存文件名\",\"name\":\"save_file_name\",\"tip\":\"输入保存文件名,不输入则使用默认文件名\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.save_file_name.show\",\"expression\":\"return [\'txt\', \'word_and_txt\', \'word\'].includes($this.text_save_type.value)\"}],\"required\":false},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_handle_type\",\"title\":\"存在同名文件处理方式\",\"name\":\"exist_handle_type\",\"tip\":\"选择存在文件处理方式,支持覆盖原有文件、创建文件副本、取消保存操作\",\"options\":[{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.exist_handle_type.show\",\"expression\":\"return [\'txt\', \'word_and_txt\', \'word\'].includes($this.text_save_type.value)\"}],\"required\":true}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"pdf_text\",\"title\":\"提取的PDF文档文本\",\"tip\":\"提取的PDF文档文本,以列表形式存储返回\"}],\"icon\":\"pdf-extract-text\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(193,'document/document.PDF','PDF.get_pdf_images','{\"key\":\"PDF.get_pdf_images\",\"title\":\"提取PDF文档图片\",\"version\":\"1.0.0\",\"src\":\"astronverse.pdf.pdf.PDF().get_pdf_images\",\"comment\":\"提取路径为 @{file_path} 的PDF文档图片,并保存到 @{save_dir} 文件夹\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"PDF文件路径\",\"name\":\"file_path\",\"tip\":\"\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"pwd\",\"title\":\"PDF文件密码\",\"name\":\"pwd\",\"tip\":\"如果PDF文件需要密码,请输入密码,否则留空\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"required\":false},{\"types\":\"SelectRangeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"select_range\",\"title\":\"选择范围\",\"name\":\"select_range\",\"tip\":\"选择范围,支持全部页面和指定页面范围\",\"options\":[{\"label\":\"所有页面\",\"value\":\"all\"},{\"label\":\"指定页面\",\"value\":\"part\"}],\"default\":\"all\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page_range\",\"title\":\"指定页面范围\",\"name\":\"page_range\",\"tip\":\"输入页面范围,格式为1-3,5,7-9,11,表示从1到3页,5页,7到9页,11页\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.page_range.show\",\"expression\":\"return $this.select_range.value == \'part\'\"}],\"required\":false},{\"types\":\"PictureType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"image_type\",\"title\":\"图片格式\",\"name\":\"image_type\",\"tip\":\"选择图片格式,支持JPEG、PNG等格式\",\"options\":[{\"label\":\"PNG\",\"value\":\"png\"},{\"label\":\"JPEG\",\"value\":\"jpeg\"}],\"default\":\"png\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"save_dir\",\"title\":\"保存文件路径\",\"name\":\"save_dir\",\"tip\":\"选择保存文件的文件夹路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"prefix\",\"title\":\"图片文件名前缀\",\"name\":\"prefix\",\"tip\":\"输入图片文件名前缀,不输入则使用原文件名前缀\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_handle_type\",\"title\":\"存在同名文件处理方式\",\"name\":\"exist_handle_type\",\"tip\":\"选择存在文件处理方式,支持覆盖原有文件、创建文件副本、取消保存操作\",\"options\":[{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"level\":\"advanced\",\"required\":true}],\"outputList\":[],\"icon\":\"pdf-extract-images\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(194,'document/document.PDF','PDF.merge_pdf_files','{\"key\":\"PDF.merge_pdf_files\",\"title\":\"合并PDF文件\",\"version\":\"1.0.0\",\"src\":\"astronverse.pdf.pdf.PDF().merge_pdf_files\",\"comment\":\"合并PDF文件为一个PDF文件,并保存到 @{pdf_merge_file_path} 路径\",\"inputList\":[{\"types\":\"MergeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"merge_type\",\"title\":\"合并方式\",\"name\":\"merge_type\",\"tip\":\"选择合并方式,支持按文件夹合并或按文件合并\",\"options\":[{\"label\":\"按文件夹合并\",\"value\":\"folder\"},{\"label\":\"按文件合并\",\"value\":\"file\"}],\"default\":\"folder\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"file_folder_path\",\"title\":\"合并文件夹\",\"name\":\"file_folder_path\",\"tip\":\"将会合并文件夹中所有的PDF文件\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.file_folder_path.show\",\"expression\":\"return $this.merge_type.value == \'folder\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"files\"}},\"key\":\"files_path\",\"title\":\"合并文件\",\"name\":\"files_path\",\"tip\":\"将会合并所选的所有PDF文件\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.files_path.show\",\"expression\":\"return $this.merge_type.value == \'file\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"save_dir\",\"title\":\"保存文件路径\",\"name\":\"save_dir\",\"tip\":\"选择保存文件的文件夹路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"new_file_name\",\"title\":\"合并文件名\",\"name\":\"new_file_name\",\"tip\":\"输入合并文件名,不输入则使用默认文件名\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"new_pwd_flag\",\"title\":\"是否给新PDF文件设置密码\",\"name\":\"new_pwd_flag\",\"tip\":\"选择是否设置密码\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"level\":\"advanced\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"new_pwd\",\"title\":\"新PDF文件密码\",\"name\":\"new_pwd\",\"tip\":\"输入新PDF文件密码\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.new_pwd.show\",\"expression\":\"return $this.new_pwd_flag.value == true\"}],\"required\":true},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_handle_type\",\"title\":\"存在同名文件处理方式\",\"name\":\"exist_handle_type\",\"tip\":\"选择存在文件处理方式,支持覆盖原有文件、创建文件副本、取消保存操作\",\"options\":[{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"level\":\"advanced\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"pdf_merge_file_path\",\"title\":\"合并后的PDF文件路径\",\"tip\":\"合并后的PDF文件路径\"}],\"icon\":\"merge-pdf-files\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(195,'document/document.PDF','PDF.extract_pdf_file','{\"key\":\"PDF.extract_pdf_file\",\"title\":\"抽取PDF指定页\",\"version\":\"1.0.0\",\"src\":\"astronverse.pdf.pdf.PDF().extract_pdf_file\",\"comment\":\"抽取路径为 @{file_path} 的PDF文档指定页,并保存到 @{extract_file_path} 文件夹\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"PDF文件路径\",\"name\":\"file_path\",\"tip\":\"选择需要抽取的PDF文件路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"pwd\",\"title\":\"PDF文件密码\",\"name\":\"pwd\",\"tip\":\"如果PDF文件需要密码,请输入密码,否则留空\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page_range\",\"title\":\"指定页面范围\",\"name\":\"page_range\",\"tip\":\"输入页面范围,格式为1-3,5,7-9,11,表示从1到3页,5页,7到9页,11页\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"save_dir\",\"title\":\"保存文件路径\",\"name\":\"save_dir\",\"tip\":\"选择保存文件的文件夹路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"new_file_name\",\"title\":\"抽取后新PDF文件名\",\"name\":\"new_file_name\",\"tip\":\"输入新文件名,不输入则使用默认文件名\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"new_pwd_flag\",\"title\":\"是否给新PDF文件设置密码\",\"name\":\"new_pwd_flag\",\"tip\":\"选择是否设置密码\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"level\":\"advanced\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"new_pwd\",\"title\":\"新PDF文件密码\",\"name\":\"new_pwd\",\"tip\":\"输入新PDF文件密码\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.new_pwd.show\",\"expression\":\"return $this.new_pwd_flag.value == true\"}],\"required\":false},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_handle_type\",\"title\":\"存在同名文件处理方式\",\"name\":\"exist_handle_type\",\"tip\":\"选择存在文件处理方式,支持覆盖原有文件、创建文件副本、取消保存操作\",\"options\":[{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"level\":\"advanced\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"extract_file_path\",\"title\":\"提取后的PDF文件路径\",\"tip\":\"提取后的PDF文件路径\"}],\"icon\":\"pdf-extract-page\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(196,'document/document.PDF','PDF.extract_forms_from_pdf','{\"key\":\"PDF.extract_forms_from_pdf\",\"title\":\"提取PDF表格到Excel\",\"version\":\"1.0.0\",\"src\":\"astronverse.pdf.pdf.PDF().extract_forms_from_pdf\",\"comment\":\"提取路径为 @{file_path} 的PDF文档中的表格,并保存到 @{forms_file_path} 文件夹\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"PDF文件路径\",\"name\":\"file_path\",\"tip\":\"选择需要提取表格的PDF文件路径\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"pwd\",\"title\":\"PDF文件密码\",\"name\":\"pwd\",\"tip\":\"如果PDF文件需要密码,请输入密码,否则留空\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"required\":false},{\"types\":\"SelectRangeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"select_range\",\"title\":\"选择范围\",\"name\":\"select_range\",\"tip\":\"选择范围,支持全部页面和指定页面范围\",\"options\":[{\"label\":\"所有页面\",\"value\":\"all\"},{\"label\":\"指定页面\",\"value\":\"part\"}],\"default\":\"all\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page_range\",\"title\":\"指定页面范围\",\"name\":\"page_range\",\"tip\":\"输入页面范围,格式为1-3,5,7-9,11,表示从1到3页,5页,7到9页,11页\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.page_range.show\",\"expression\":\"return $this.select_range.value == \'part\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"combine_flag\",\"title\":\"是否需要合并多个表格\",\"name\":\"combine_flag\",\"tip\":\"当出现跨页的表格时,可以选择是否合并成一个表格,建议表头相同时选择合并\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"save_dir\",\"title\":\"保存文件路径\",\"name\":\"save_dir\",\"tip\":\"选择保存文件的文件夹路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"new_file_name\",\"title\":\"表格文件名\",\"name\":\"new_file_name\",\"tip\":\"输入表格文件名,不输入则使用默认文件名\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_handle_type\",\"title\":\"存在同名文件处理方式\",\"name\":\"exist_handle_type\",\"tip\":\"选择存在文件处理方式,支持覆盖原有文件、创建文件副本、取消保存操作\",\"options\":[{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"level\":\"advanced\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"forms_file_path\",\"title\":\"提取后的Excel文件路径\",\"tip\":\"提取后的Excel文件路径\"}],\"icon\":\"pdf-extract-table-to-excel\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(197,'document/document.PDF','PDF.convert_pdf_to_img','{\"key\":\"PDF.convert_pdf_to_img\",\"title\":\"PDF页面转图片\",\"version\":\"1.0.0\",\"src\":\"astronverse.pdf.pdf.PDF().convert_pdf_to_img\",\"comment\":\"转换路径为 @{file_path} 的PDF文档为图片,并保存到 @{save_dir} 文件夹\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"PDF文件路径\",\"name\":\"file_path\",\"tip\":\"选择需要转换的PDF文件路径\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"pwd\",\"title\":\"PDF文件密码\",\"name\":\"pwd\",\"tip\":\"如果PDF文件需要密码,请输入密码,否则留空\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"required\":false},{\"types\":\"PictureType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"image_type\",\"title\":\"图片格式\",\"name\":\"image_type\",\"tip\":\"选择图片格式,支持JPEG、PNG等格式\",\"options\":[{\"label\":\"PNG\",\"value\":\"png\"},{\"label\":\"JPEG\",\"value\":\"jpeg\"}],\"default\":\"png\",\"required\":true},{\"types\":\"SelectRangeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"select_range\",\"title\":\"选择范围\",\"name\":\"select_range\",\"tip\":\"选择范围,支持全部页面和指定页面范围\",\"options\":[{\"label\":\"所有页面\",\"value\":\"all\"},{\"label\":\"指定页面\",\"value\":\"part\"}],\"default\":\"all\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page_range\",\"title\":\"指定页面范围\",\"name\":\"page_range\",\"tip\":\"输入页面范围,格式为1-3,5,7-9,11,表示从1到3页,5页,7到9页,11页\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.page_range.show\",\"expression\":\"return $this.select_range.value == \'part\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"save_dir\",\"title\":\"保存文件路径\",\"name\":\"save_dir\",\"tip\":\"选择保存文件的文件夹路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"prefix\",\"title\":\"图片文件名前缀\",\"name\":\"prefix\",\"tip\":\"输入图片文件名前缀,不输入则使用原文件名前缀\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_handle_type\",\"title\":\"存在同名文件处理方式\",\"name\":\"exist_handle_type\",\"tip\":\"选择存在文件处理方式,支持覆盖原有文件、创建文件副本、取消保存操作\",\"options\":[{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"level\":\"advanced\",\"required\":true}],\"outputList\":[],\"icon\":\"pdf-page-to-image\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(198,'code','Report.print','{\"key\":\"Report.print\",\"title\":\"日志打印\",\"version\":\"1.0.0\",\"src\":\"astronverse.report.report.Report().print\",\"comment\":\"将变量(@{msg})打印\",\"inputList\":[{\"types\":\"ReportLevelType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"report_type\",\"title\":\"日志类型\",\"name\":\"report_type\",\"options\":[{\"label\":\"信息\",\"value\":\"info\"},{\"label\":\"警告\",\"value\":\"warning\"},{\"label\":\"错误\",\"value\":\"error\"}],\"default\":\"info\",\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"msg\",\"title\":\"日志内容\",\"name\":\"msg\",\"tip\":\"打印运行过程中输出的流变量\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"log-print\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(199,'script','Script.module','{\"key\":\"Script.module\",\"title\":\"运行Python模块\",\"version\":\"1.0.0\",\"src\":\"astronverse.script.script.Script().module\",\"comment\":\"运行Python模块(@{content:Python模块})\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"SELECT\",\"params\":{\"filters\":\"PyModule\"}},\"key\":\"content\",\"title\":\"选择Python模块\",\"name\":\"content\",\"tip\":\"\",\"default\":\"\",\"required\":true}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"program_script\",\"title\":\"执行结果\",\"tip\":\"\"}],\"icon\":\"run-python-module\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(200,'desktop','Software.open','{\"key\":\"Software.open\",\"title\":\"打开程序\",\"version\":\"1.0.0\",\"src\":\"astronverse.software.software.Software().open\",\"comment\":\"打开应用程序路径(@{app_abs_path}),并设置运行参数为(@{app_args}),将结果输出为(@{software_open})\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[]}},\"key\":\"app_absolute_path\",\"name\":\"app_absolute_path\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"app_arguments\",\"name\":\"app_arguments\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"software_open\",\"title\":\"应用程序路径\",\"tip\":\"输出该被打开的应用程序路径\"}],\"icon\":\"open-program\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(201,'desktop','Software.close','{\"key\":\"Software.close\",\"title\":\"关闭程序\",\"version\":\"1.0.0\",\"src\":\"astronverse.software.software.Software().close\",\"comment\":\"关闭应用程序路径为(@{app_abs_path})的程序\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[]}},\"key\":\"app_absolute_path\",\"name\":\"app_absolute_path\",\"required\":true}],\"outputList\":[],\"icon\":\"close-program\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(202,'','Software.cmd','{\"key\":\"Software.cmd\",\"title\":\"Cmd命令\",\"version\":\"1.0.0\",\"src\":\"astronverse.software.software.Software().cmd\",\"comment\":\"通过配置cmd字符串(@{cmd}),执行cmd命令,执行结果保存至(@{exec_cmd})\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"cmd\",\"title\":\"cmd字符串\",\"name\":\"cmd\",\"tip\":\"输入cmd字符串\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"exec_cmd\",\"title\":\"执行结果\",\"tip\":\"输出自定义cmd命令运行后返回的对象结果\"}],\"icon\":\"cmd-command\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(203,'os/os.clipboard','System.copy_clip','{\"key\":\"System.copy_clip\",\"title\":\"复制到剪切板\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.clipboard.Clipboard().copy_clip\",\"comment\":\"将 @{content_type} @{message||file_path||folder_path} 复制到剪切板\",\"inputList\":[{\"types\":\"ContentType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"content_type\",\"title\":\"复制类型\",\"name\":\"content_type\",\"tip\":\"选择复制到剪贴板的内容类型\",\"options\":[{\"label\":\"文本内容\",\"value\":\"msg\"},{\"label\":\"HTML格式文本内容\",\"value\":\"html\"},{\"label\":\"文件\",\"value\":\"file\"},{\"label\":\"文件夹\",\"value\":\"folder\"}],\"default\":\"msg\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"message\",\"title\":\"待复制的文本内容\",\"name\":\"message\",\"tip\":\"输入文本内容\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.message.show\",\"expression\":\"return $this.content_type.value == \'msg\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"待复制的文件路径\",\"name\":\"file_path\",\"tip\":\"输入或选择待复制文件\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.file_path.show\",\"expression\":\"return $this.content_type.value == \'file\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"folder_path\",\"title\":\"待复制的文件夹路径\",\"name\":\"folder_path\",\"tip\":\"输入或选择待复制文件夹\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.folder_path.show\",\"expression\":\"return $this.content_type.value == \'folder\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"copy-to-clipboard\",\"helpManual\":\"支持将文本内容/文件/文件夹复制到剪切板\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(204,'os/os.clipboard','System.clear_clip','{\"key\":\"System.clear_clip\",\"title\":\"清空剪切板\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.clipboard.Clipboard().clear_clip\",\"comment\":\"清空剪切板中的内容\",\"inputList\":[],\"outputList\":[],\"icon\":\"clear-clipboard\",\"helpManual\":\"清空剪切板中的内容\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(205,'os/os.clipboard','System.paste_clip','{\"key\":\"System.paste_clip\",\"title\":\"获取剪切板\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.clipboard.Clipboard().paste_clip\",\"comment\":\"获取剪切板中的 @{content_type} ,并保存至变量 @{output_content}\",\"inputList\":[{\"types\":\"ContentType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"content_type\",\"title\":\"获取类型\",\"name\":\"content_type\",\"tip\":\"选择剪切板中要获取的内容类型\",\"options\":[{\"label\":\"文本内容\",\"value\":\"msg\"},{\"label\":\"HTML格式文本内容\",\"value\":\"html\"},{\"label\":\"文件\",\"value\":\"file\"},{\"label\":\"文件夹\",\"value\":\"folder\"}],\"default\":\"msg\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"dst_path\",\"title\":\"保存路径\",\"name\":\"dst_path\",\"tip\":\"请输入或选择保存路径\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.dst_path.show\",\"expression\":\"return [\'file\', \'folder\'].includes($this.content_type.value)\"}],\"required\":true},{\"types\":\"StateType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"state_type\",\"title\":\"保存路径不存在时\",\"name\":\"state_type\",\"tip\":\"设置保存路径不存在时执行的操作\",\"options\":[{\"label\":\"创建\",\"value\":\"create\"},{\"label\":\"提示并报错\",\"value\":\"error\"}],\"default\":\"error\",\"dynamics\":[{\"key\":\"$this.state_type.show\",\"expression\":\"return [\'folder\', \'file\'].includes($this.content_type.value)\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dst_file_name\",\"title\":\"文件保存名称\",\"name\":\"dst_file_name\",\"tip\":\"输入保存的文件名,不需加文件后缀,为空自动使用原文件名\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.dst_file_name.show\",\"expression\":\"return $this.content_type.value == \'file\'\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dst_folder_name\",\"title\":\"文件夹保存名称\",\"name\":\"dst_folder_name\",\"tip\":\"输入保存的文件夹名称,为空自动使用原文件夹名称\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.dst_folder_name.show\",\"expression\":\"return $this.content_type.value == \'folder\'\"}],\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"output_content\",\"title\":\"输出剪切板内容至变量\",\"tip\":\"获取文本内容输出为文本变量,获取文件/文件夹输出为路径信息\"}],\"icon\":\"get-clipboard\",\"helpManual\":\"支持获取剪切板中的文本内容/文件/文件夹,并将文本内容/文件文件夹保存路径保存到指定路径中\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(206,'os/os.zip','System.compress','{\"key\":\"System.compress\",\"title\":\"压缩\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.compress.Compress().compress\",\"comment\":\"压缩 @{file_type} 到指定目录 @{compress_dir} 中,并保存压缩包路径至 @{compress_path}\",\"inputList\":[{\"types\":\"FileFolderType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"file_type\",\"title\":\"选择压缩方式\",\"name\":\"file_type\",\"tip\":\"选择压缩文件/文件夹/文件和文件夹\",\"options\":[{\"label\":\"文件\",\"value\":\"file\"},{\"label\":\"文件夹\",\"value\":\"folder\"},{\"label\":\"文件和文件夹\",\"value\":\"both\"}],\"default\":\"file\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"files\"}},\"key\":\"file_path\",\"title\":\"待压缩文件\",\"name\":\"file_path\",\"tip\":\"选择或输入待压缩文件路径\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.file_path.show\",\"expression\":\"return $this.file_type.value != \'folder\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"folder_path\",\"title\":\"待压缩文件夹\",\"name\":\"folder_path\",\"tip\":\"选择或输入待压缩文件夹路径\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.folder_path.show\",\"expression\":\"return $this.file_type.value != \'file\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"compress_dir\",\"title\":\"目标路径\",\"name\":\"compress_dir\",\"tip\":\"保存目标压缩文件路径\",\"default\":\"\",\"required\":true},{\"types\":\"StateType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"state_type\",\"title\":\"目标路径不存在时\",\"name\":\"state_type\",\"tip\":\"选择目标路径不存在时执行的操作\",\"options\":[{\"label\":\"创建\",\"value\":\"create\"},{\"label\":\"提示并报错\",\"value\":\"error\"}],\"default\":\"error\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"compress_name\",\"title\":\"压缩包名称\",\"name\":\"compress_name\",\"tip\":\"指定压缩包名称,为空则默认以压缩列表中第一个压缩文件名称命名\",\"default\":\"\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"pwd\",\"title\":\"压缩密码\",\"name\":\"pwd\",\"tip\":\"为压缩包设置解压缩密码\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"SaveType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"save_type\",\"title\":\"压缩后源文件是否保存\",\"name\":\"save_type\",\"tip\":\"\",\"options\":[{\"label\":\"删除\",\"value\":\"delete\"},{\"label\":\"保留\",\"value\":\"save\"}],\"default\":\"save\",\"level\":\"advanced\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"compress_path\",\"title\":\"输出压缩后压缩包路径\",\"tip\":\"\"}],\"icon\":\"compress\",\"helpManual\":\"压缩选择文件与文件夹到指定目录,支持单个或多个文件文件夹同时压缩为一个压缩包(压缩后文件格式为zip格式)\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(207,'os/os.zip','System.uncompress','{\"key\":\"System.uncompress\",\"title\":\"解压\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.compress.Compress().uncompress\",\"comment\":\"将压缩文件 @{source_path} 解压至指定目录 @{target_path} 下,并输出解压后文件所在路径 @{uncompress_path}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"source_path\",\"title\":\"压缩包路径\",\"name\":\"source_path\",\"tip\":\"请选择或输入压缩包路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"target_path\",\"title\":\"目标解压目录\",\"name\":\"target_path\",\"tip\":\"选择或输入解压后文件保存路径\",\"default\":\"\",\"required\":true},{\"types\":\"StateType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"status_type\",\"title\":\"目标目录不存在时\",\"name\":\"status_type\",\"tip\":\"选择目标目录不存在时执行的操作,默认直接创建\",\"options\":[{\"label\":\"创建\",\"value\":\"create\"},{\"label\":\"提示并报错\",\"value\":\"error\"}],\"default\":\"error\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"pwd\",\"title\":\"解压密码\",\"name\":\"pwd\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"SaveType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"save_type\",\"title\":\"解压缩后源文件是否保留\",\"name\":\"save_type\",\"tip\":\"解压后对源文件的操作,默认保留\",\"options\":[{\"label\":\"删除\",\"value\":\"delete\"},{\"label\":\"保留\",\"value\":\"save\"}],\"default\":\"save\",\"level\":\"advanced\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"uncompress_path\",\"title\":\"输出解压后文件路径\",\"tip\":\"\"}],\"icon\":\"decompress\",\"helpManual\":\"将压缩文件解压至指定路径\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(208,'os/os.file','File.file_exist','{\"key\":\"File.file_exist\",\"title\":\"IF 文件存在\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.file.File().file_exist\",\"comment\":\"判断文件 @{file_path} 是否存在,存在就执行以下操作\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"文件路径\",\"name\":\"file_path\",\"tip\":\"输入或选择文件路径\",\"default\":\"\",\"required\":true},{\"types\":\"ExistType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_type\",\"title\":\"判断类型\",\"name\":\"exist_type\",\"tip\":\"选择判断类型\",\"options\":[{\"label\":\"存在\",\"value\":\"exist\"},{\"label\":\"不存在\",\"value\":\"not_exist\"}],\"default\":\"exist\",\"required\":false}],\"outputList\":[],\"icon\":\"check-file-exists\",\"helpManual\":\"判断文件是否存在并将判断结果输出至变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(209,'os/os.file','File.file_create','{\"key\":\"File.file_create\",\"title\":\"新建文件\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.file.File().file_create\",\"comment\":\"在指定目录 @{dst_path} 下创建文件 @{file_name} ,并保存新建文件路径到 @{new_file_path}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"dst_path\",\"title\":\"指定目录\",\"name\":\"dst_path\",\"tip\":\"输入或选择指定文件夹目录\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\",\"params\":{\"size\":\"middle\"}},\"key\":\"file_name\",\"title\":\"文件名称\",\"name\":\"file_name\",\"tip\":\"输入文件名称及扩展名\",\"default\":\"\",\"required\":true},{\"types\":\"OptionType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"exist_options\",\"title\":\"文件存在时\",\"name\":\"exist_options\",\"tip\":\"选择新建文件已存在时的操作;生成副本:将在文件名称后增加数字标识,如a(1).txt,如果副本文件同样存在,则数字递增;覆盖:删除已存在文件并重新创建;跳过:返回当前已存在文件路径\",\"options\":[{\"label\":\"覆盖原有文件夹\",\"value\":\"overwrite\"},{\"label\":\"取消保存操作\",\"value\":\"skip\"},{\"label\":\"创建文件夹副本\",\"value\":\"generate\"}],\"default\":\"generate\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"new_file_path\",\"title\":\"新建文件路径\",\"tip\":\"输出新建文件路径,并保存到变量中,数据类型为字符串\"}],\"icon\":\"create-new-file\",\"helpManual\":\"在指定目录下新建文件\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(210,'os/os.file','File.file_delete','{\"key\":\"File.file_delete\",\"title\":\"删除文件\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.file.File().file_delete\",\"comment\":\"删除文件 @{file_path} ,并将结果输出至变量 @{delete_file_result}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"待删除文件\",\"name\":\"file_path\",\"tip\":\"选择或输入待删除文件路径\",\"default\":\"\",\"required\":true},{\"types\":\"DeleteType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"delete_options\",\"title\":\"删除操作\",\"name\":\"delete_options\",\"tip\":\"选择将文件彻底删除或移入回收站\",\"options\":[{\"label\":\"彻底删除\",\"value\":\"delete\"},{\"label\":\"移入回收站\",\"value\":\"trash\"}],\"default\":\"delete\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"delete_file_result\",\"title\":\"输出删除结果至\",\"tip\":\"将文件删除结果保存至变量,数据类型为布尔值\"}],\"icon\":\"delete-file\",\"helpManual\":\"删除指定文件,并将执行结果输出至变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(211,'os/os.file','File.file_copy','{\"key\":\"File.file_copy\",\"title\":\"复制文件\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.file.File().file_copy\",\"comment\":\"复制文件 @{file_path} 到指定目录 @{target_path} 下,并保存复制后的文件路径 @{copy_file_path}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"待复制文件\",\"name\":\"file_path\",\"tip\":\"选择或输入待复制文件路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"target_path\",\"title\":\"指定目录\",\"name\":\"target_path\",\"tip\":\"选择或输入目标目录\",\"default\":\"\",\"required\":true},{\"types\":\"StateType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"state_type\",\"title\":\"目录不存在时\",\"name\":\"state_type\",\"tip\":\"设置指定目录不存在时执行的操作\",\"options\":[{\"label\":\"创建\",\"value\":\"create\"},{\"label\":\"提示并报错\",\"value\":\"error\"}],\"default\":\"error\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\",\"params\":{\"size\":\"middle\"}},\"key\":\"file_name\",\"title\":\"复制后文件名\",\"name\":\"file_name\",\"tip\":\"指定复制后文件名,无需输入文件扩展名,为空默认使用原文件名称\",\"default\":\"\",\"required\":false},{\"types\":\"OptionType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"copy_options\",\"title\":\"文件存在时\",\"name\":\"copy_options\",\"tip\":\"选择指定目录下文件已存在时的操作; 生成副本:将在文件名称后增加数字标识,如a(1).txt,如果副本文件同样存在,则数字递增; 覆盖:删除已存在文件并重新创建; 跳过:返回当前已存在文件路径\",\"options\":[{\"label\":\"覆盖原有文件夹\",\"value\":\"overwrite\"},{\"label\":\"取消保存操作\",\"value\":\"skip\"},{\"label\":\"创建文件夹副本\",\"value\":\"generate\"}],\"default\":\"generate\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"copy_file_path\",\"title\":\"复制后文件路径\",\"tip\":\"输出复制后文件路径,并保存至变量,数据类型为字符串\"}],\"icon\":\"copy-file\",\"helpManual\":\"复制目标文件到指定目录\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(212,'os/os.file','File.file_write','{\"key\":\"File.file_write\",\"title\":\"写入文件\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.file.File().file_write\",\"comment\":\"写入内容 @{msg} 到文件 @{file_path} 中,并保存写入后的文件路径 @{write_file_path}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"文件路径\",\"name\":\"file_path\",\"tip\":\"选择或输入文件路径,支持写入的文件类型有:\\\".txt\\\", \\\".docx\\\", \\\".md\\\", \\\".py\\\", \\\".json\\\", \\\".csv\\\"\",\"default\":\"\",\"required\":true},{\"types\":\"StateType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"file_option\",\"title\":\"文件不存在时\",\"name\":\"file_option\",\"tip\":\"选择文件不存在时执行的操作\",\"options\":[{\"label\":\"创建\",\"value\":\"create\"},{\"label\":\"提示并报错\",\"value\":\"error\"}],\"default\":\"error\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\",\"params\":{\"size\":\"middle\"}},\"key\":\"msg\",\"title\":\"写入内容\",\"name\":\"msg\",\"tip\":\"输入要写入的内容\",\"default\":\"\",\"required\":true},{\"types\":\"WriteType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"write_type\",\"title\":\"写入方式\",\"name\":\"write_type\",\"tip\":\"指定写入方式\",\"options\":[{\"label\":\"覆盖写入\",\"value\":\"overwrite\"},{\"label\":\"追加写入\",\"value\":\"append\"}],\"default\":\"append\",\"required\":false},{\"types\":\"EncodeType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"encode_type\",\"title\":\"编码方式\",\"name\":\"encode_type\",\"tip\":\"选择写入内容的编码方式,文件内容为空时需指定,默认选项时自动使用待写入文件的编码方式\",\"options\":[{\"label\":\"默认\",\"value\":\"default\"},{\"label\":\"ansi\",\"value\":\"ansi\"},{\"label\":\"utf-8\",\"value\":\"utf-8\"},{\"label\":\"utf-16\",\"value\":\"utf-16\"},{\"label\":\"utf-16 be\",\"value\":\"utf-16 be\"},{\"label\":\"gbk\",\"value\":\"gbk\"},{\"label\":\"gb2312\",\"value\":\"gb2312\"},{\"label\":\"gb18030\",\"value\":\"gb18030\"}],\"default\":\"default\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"write_file_path\",\"title\":\"文件路径\",\"tip\":\"输出写入后文件路径至变量,数据类型为字符串\"}],\"icon\":\"write-file\",\"helpManual\":\"向指定文件中写入内容,并输出写入后的文件路径至变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(213,'os/os.file','File.get_file_encoding_type','{\"key\":\"File.get_file_encoding_type\",\"title\":\"获取文件编码类型\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.file.File().get_file_encoding_type\",\"comment\":\"获取文件 @{file_path} 的编码类型并保存至变量 @{file_encoding_type}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"文件路径\",\"name\":\"file_path\",\"tip\":\"选择或输入待获取编码类型的文件路径\",\"default\":\"\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"file_encoding_type\",\"title\":\"文件编码类型\",\"tip\":\"输出文件编码类型至变量,数据类型为字符串\"}],\"icon\":\"get-file-encoding\",\"helpManual\":\"获取指定文件的编码类型,并输出编码类型至变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(214,'os/os.file','File.file_read','{\"key\":\"File.file_read\",\"title\":\"读取文件\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.file.File().file_read\",\"comment\":\"按照 @{read_type} 方式读取文件 @{file_path} 中的内容,并保存至变量 @{read_file_content}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"待读取文件路径\",\"name\":\"file_path\",\"tip\":\"选择或输入待读取文件路径, 支持读取的文件类型有:\\\".txt\\\", \\\".docx\\\", \\\".md\\\", \\\".py\\\", \\\".json\\\", \\\".csv\\\"\",\"default\":\"\",\"required\":true},{\"types\":\"ReadType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"read_type\",\"title\":\"读取方式\",\"name\":\"read_type\",\"tip\":\"选择读取方式,全部读取:读取全部内容; 按行读取:按行读取文本内容; 二进制:以二进制方式读取文件内容\",\"options\":[{\"label\":\"读取全部内容\",\"value\":\"all\"},{\"label\":\"按行读取到列表中\",\"value\":\"list\"},{\"label\":\"二进制方式读取\",\"value\":\"byte\"}],\"default\":\"all\",\"required\":false},{\"types\":\"EncodeType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"encode_type\",\"title\":\"编码方式\",\"name\":\"encode_type\",\"tip\":\"选择读取内容的编码方式,默认选项时自动使用待读取文件的编码方式\",\"options\":[{\"label\":\"默认\",\"value\":\"default\"},{\"label\":\"ansi\",\"value\":\"ansi\"},{\"label\":\"utf-8\",\"value\":\"utf-8\"},{\"label\":\"utf-16\",\"value\":\"utf-16\"},{\"label\":\"utf-16 be\",\"value\":\"utf-16 be\"},{\"label\":\"gbk\",\"value\":\"gbk\"},{\"label\":\"gb2312\",\"value\":\"gb2312\"},{\"label\":\"gb18030\",\"value\":\"gb18030\"}],\"default\":\"default\",\"required\":false}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"read_file_content\",\"title\":\"读取内容为\",\"tip\":\"输出读取内容至变量,数据类型为字符串\"}],\"icon\":\"read-file\",\"helpManual\":\"读取指定文件内容,并将读取内容输出保存至变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(215,'os/os.file','File.file_move','{\"key\":\"File.file_move\",\"title\":\"移动文件\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.file.File().file_move\",\"comment\":\"将文件 @{file_path} 移动至指定目录 @{target_folder} 下,并保存移动后的文件路径 @{move_file_path}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"待移动文件路径\",\"name\":\"file_path\",\"tip\":\"选择或输入待移动文件路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"target_folder\",\"title\":\"指定目录\",\"name\":\"target_folder\",\"tip\":\"选择或输入目标目录, 指定目录不存在时默认自动创建\",\"default\":\"\",\"required\":true},{\"types\":\"StateType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"state_type\",\"title\":\"目录不存在时\",\"name\":\"state_type\",\"tip\":\"设置指定目录不存在时执行的操作\",\"options\":[{\"label\":\"创建\",\"value\":\"create\"},{\"label\":\"提示并报错\",\"value\":\"error\"}],\"default\":\"error\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"file_name\",\"title\":\"移动后文件名\",\"name\":\"file_name\",\"tip\":\"输入移动后文件名(不需后缀名),默认为空使用原文件名\",\"default\":\"\",\"required\":false},{\"types\":\"OptionType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"exist_options\",\"title\":\"文件存在时\",\"name\":\"exist_options\",\"tip\":\"选择文件存在时执行的操作(覆盖、跳过、生成副本)\",\"options\":[{\"label\":\"覆盖原有文件夹\",\"value\":\"overwrite\"},{\"label\":\"取消保存操作\",\"value\":\"skip\"},{\"label\":\"创建文件夹副本\",\"value\":\"generate\"}],\"default\":\"generate\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"move_file_path\",\"title\":\"移动后文件路径\",\"tip\":\"输出移动后文件路径至变量,数据类型为字符串\"}],\"icon\":\"move-file\",\"helpManual\":\"将指定文件移动到目标目录,并输出移动后的文件路径至变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(216,'os/os.file','File.file_rename','{\"key\":\"File.file_rename\",\"title\":\"重命名文件\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.file.File().file_rename\",\"comment\":\"将文件 @{file_path} 重命名为 @{new_name} 并保存重命名后的文件路径 @{rename_file_path}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"待重命名文件路径\",\"name\":\"file_path\",\"tip\":\"选择或输入待重命名文件路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"new_name\",\"title\":\"新文件名\",\"name\":\"new_name\",\"tip\":\"输入新文件名(不需后缀名)\",\"default\":\"\",\"required\":true},{\"types\":\"OptionType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"exist_options\",\"title\":\"文件存在时\",\"name\":\"exist_options\",\"tip\":\"选择文件存在时执行的操作(覆盖、跳过、生成副本)\",\"options\":[{\"label\":\"覆盖原有文件夹\",\"value\":\"overwrite\"},{\"label\":\"取消保存操作\",\"value\":\"skip\"},{\"label\":\"创建文件夹副本\",\"value\":\"generate\"}],\"default\":\"generate\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"rename_file_path\",\"title\":\"重命名后文件路径\",\"tip\":\"输出重命名后文件路径至变量,数据类型为字符串\"}],\"icon\":\"rename-file\",\"helpManual\":\"将指定文件重命名,并输出重命名后的文件路径至变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(217,'os/os.file','File.file_search','{\"key\":\"File.file_search\",\"title\":\"查找文件\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.file.File().file_search\",\"comment\":\"在 @{folder_path} 目录中查找文件名包含 @{search_pattern} 的文件,并保存匹配文件路径至变量 @{find_file_result}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"folder_path\",\"title\":\"待查找文件所在目录\",\"name\":\"folder_path\",\"tip\":\"选择或输入待查找文件所在目录\",\"default\":\"\",\"required\":true},{\"types\":\"SearchType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"find_type\",\"title\":\"查找方式\",\"name\":\"find_type\",\"tip\":\"指定查找方式:精确匹配需输入完整文件名;模糊匹配输入部分文件名,需区分大小写;正则表达式匹配输入正则表达式\",\"options\":[{\"label\":\"精确匹配\",\"value\":\"exact\"},{\"label\":\"模糊匹配\",\"value\":\"fuzzy\"},{\"label\":\"正则表达式匹配\",\"value\":\"regex\"}],\"default\":\"fuzzy\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"search_pattern\",\"title\":\"查找文件名\",\"name\":\"search_pattern\",\"tip\":\"输入查找内容\",\"default\":\"\",\"required\":true},{\"types\":\"TraverseType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"traverse_subfolder\",\"title\":\"遍历子文件夹\",\"name\":\"traverse_subfolder\",\"tip\":\"选择是否遍历子文件夹\",\"options\":[{\"label\":\"遍历子目录\",\"value\":\"yes\"},{\"label\":\"不遍历子目录\",\"value\":\"no\"}],\"default\":\"no\",\"level\":\"advanced\",\"required\":false}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"find_file_result\",\"title\":\"保存查找结果至\",\"tip\":\"输出匹配文件路径列表,并保存到变量,数据类型为列表\"}],\"icon\":\"find-file\",\"helpManual\":\"在指定目录中查找文件名包含指定内容的文件,并输出文件列表至变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(218,'os/os.file','File.file_wait_status','{\"key\":\"File.file_wait_status\",\"title\":\"等待文件\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.file.File().file_wait_status\",\"comment\":\"等待文件 @{file_path} 状态为 @{status_type} 时执行下一步,保存等待结果到 @{wait_file_result}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"文件路径\",\"name\":\"file_path\",\"tip\":\"选择或输入文件路径\",\"default\":\"\",\"required\":true},{\"types\":\"StatusType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"status_type\",\"title\":\"等待状态\",\"name\":\"status_type\",\"tip\":\"选择等待文件的状态\",\"options\":[{\"label\":\"被创建\",\"value\":\"created\"},{\"label\":\"被删除\",\"value\":\"deleted\"}],\"default\":\"created\",\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"wait_time\",\"title\":\"超时时间\",\"name\":\"wait_time\",\"tip\":\"设置等待超时时间,单位为秒\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"wait_file_result\",\"title\":\"保存等待结果至\",\"tip\":\"输出等待结果至变量,数据类型为布尔值\"}],\"icon\":\"wait-file\",\"helpManual\":\"等待文件状态为指定状态时执行下一步,并输出等待结果至变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(219,'os/os.file','File.file_info','{\"key\":\"File.file_info\",\"title\":\"获取文件信息\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.file.File().file_info\",\"comment\":\"获取指定文件 @{file_path} 的 @{info_type} 信息,并保存文件信息至变量 @{file_info}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"文件路径\",\"name\":\"file_path\",\"tip\":\"选择或输入文件路径\",\"default\":\"\",\"required\":true},{\"types\":\"InfoType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"info_type\",\"title\":\"获取信息类型\",\"name\":\"info_type\",\"tip\":\"指定获取的信息类型\",\"options\":[{\"label\":\"全部信息\",\"value\":\"all\"},{\"label\":\"绝对路径\",\"value\":\"abs_path\"},{\"label\":\"根目录\",\"value\":\"root\"},{\"label\":\"文件路径\",\"value\":\"directory\"},{\"label\":\"文件大小(字节)\",\"value\":\"size\"},{\"label\":\"文件名\",\"value\":\"name_ext\"},{\"label\":\"单独文件名\",\"value\":\"name\"},{\"label\":\"文件扩展名\",\"value\":\"extension\"},{\"label\":\"文件创建时间\",\"value\":\"c_time\"},{\"label\":\"文件修改时间\",\"value\":\"m_time\"}],\"default\":\"all\",\"required\":false}],\"outputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"file_info\",\"title\":\"文件信息为\",\"tip\":\"输出文件信息至变量,获取全部信息时数据类型为字典,获取其他信息时数据类型为字符串\"}],\"icon\":\"get-file-info\",\"helpManual\":\"获取文件的全部信息/大小/文件路径/大小(字节)/根目录/文件夹目录/名称与扩展名/名称/扩展名/创建时间/修改时间,并保存到输出变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(220,'os/os.file','File.get_file_list','{\"key\":\"File.get_file_list\",\"title\":\"获取文件列表\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.file.File().get_file_list\",\"comment\":\"获取指定目录 @{folder_path} 中的文件列表,并保存文件列表至变量 @{file_list}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"folder_path\",\"title\":\"文件目录\",\"name\":\"folder_path\",\"tip\":\"选择或输入文件目录路径\",\"default\":\"\",\"required\":true},{\"types\":\"TraverseType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"traverse_subfolder\",\"title\":\"遍历子目录\",\"name\":\"traverse_subfolder\",\"tip\":\"选择是否遍历子目录\",\"options\":[{\"label\":\"遍历子目录\",\"value\":\"yes\"},{\"label\":\"不遍历子目录\",\"value\":\"no\"}],\"default\":\"no\",\"required\":true},{\"types\":\"OutputType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"output_type\",\"title\":\"输出方式\",\"name\":\"output_type\",\"tip\":\"设置输出方式\",\"options\":[{\"label\":\"列表输出\",\"value\":\"list\"},{\"label\":\"存储到表格文件\",\"value\":\"excel\"}],\"default\":\"list\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"excel_path\",\"title\":\"Excel文件保存目录\",\"name\":\"excel_path\",\"tip\":\"选择或输入保存的Excel文件保存目录\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.excel_path.show\",\"expression\":\"return $this.output_type.value == \'excel\'\"}],\"required\":true},{\"types\":\"StateType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"state_type\",\"title\":\"目录不存在时\",\"name\":\"state_type\",\"tip\":\"选择Excel文件保存目录不存在时执行的操作\",\"options\":[{\"label\":\"创建\",\"value\":\"create\"},{\"label\":\"提示并报错\",\"value\":\"error\"}],\"default\":\"error\",\"dynamics\":[{\"key\":\"$this.state_type.show\",\"expression\":\"return $this.output_type.value == \'excel\'\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel_name\",\"title\":\"Excel文件名\",\"name\":\"excel_name\",\"tip\":\"输入保存的Excel文件名,不需输入文件扩展名,默认扩展名为.xlsx\",\"default\":\"1.xlsx\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.excel_name.show\",\"expression\":\"return $this.output_type.value == \'excel\'\"}],\"required\":true},{\"types\":\"SortMethod\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"sort_method\",\"title\":\"排序方式\",\"name\":\"sort_method\",\"tip\":\"指定排序方式\",\"options\":[{\"label\":\"无\",\"value\":\"none\"},{\"label\":\"按创建时间排序\",\"value\":\"ctime\"},{\"label\":\"按修改时间排序\",\"value\":\"mtime\"}],\"default\":\"none\",\"level\":\"advanced\",\"required\":false},{\"types\":\"SortType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"sort_type\",\"title\":\"排序类型\",\"name\":\"sort_type\",\"tip\":\"指定排序类型\",\"options\":[{\"label\":\"升序\",\"value\":\"ascending\"},{\"label\":\"降序\",\"value\":\"descending\"}],\"default\":\"ascending\",\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.sort_type.show\",\"expression\":\"return $this.sort_method.value [\'ctime\', \'mtime\']\"}],\"required\":false}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"file_list\",\"title\":\"获取文件列表为\",\"tip\":\"输出获取到的文件列表到变量,数据类型为列表\"}],\"icon\":\"get-file-list\",\"helpManual\":\"获取指定目录中的文件列表,并保存至输出变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(221,'os/os.path','Folder.folder_exist','{\"key\":\"Folder.folder_exist\",\"title\":\"IF 文件夹存在\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.folder.Folder().folder_exist\",\"comment\":\"判断文件夹 @{folder_path} @{exist_type},存在就执行以下操作\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"folder_path\",\"title\":\"文件夹路径\",\"name\":\"folder_path\",\"tip\":\"选择或输入文件夹路径\",\"default\":\"\",\"required\":true},{\"types\":\"ExistType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_type\",\"title\":\"判断类型\",\"name\":\"exist_type\",\"tip\":\"设置判断类型\",\"options\":[{\"label\":\"存在\",\"value\":\"exist\"},{\"label\":\"不存在\",\"value\":\"not_exist\"}],\"default\":\"exist\",\"required\":false}],\"outputList\":[],\"icon\":\"check-folder-exists\",\"helpManual\":\"判断文件夹是否存在\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(222,'os/os.path','Folder.folder_open','{\"key\":\"Folder.folder_open\",\"title\":\"打开文件夹\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.folder.Folder().folder_open\",\"comment\":\"打开指定文件夹 @{folder_path}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"folder_path\",\"title\":\"文件夹路径\",\"name\":\"folder_path\",\"tip\":\"选择或输入文件夹路径\",\"default\":\"\",\"required\":true}],\"outputList\":[],\"icon\":\"open-folder\",\"helpManual\":\"打开指定文件夹\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(223,'os/os.path','Folder.folder_create','{\"key\":\"Folder.folder_create\",\"title\":\"创建文件夹\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.folder.Folder().folder_create\",\"comment\":\"在指定目录 @{target_path} 创建文件夹 @{folder_name} ,并保存新文件夹路径至变量 @{new_folder_path}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"target_path\",\"title\":\"指定目录\",\"name\":\"target_path\",\"tip\":\"选择或输入创建文件夹路径,路径不存在时自动创建\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\",\"params\":{\"size\":\"middle\"}},\"key\":\"folder_name\",\"title\":\"文件夹名称\",\"name\":\"folder_name\",\"tip\":\"输入创建文件夹名称\",\"default\":\"\",\"required\":true},{\"types\":\"OptionType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"exist_options\",\"title\":\"文件夹存在时\",\"name\":\"exist_options\",\"tip\":\"选择新建文件夹已存在时的操作;生成副本:将在文件名称后增加数字标识,如a(1),如果副本文件同样存在,则数字递增;覆盖:删除已存在文件夹并重新创建;跳过:返回当前已存在文件夹路径\",\"options\":[{\"label\":\"覆盖原有文件夹\",\"value\":\"overwrite\"},{\"label\":\"取消保存操作\",\"value\":\"skip\"},{\"label\":\"创建文件夹副本\",\"value\":\"generate\"}],\"default\":\"generate\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"new_folder_path\",\"title\":\"创建文件夹路径\",\"tip\":\"保存创建的文件夹路径到输出变量,数据类型为字符串\"}],\"icon\":\"create-folder\",\"helpManual\":\"在指定目录下创建文件夹,并保存新建文件夹路径到输出变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(224,'os/os.path','Folder.folder_delete','{\"key\":\"Folder.folder_delete\",\"title\":\"删除文件夹\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.folder.Folder().folder_delete\",\"comment\":\"删除文件夹 @{folder_path} ,并将结果输出至变量 @{delete_folder_result}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"folder_path\",\"title\":\"文件夹路径\",\"name\":\"folder_path\",\"tip\":\"选择或输入文件夹路径\",\"default\":\"\",\"required\":true},{\"types\":\"DeleteType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"delete_options\",\"title\":\"删除操作\",\"name\":\"delete_options\",\"tip\":\"选择将文件夹彻底删除或移入回收站\",\"options\":[{\"label\":\"彻底删除\",\"value\":\"delete\"},{\"label\":\"移入回收站\",\"value\":\"trash\"}],\"default\":\"delete\",\"required\":false}],\"outputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"delete_folder_result\",\"title\":\"删除文件夹结果\",\"tip\":\"保存删除文件夹的结果到输出变量,数据类型为布尔值\"}],\"icon\":\"delete-folder-ftp\",\"helpManual\":\"删除文件夹\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(225,'os/os.path','Folder.folder_copy','{\"key\":\"Folder.folder_copy\",\"title\":\"复制文件夹\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.folder.Folder().folder_copy\",\"comment\":\"将文件夹 @{source_path} 复制到指定目录 @{target_path} 下,并保存复制后的文件夹路径至变量 @{copy_folder_path}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"source_path\",\"title\":\"文件夹路径\",\"name\":\"source_path\",\"tip\":\"选择或输入待复制文件夹路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"target_path\",\"title\":\"指定目录\",\"name\":\"target_path\",\"tip\":\"选择或输入目标文件夹路径\",\"default\":\"\",\"required\":true},{\"types\":\"StateType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"state_type\",\"title\":\"目录不存在时\",\"name\":\"state_type\",\"tip\":\"设置指定目录不存在时执行的操作\",\"options\":[{\"label\":\"创建\",\"value\":\"create\"},{\"label\":\"提示并报错\",\"value\":\"error\"}],\"default\":\"error\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"folder_name\",\"title\":\"文件夹名称\",\"name\":\"folder_name\",\"tip\":\"默认为空,使用源文件夹名称\",\"default\":\"\",\"required\":false},{\"types\":\"OptionType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"exist_options\",\"title\":\"文件夹存在时\",\"name\":\"exist_options\",\"tip\":\"选择文件夹已存在时的操作;生成副本:将在文件名称后增加数字标识,如a(1),如果副本文件夹同样存在,则数字递增;覆盖:删除已存在文件夹;跳过:返回当前已存在文件路径\",\"options\":[{\"label\":\"覆盖原有文件夹\",\"value\":\"overwrite\"},{\"label\":\"取消保存操作\",\"value\":\"skip\"},{\"label\":\"创建文件夹副本\",\"value\":\"generate\"}],\"default\":\"generate\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"copy_folder_path\",\"title\":\"复制后文件夹路径\",\"tip\":\"保存复制后的文件夹路径到输出变量,数据类型为字符串\"}],\"icon\":\"copy-folder\",\"helpManual\":\"复制文件夹到指定目录,并保存复制后的文件夹路径到输出变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(226,'os/os.path','Folder.folder_move','{\"key\":\"Folder.folder_move\",\"title\":\"移动文件夹\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.folder.Folder().folder_move\",\"comment\":\"移动文件夹 @{folder_path} 到指定目录 @{target_folder} 下,并保存移动后的文件夹路径至变量 @{move_folder_path}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"folder_path\",\"title\":\"文件夹路径\",\"name\":\"folder_path\",\"tip\":\"选择或输入待移动文件夹路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"target_folder\",\"title\":\"指定目录\",\"name\":\"target_folder\",\"tip\":\"选择或输入目标文件夹路径\",\"default\":\"\",\"required\":true},{\"types\":\"StateType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"state_type\",\"title\":\"目录不存在时\",\"name\":\"state_type\",\"tip\":\"设置指定目录不存在时执行的操作\",\"options\":[{\"label\":\"创建\",\"value\":\"create\"},{\"label\":\"提示并报错\",\"value\":\"error\"}],\"default\":\"error\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"folder_name\",\"title\":\"文件夹名称\",\"name\":\"folder_name\",\"tip\":\"默认为空,使用原文件夹名称\",\"default\":\"\",\"required\":false},{\"types\":\"OptionType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"exist_options\",\"title\":\"文件夹存在时\",\"name\":\"exist_options\",\"tip\":\"选择文件夹已存在时的操作;生成副本:将在文件名称后增加数字标识,如a(1),如果副本文件夹同样存在,则数字递增;覆盖:删除已存在文件夹;跳过:返回当前已存在文件路径\",\"options\":[{\"label\":\"覆盖原有文件夹\",\"value\":\"overwrite\"},{\"label\":\"取消保存操作\",\"value\":\"skip\"},{\"label\":\"创建文件夹副本\",\"value\":\"generate\"}],\"default\":\"generate\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"move_folder_path\",\"title\":\"移动后文件夹路径\",\"tip\":\"保存移动后文件夹路径至输出变量,数据类型为字符串\"}],\"icon\":\"move-folder\",\"helpManual\":\"移动文件夹到指定目录,并保存移动后的文件夹路径到输出变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(227,'os/os.path','Folder.folder_rename','{\"key\":\"Folder.folder_rename\",\"title\":\"重命名文件夹\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.folder.Folder().folder_rename\",\"comment\":\"重命名文件夹 @{folder_path} 为 @{new_name} ,并保存重命名后的文件夹路径至变量 @{rename_folder_path}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"folder_path\",\"title\":\"文件夹路径\",\"name\":\"folder_path\",\"tip\":\"选择或输入待重命名文件夹路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"new_name\",\"title\":\"新文件夹名称\",\"name\":\"new_name\",\"tip\":\"输入新文件夹名称\",\"default\":\"\",\"required\":true},{\"types\":\"OptionType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"exist_options\",\"title\":\"文件夹存在时\",\"name\":\"exist_options\",\"tip\":\"选择文件夹已存在时的操作;生成副本:将在文件名称后增加数字标识,如a(1),如果副本文件夹同样存在,则数字递增;覆盖:删除已存在文件夹;跳过:返回当前已存在文件路径\",\"options\":[{\"label\":\"覆盖原有文件夹\",\"value\":\"overwrite\"},{\"label\":\"取消保存操作\",\"value\":\"skip\"},{\"label\":\"创建文件夹副本\",\"value\":\"generate\"}],\"default\":\"generate\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"rename_folder_path\",\"title\":\"重命名文件夹路径\",\"tip\":\"保存重命名后文件夹路径到输出变量,数据类型为字符串\"}],\"icon\":\"rename-folder\",\"helpManual\":\"重命名文件夹,并保存重命名后的文件夹路径到输出变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(228,'os/os.path','Folder.folder_clear','{\"key\":\"Folder.folder_clear\",\"title\":\"清空文件夹\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.folder.Folder().folder_clear\",\"comment\":\"清空文件夹 @{folder_path} ,并保存清空结果到变量 @{clear_folder_result}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"folder_path\",\"title\":\"文件夹路径\",\"name\":\"folder_path\",\"tip\":\"选择或输入待清空文件夹\",\"default\":\"\",\"required\":true}],\"outputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"clear_folder_result\",\"title\":\"清空操作结果\",\"tip\":\"保存清空结果到输出变量,数据类型为布尔值\"}],\"icon\":\"clear-folder\",\"helpManual\":\"清空指定文件夹,并保存操作结果到输出变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(229,'os/os.path','Folder.get_folder_list','{\"key\":\"Folder.get_folder_list\",\"title\":\"获取文件夹列表\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.folder.Folder().get_folder_list\",\"comment\":\"获取指定目录 @{folder_path} 下的文件夹列表,并保存文件夹列表至变量 @{folder_list}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"folder_path\",\"title\":\"文件夹目录\",\"name\":\"folder_path\",\"tip\":\"选择或输入文件夹目录路径\",\"default\":\"\",\"required\":true},{\"types\":\"TraverseType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"traverse_subfolder\",\"title\":\"遍历子目录\",\"name\":\"traverse_subfolder\",\"tip\":\"选择是否遍历目录下的子目录\",\"options\":[{\"label\":\"遍历子目录\",\"value\":\"yes\"},{\"label\":\"不遍历子目录\",\"value\":\"no\"}],\"default\":\"no\",\"required\":false},{\"types\":\"OutputType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"output_type\",\"title\":\"输出类型\",\"name\":\"output_type\",\"tip\":\"选择文件夹列表的输出类型\",\"options\":[{\"label\":\"列表输出\",\"value\":\"list\"},{\"label\":\"存储到表格文件\",\"value\":\"excel\"}],\"default\":\"list\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"excel_path\",\"title\":\"Excel文件保存目录\",\"name\":\"excel_path\",\"tip\":\"选择或输入保存的Excel文件保存目录\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.excel_path.show\",\"expression\":\"return $this.output_type.value == \'excel\'\"}],\"required\":true},{\"types\":\"StateType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"state_type\",\"title\":\"目录不存在时\",\"name\":\"state_type\",\"tip\":\"选择Excel文件保存目录不存在时执行的操作\",\"options\":[{\"label\":\"创建\",\"value\":\"create\"},{\"label\":\"提示并报错\",\"value\":\"error\"}],\"default\":\"error\",\"dynamics\":[{\"key\":\"$this.state_type.show\",\"expression\":\"return $this.output_type.value == \'excel\'\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"excel_name\",\"title\":\"Excel文件名\",\"name\":\"excel_name\",\"tip\":\"输入保存的Excel文件名,不需输入文件扩展名,默认扩展名为.xlsx\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.excel_name.show\",\"expression\":\"return $this.output_type.value == \'excel\'\"}],\"required\":true},{\"types\":\"SortMethod\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"sort_method\",\"title\":\"排序方式\",\"name\":\"sort_method\",\"tip\":\"选择排序方式\",\"options\":[{\"label\":\"无\",\"value\":\"none\"},{\"label\":\"按创建时间排序\",\"value\":\"ctime\"},{\"label\":\"按修改时间排序\",\"value\":\"mtime\"}],\"default\":\"none\",\"level\":\"advanced\",\"required\":true},{\"types\":\"SortType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"sort_type\",\"title\":\"排序类型\",\"name\":\"sort_type\",\"tip\":\"指定排序类型\",\"options\":[{\"label\":\"升序\",\"value\":\"ascending\"},{\"label\":\"降序\",\"value\":\"descending\"}],\"default\":\"ascending\",\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.sort_type.show\",\"expression\":\"return $this.sort_method.value [\'ctime\', \'mtime\']\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"folder_list\",\"title\":\"文件夹列表\",\"tip\":\"保存获取的文件夹列表到输出变量,数据类型为列表\"}],\"icon\":\"get-folder-list\",\"helpManual\":\"获取文件夹列表,并保存到输出变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(230,'os/os.system','System.run_command','{\"key\":\"System.run_command\",\"title\":\"运行或打开\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.process.Process().run_command\",\"comment\":\"运行或打开 @{command} ,并将执行结果保存到输出变量 @{process_out}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"command\",\"title\":\"命令或可执行文件\",\"name\":\"command\",\"tip\":\"输入cmd命令行或可执行.exe文件\",\"default\":\"\",\"required\":true},{\"types\":\"CmdType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"cmd_type\",\"title\":\"运行方式\",\"name\":\"cmd_type\",\"tip\":\"选择命令行执行方式\",\"options\":[{\"label\":\"运行\",\"value\":\"normal\"},{\"label\":\"管理员身份运行\",\"value\":\"admin\"}],\"default\":\"normal\",\"required\":false},{\"types\":\"RunType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"run_type\",\"title\":\"在指令执行结束之后\",\"name\":\"run_type\",\"tip\":\"选择是否继续执行指令,或等待程序执行结束\",\"options\":[{\"label\":\"继续执行下一指令\",\"value\":\"continue\"},{\"label\":\"等待指令执行结束\",\"value\":\"complete\"}],\"default\":\"continue\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"params\",\"title\":\"参数\",\"name\":\"params\",\"tip\":\"程序执行的所需参数\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"work_dir\",\"title\":\"工作目录\",\"name\":\"work_dir\",\"tip\":\"所执行命令的工作目录\",\"default\":\"\",\"level\":\"advanced\",\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"wait_time\",\"title\":\"等待时间不超过\",\"name\":\"wait_time\",\"tip\":\"指定命令执行的等待时间,默认60秒\",\"default\":60,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.wait_time.show\",\"expression\":\"return $this.run_type.value == \'complete\'\"}],\"required\":false}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"process_out\",\"title\":\"保存执行结果至\",\"tip\":\"输出cmd命令的执行结果并保存至变量,数据类型为布尔值\"}],\"icon\":\"run-or-open\",\"helpManual\":\"运行cmd命令或打开可执行.exe文件,并将执行结果保存到输出变量\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(231,'os/os.system','System.get_pid','{\"key\":\"System.get_pid\",\"title\":\"获取进程PID\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.process.Process().get_pid\",\"comment\":\"获取与输入 @{process_name} 匹配的进程PID,并保存至输出变量 @{match_proces_pid}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"process_name\",\"title\":\"待匹配内容\",\"name\":\"process_name\",\"tip\":\"输入待匹配进程内容,精确匹配模式下需输入完整进程名,区分大小写\",\"default\":\"\",\"required\":true},{\"types\":\"SearchType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"search_type\",\"title\":\"匹配方式\",\"name\":\"search_type\",\"tip\":\"选择匹配方式\",\"options\":[{\"label\":\"精确匹配\",\"value\":\"exact\"},{\"label\":\"模糊匹配\",\"value\":\"fuzzy\"},{\"label\":\"正则表达式匹配\",\"value\":\"regex\"}],\"default\":\"exact\",\"required\":false},{\"types\":\"PidType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"pid_type\",\"title\":\"获取内容\",\"name\":\"pid_type\",\"tip\":\"指定获取到匹配进程PID的内容\",\"options\":[{\"label\":\"获取全部\",\"value\":\"all\"},{\"label\":\"获取一个\",\"value\":\"one\"}],\"default\":\"all\",\"required\":false}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"match_proces_pid\",\"title\":\"输出匹配进程PID至\",\"tip\":\"当获取全部匹配PID时输出为列表,获取单个匹配PID时输出为整型\"}],\"icon\":\"get-process-pid\",\"helpManual\":\"输入待匹配进程名称,支持精确匹配/模糊匹配/正则表达式匹配,可获取单个匹配进程PID或全部匹配进程PID,并输出至变量列表\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(232,'os/os.system','System.terminate_process','{\"key\":\"System.terminate_process\",\"title\":\"终止进程\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.process.Process().terminate_process\",\"comment\":\"终止指定 @{termination_type} 的进程,并保存执行结果至输出变量 @{termination_process}\",\"inputList\":[{\"types\":\"TerminationType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"termination_type\",\"title\":\"终止方式\",\"name\":\"termination_type\",\"tip\":\"指定终止方式,通过进程PID/进程名称终止进程\",\"options\":[{\"label\":\"进程PID\",\"value\":\"pid\"},{\"label\":\"进程名称\",\"value\":\"name\"}],\"default\":\"pid\",\"required\":false},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"pid\",\"title\":\"进程PID\",\"name\":\"pid\",\"tip\":\"要终止的进程PID\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.pid.show\",\"expression\":\"return $this.termination_type.value == \'pid\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"process_name\",\"title\":\"进程名称\",\"name\":\"process_name\",\"tip\":\"要终止的进程名称\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.process_name.show\",\"expression\":\"return $this.termination_type.value == \'name\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"time_out\",\"title\":\"超时时间\",\"name\":\"time_out\",\"tip\":\"指定超时时间,单位为秒\",\"default\":5,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"required\":false}],\"outputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"termination_process\",\"title\":\"保存执行结果至\",\"tip\":\"输出执行结果并保存到变量,数据类型为布尔值\"}],\"icon\":\"terminate-process\",\"helpManual\":\"终止指定PID/名称的进程程序\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(233,'os/os.screenshot','System.screen_shot','{\"key\":\"System.screen_shot\",\"title\":\"屏幕截图\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.system.System().screen_shot\",\"comment\":\"按 @{screen_type} 方式截图并保存到 @{png_path} ,输出图片保存路径 @{screenshot_path}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"png_path\",\"title\":\"图片保存路径\",\"name\":\"png_path\",\"tip\":\"输入或选择截图后的文件保存路径\",\"default\":\"\",\"required\":true},{\"types\":\"StateType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"state_type\",\"title\":\"路径不存在时\",\"name\":\"state_type\",\"tip\":\"选择图片保存文件夹不存在时执行的操作\",\"options\":[{\"label\":\"创建\",\"value\":\"create\"},{\"label\":\"提示并报错\",\"value\":\"error\"}],\"default\":\"error\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"png_name\",\"title\":\"图片保存名称\",\"name\":\"png_name\",\"tip\":\"输入截图后的文件名,不需加文件后缀\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"ScreenType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"screen_type\",\"title\":\"截图区域\",\"name\":\"screen_type\",\"tip\":\"指定截图区域\",\"options\":[{\"label\":\"全屏\",\"value\":\"full\"},{\"label\":\"选择区域\",\"value\":\"region\"}],\"default\":\"full\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"top_left_x\",\"title\":\"左上角x坐标\",\"name\":\"top_left_x\",\"tip\":\"输入截图的矩形区域左上角横坐标,单位为像素px\",\"default\":0,\"dynamics\":[{\"key\":\"$this.top_left_x.show\",\"expression\":\"return $this.screen_type.value == \'region\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"top_left_y\",\"title\":\"左上角y坐标\",\"name\":\"top_left_y\",\"tip\":\"输入截图的矩形区域左上角纵坐标,单位为像素px\",\"default\":0,\"dynamics\":[{\"key\":\"$this.top_left_y.show\",\"expression\":\"return $this.screen_type.value == \'region\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"bottom_right_x\",\"title\":\"右下角x坐标\",\"name\":\"bottom_right_x\",\"tip\":\"输入截图的矩形区域右下角横坐标,单位为像素px\",\"default\":0,\"dynamics\":[{\"key\":\"$this.bottom_right_x.show\",\"expression\":\"return $this.screen_type.value == \'region\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"bottom_right_y\",\"title\":\"右下角y坐标\",\"name\":\"bottom_right_y\",\"tip\":\"输入截图的矩形区域右下角纵坐标,单位为像素px\",\"default\":0,\"dynamics\":[{\"key\":\"$this.bottom_right_y.show\",\"expression\":\"return $this.screen_type.value == \'region\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"screenshot_path\",\"title\":\"截图保存路径\",\"tip\":\"\"}],\"icon\":\"screen-screenshot\",\"helpManual\":\"选择屏幕或指定区域进行截屏,并保存到指定路径\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(234,'','System.screen_lock','{\"key\":\"System.screen_lock\",\"title\":\"屏幕锁定\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.system.System().screen_lock\",\"comment\":\"系统屏幕锁屏,并将操作结果输出至变量 @{screen_lock_result}\",\"inputList\":[],\"outputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"screen_lock_result\",\"title\":\"锁屏执行结果\",\"tip\":\"输出锁屏操作的执行结果并保存至变量,变量类型为布尔值\"}],\"icon\":\"screen-lock\",\"helpManual\":\"系统屏幕锁屏\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(235,'','System.screen_unlock','{\"key\":\"System.screen_unlock\",\"title\":\"屏幕解锁\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.system.System().screen_unlock\",\"comment\":\"通过用户名 @{user_name} 和 @{pwd_type} @{password_text||password_rsa} 进行系统屏幕解锁,并将操作结果输出至变量 @{screen_unlock_result}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"user_name\",\"title\":\"用户名\",\"name\":\"user_name\",\"tip\":\"待解锁屏幕用户名\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"PwdType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"pwd_type\",\"title\":\"解锁类型\",\"name\":\"pwd_type\",\"tip\":\"待解锁屏幕解锁类型\",\"options\":[{\"label\":\"密钥\",\"value\":\"rsa\"},{\"label\":\"密码\",\"value\":\"password\"}],\"default\":\"password\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"password_text\",\"title\":\"密码\",\"name\":\"password_text\",\"tip\":\"待解锁屏幕解锁密码\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.password_text.show\",\"expression\":\"return $this.pwd_type.value == \'password\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"password_rsa\",\"title\":\"密钥\",\"name\":\"password_rsa\",\"tip\":\"待解锁屏幕解锁密钥\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.password_rsa.show\",\"expression\":\"return $this.pwd_type.value == \'rsa\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"screen_unlock_result\",\"title\":\"执行结果\",\"tip\":\"输出屏幕解锁的执行结果并保存至变量,数据类型为布尔值\"}],\"icon\":\"screen-unlock\",\"helpManual\":\"输入用户名和密码进行系统屏幕解锁\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(236,'','System.printer','{\"key\":\"System.printer\",\"title\":\"打印机打印\",\"version\":\"1.0.0\",\"src\":\"astronverse.system.system.System().printer\",\"comment\":\"使用打印机 @{printer_name} @{batch_print} 打印指定文件 @{file_path||folder_path} ,并保存执行结果至输出变量 @{printer_status}\",\"inputList\":[{\"types\":\"FileType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"file_type\",\"title\":\"打印对象\",\"name\":\"file_type\",\"tip\":\"指定打印对象,支持打印WORD、EXCEL、PDF和图像文件,或批量打印文件夹中文件\",\"options\":[{\"label\":\"图片\",\"value\":\"picture\"},{\"label\":\"word\",\"value\":\"word\"},{\"label\":\"pdf\",\"value\":\"pdf\"},{\"label\":\"excel\",\"value\":\"excel\"}],\"default\":\"word\",\"required\":true},{\"types\":\"BatchType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"batch_print\",\"title\":\"批量打印\",\"name\":\"batch_print\",\"tip\":\"设置批量打印\",\"options\":[{\"label\":\"批量打印\",\"value\":\"batch\"},{\"label\":\"单张打印\",\"value\":\"single\"}],\"default\":\"single\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"待打印文件路径\",\"name\":\"file_path\",\"tip\":\"选择或输入待打印文件路径\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.file_path.show\",\"expression\":\"return $this.batch_print.value == \'single\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"folder_path\",\"title\":\"待打印文件目录\",\"name\":\"folder_path\",\"tip\":\"选择或输入待打印文件目录\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.folder_path.show\",\"expression\":\"return $this.batch_print.value == \'batch\'\"}],\"required\":true},{\"types\":\"PrinterType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"printer_type\",\"title\":\"打印设置\",\"name\":\"printer_type\",\"tip\":\"设置打印相关参数\",\"options\":[{\"label\":\"自定义\",\"value\":\"custom\"},{\"label\":\"默认\",\"value\":\"default\"}],\"default\":\"default\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"printer_name\",\"title\":\"打印机名称\",\"name\":\"printer_name\",\"tip\":\"输入打印机名称,为空时使用默认打印机\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"PaperType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"paper_size\",\"title\":\"纸张尺寸\",\"name\":\"paper_size\",\"tip\":\"指定打印纸张尺寸\",\"options\":[{\"label\":\"A3\",\"value\":\"A3\"},{\"label\":\"A4\",\"value\":\"A4\"},{\"label\":\"LA4\",\"value\":\"LA4\"},{\"label\":\"A5\",\"value\":\"A5\"},{\"label\":\"B4\",\"value\":\"B4\"},{\"label\":\"B5\",\"value\":\"B5\"},{\"label\":\"C_SHEET\",\"value\":\"C_SHEET\"},{\"label\":\"D_SHEET\",\"value\":\"D_SHEET\"},{\"label\":\"默认\",\"value\":\"CUSTOM\"}],\"default\":\"A4\",\"dynamics\":[{\"key\":\"$this.paper_size.show\",\"expression\":\"return $this.printer_type.value == \'custom\'\"}],\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page_weight\",\"title\":\"纸张宽度\",\"name\":\"page_weight\",\"tip\":\"输入打印纸张宽度\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.page_weight.show\",\"expression\":\"return $this.paper_size.value == \'CUSTOM\'\"}],\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page_height\",\"title\":\"纸张高度\",\"name\":\"page_height\",\"tip\":\"输入打印纸张高度\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.page_height.show\",\"expression\":\"return $this.paper_size.value == \'CUSTOM\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"print_num\",\"title\":\"打印份数\",\"name\":\"print_num\",\"tip\":\"输入打印份数,默认1份\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.print_num.show\",\"expression\":\"return $this.printer_type.value == \'custom\'\"}],\"required\":true},{\"types\":\"OrientationType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"orientation_type\",\"title\":\"打印版式\",\"name\":\"orientation_type\",\"tip\":\"\",\"options\":[{\"label\":\"水平方向\",\"value\":\"horizontal\"},{\"label\":\"垂直方向\",\"value\":\"vertical\"}],\"default\":\"vertical\",\"dynamics\":[{\"key\":\"$this.orientation_type.show\",\"expression\":\"return $this.printer_type.value == \'custom\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"scale\",\"title\":\"缩放(%)\",\"name\":\"scale\",\"tip\":\"\",\"default\":100,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.scale.show\",\"expression\":\"return $this.printer_type.value == \'custom\'\"}],\"required\":true},{\"types\":\"MarginType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"margin_type\",\"title\":\"边距(单位毫米)\",\"name\":\"margin_type\",\"tip\":\"\",\"options\":[{\"label\":\"自定义\",\"value\":\"custom\"},{\"label\":\"默认\",\"value\":\"default\"}],\"default\":\"default\",\"dynamics\":[{\"key\":\"$this.margin_type.show\",\"expression\":\"return $this.printer_type.value == \'custom\'\"}],\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"left_margin\",\"title\":\"左\",\"name\":\"left_margin\",\"tip\":\"\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.left_margin.show\",\"expression\":\"return $this.margin_type.value == \'custom\'\"}],\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"top_margin\",\"title\":\"上\",\"name\":\"top_margin\",\"tip\":\"\",\"default\":9.5,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.top_margin.show\",\"expression\":\"return $this.margin_type.value == \'custom\'\"}],\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"right_margin\",\"title\":\"右\",\"name\":\"right_margin\",\"tip\":\"\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.right_margin.show\",\"expression\":\"return $this.margin_type.value == \'custom\'\"}],\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"bottom_margin\",\"title\":\"下\",\"name\":\"bottom_margin\",\"tip\":\"\",\"default\":9.5,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.bottom_margin.show\",\"expression\":\"return $this.margin_type.value == \'custom\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page\",\"title\":\"页码范围\",\"name\":\"page\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.page.show\",\"expression\":\"return $this.file_type.value == \'excel\'\"}],\"required\":false}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"printer_status\",\"title\":\"打印结果\",\"tip\":\"保存打印结果到输出变量,数据类型为布尔值\"}],\"icon\":\"printer-print\",\"helpManual\":\"连接指定打印机进行文档打印\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(237,'ai/verify','VerifyCode.picture_code','{\"key\":\"VerifyCode.picture_code\",\"title\":\"通用数英验证码\",\"version\":\"1.0.0\",\"src\":\"astronverse.verifycode.verifycode.VerifyCode().picture_code\",\"comment\":\"识别浏览器中的验证码 @{picture_pick} ,返回识别结果 @{code_result}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"picture_pick\",\"title\":\"拾取验证码对象\",\"name\":\"picture_pick\",\"tip\":\"\",\"required\":true,\"noInput\":true},{\"types\":\"PictureCodeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"code_type\",\"title\":\"验证码类型\",\"name\":\"code_type\",\"tip\":\"\",\"options\":[{\"label\":\"通用数英验证码1-4位\",\"value\":\"10110\"},{\"label\":\"通用数英验证码5-8位\",\"value\":\"10111\"},{\"label\":\"通用数英验证码(特殊)\",\"value\":\"10211\"}],\"default\":\"10110\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"input_flag\",\"title\":\"是否填写输入框\",\"name\":\"input_flag\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"input_box\",\"title\":\"输入框对象\",\"name\":\"input_box\",\"tip\":\"\",\"dynamics\":[{\"key\":\"$this.input_box.show\",\"expression\":\"return $this.input_flag.value == true\"}],\"required\":true,\"noInput\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"code_result\",\"title\":\"识别结果\",\"tip\":\"\"}],\"icon\":\"captcha-text\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(238,'ai/verify','VerifyCode.slider_code','{\"key\":\"VerifyCode.slider_code\",\"title\":\"通用滑块验证码\",\"version\":\"1.0.0\",\"src\":\"astronverse.verifycode.verifycode.VerifyCode().slider_code\",\"comment\":\"在背景图为 @{picture_pick} 的滑块验证码上,拖动滑块 @{slider_pick} 至指定位置,拖动距离为 @{drag_distance}\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"picture_pick\",\"title\":\"背景图片对象\",\"name\":\"picture_pick\",\"tip\":\"\",\"required\":true,\"noInput\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"slider_pick\",\"title\":\"拾取滑块对象\",\"name\":\"slider_pick\",\"tip\":\"\",\"required\":true,\"noInput\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"unmatched_flag\",\"title\":\"是否为变速验证码\",\"name\":\"unmatched_flag\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"move_pic_pick\",\"title\":\"拾取滑动图片对象\",\"name\":\"move_pic_pick\",\"tip\":\"\",\"dynamics\":[{\"key\":\"$this.move_pic_pick.show\",\"expression\":\"return $this.unmatched_flag.value == true\"}],\"required\":true,\"noInput\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"mini_step\",\"title\":\"微调步长(px)\",\"name\":\"mini_step\",\"tip\":\"\",\"default\":5,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.mini_step.show\",\"expression\":\"return $this.unmatched_flag.value == true\"}],\"required\":true}],\"outputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"drag_distance\",\"title\":\"移动距离\",\"tip\":\"\"}],\"icon\":\"captcha-slider\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(239,'ai/verify','VerifyCode.click_code','{\"key\":\"VerifyCode.click_code\",\"title\":\"通用点击验证码\",\"version\":\"1.0.0\",\"src\":\"astronverse.verifycode.verifycode.VerifyCode().click_code\",\"comment\":\"在背景图为 @{picture_pick} 的点击验证码上,点击对应位置\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"picture_pick\",\"title\":\"点击图片对象\",\"name\":\"picture_pick\",\"tip\":\"需要包括大的点击图片和小的指明顺序的图片\",\"required\":true,\"noInput\":true},{\"types\":\"HintPosition\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"hint_position\",\"title\":\"指示顺序的图片相对大图的位置\",\"name\":\"hint_position\",\"tip\":\"如果指示顺序的图片相对大图在下,则选择下,反之选择上\",\"options\":[{\"label\":\"下\",\"value\":\"bottom\"},{\"label\":\"上\",\"value\":\"top\"}],\"default\":\"bottom\",\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"click_positions\"}],\"icon\":\"captcha-click\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(240,'cv','CV.cv_click','{\"key\":\"CV.cv_click\",\"title\":\"点击图像\",\"version\":\"1.0.0\",\"src\":\"astronverse.vision.cv.CV().cv_click\",\"comment\":\"鼠标(@{btn_type})(@{btn_model})图像(@{input_data})(@{click_position})\",\"inputList\":[{\"types\":\"IMGPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"CV\"}},\"key\":\"input_data\",\"title\":\"目标图像\",\"name\":\"input_data\",\"tip\":\"支持从图形库中选择或拾取图像获取图像元素\",\"required\":true,\"noInput\":true},{\"types\":\"BtnType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"btn_type\",\"title\":\"鼠标按键\",\"name\":\"btn_type\",\"tip\":\"\",\"options\":[{\"label\":\"左键\",\"value\":\"left\"},{\"label\":\"中键\",\"value\":\"middle\"},{\"label\":\"右键\",\"value\":\"right\"}],\"default\":\"left\",\"required\":false},{\"types\":\"BtnModel\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"btn_model\",\"title\":\"点击方式\",\"name\":\"btn_model\",\"tip\":\"\",\"options\":[{\"label\":\"单击\",\"value\":\"click\"},{\"label\":\"双击\",\"value\":\"double_click\"}],\"default\":\"click\",\"required\":false},{\"types\":\"PositionType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"click_position\",\"title\":\"点击位置\",\"name\":\"click_position\",\"tip\":\"选择鼠标点击位置\",\"options\":[{\"label\":\"中心点\",\"value\":\"center\"},{\"label\":\"随机位置\",\"value\":\"random\"},{\"label\":\"指定位置\",\"value\":\"specific\"}],\"default\":\"center\",\"required\":false},{\"types\":\"Any\",\"formType\":{\"type\":\"GRID\"},\"key\":\"specified_position\",\"title\":\"指定位置\",\"name\":\"specified_position\",\"tip\":\"\",\"default\":5,\"dynamics\":[{\"key\":\"$this.specified_position.show\",\"expression\":\"return $this.click_position.value == \'specific\'\"}],\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"horizontal_move\",\"title\":\"横向平移\",\"name\":\"horizontal_move\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.horizontal_move.show\",\"expression\":\"return $this.click_position.value == \'specific\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"vertical_move\",\"title\":\"纵向平移\",\"name\":\"vertical_move\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.vertical_move.show\",\"expression\":\"return $this.click_position.value == \'specific\'\"}],\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"SLIDER\"},\"key\":\"match_similarity\",\"title\":\"匹配相似度\",\"name\":\"match_similarity\",\"tip\":\"查找目标图像与当前页面的相似度阈值(最高匹配精确度为99%),精准匹配表示当前界面存在于截取的目标图像完全一致的时候才能匹配成功\",\"default\":0.95,\"required\":false},{\"types\":\"MoveType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"move_type\",\"title\":\"鼠标移动方式\",\"name\":\"move_type\",\"tip\":\"\",\"options\":[{\"label\":\"匀速直线\",\"value\":\"linear\"},{\"label\":\"模拟人工\",\"value\":\"simulation\"},{\"label\":\"瞬时移动\",\"value\":\"teleportation\"}],\"default\":\"linear\",\"level\":\"advanced\",\"required\":false},{\"types\":\"Speed\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"move_speed\",\"title\":\"鼠标移动速度\",\"name\":\"move_speed\",\"tip\":\"\",\"options\":[{\"label\":\"慢速\",\"value\":\"slow\"},{\"label\":\"正常\",\"value\":\"normal\"},{\"label\":\"快速\",\"value\":\"fast\"}],\"default\":\"normal\",\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.move_speed.show\",\"expression\":\"return [\'linear\',\'simulation\'].includes($this.move_type.value)\"}],\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"wait_time\",\"title\":\"等待图像出现时间(秒)\",\"name\":\"wait_time\",\"tip\":\"超过该时间停止等待,默认为10秒\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"required\":false}],\"outputList\":[],\"icon\":\"click-image\",\"helpManual\":\"在当前(激活)窗口检索目标图片,并在窗口界面中点击该图片。\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(241,'cv','CV.hover_image','{\"key\":\"CV.hover_image\",\"title\":\"鼠标悬浮在图像上\",\"version\":\"1.0.0\",\"src\":\"astronverse.vision.cv.CV().hover_image\",\"comment\":\"鼠标悬浮在图像(@{input_data})的(@{click_position})\",\"inputList\":[{\"types\":\"IMGPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"CV\"}},\"key\":\"input_data\",\"title\":\"目标图像\",\"name\":\"input_data\",\"tip\":\"支持从图形库中选择或拾取图像获取图像元素\",\"required\":true,\"noInput\":true},{\"types\":\"PositionType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"click_position\",\"title\":\"悬浮位置\",\"name\":\"click_position\",\"tip\":\"\",\"options\":[{\"label\":\"中心点\",\"value\":\"center\"},{\"label\":\"随机位置\",\"value\":\"random\"},{\"label\":\"指定位置\",\"value\":\"specific\"}],\"default\":\"center\",\"required\":false},{\"types\":\"Any\",\"formType\":{\"type\":\"GRID\"},\"key\":\"specified_position\",\"title\":\"指定位置\",\"name\":\"specified_position\",\"tip\":\"按照九宫格切割图像,支持选择九宫格任意一个区域,选择区域则悬浮在目标图像对应区域的中心点位置\",\"default\":5,\"dynamics\":[{\"key\":\"$this.specified_position.show\",\"expression\":\"return $this.click_position.value == \'specific\'\"}],\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"horizontal_move\",\"title\":\"横向平移\",\"name\":\"horizontal_move\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.horizontal_move.show\",\"expression\":\"return $this.click_position.value == \'specific\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"vertical_move\",\"title\":\"纵向平移\",\"name\":\"vertical_move\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.vertical_move.show\",\"expression\":\"return $this.click_position.value == \'specific\'\"}],\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"SLIDER\"},\"key\":\"match_similarity\",\"title\":\"匹配相似度\",\"name\":\"match_similarity\",\"tip\":\"查找目标图像与当前页面的相似度阈值(最高匹配精确度为99%),精准匹配表示当前界面存在于截取的目标图像完全一致的时候才能匹配成功\",\"default\":0.95,\"required\":false},{\"types\":\"MoveType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"move_type\",\"title\":\"鼠标移动方式\",\"name\":\"move_type\",\"tip\":\"\",\"options\":[{\"label\":\"匀速直线\",\"value\":\"linear\"},{\"label\":\"模拟人工\",\"value\":\"simulation\"},{\"label\":\"瞬时移动\",\"value\":\"teleportation\"}],\"default\":\"linear\",\"level\":\"advanced\",\"required\":false},{\"types\":\"Speed\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"move_speed\",\"title\":\"鼠标移动速度\",\"name\":\"move_speed\",\"tip\":\"\",\"options\":[{\"label\":\"慢速\",\"value\":\"slow\"},{\"label\":\"正常\",\"value\":\"normal\"},{\"label\":\"快速\",\"value\":\"fast\"}],\"default\":\"normal\",\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.move_speed.show\",\"expression\":\"return [\'linear\',\'simulation\'].includes($this.move_type.value)\"}],\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"wait_time\",\"title\":\"等待图像出现时间(秒)\",\"name\":\"wait_time\",\"tip\":\"超过该时间停止等待,默认为10秒\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"required\":false}],\"outputList\":[],\"icon\":\"mouse-hover-image\",\"helpManual\":\"在当前(激活)窗口检索图像,并将鼠标移动到该图像的指定位置上。\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(242,'cv','CV.is_image_exist','{\"key\":\"CV.is_image_exist\",\"title\":\"IF 图像存在\",\"version\":\"1.0.0\",\"src\":\"astronverse.vision.cv.CV().is_image_exist\",\"comment\":\"判断图像(@{input_data})在当前界面(@{exist_type})\",\"inputList\":[{\"types\":\"IMGPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"CV\"}},\"key\":\"input_data\",\"title\":\"目标图像\",\"name\":\"input_data\",\"tip\":\"支持从图形库中选择或拾取图像获取图像元素\",\"required\":true,\"noInput\":true},{\"types\":\"ExistType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_type\",\"title\":\"判断类型\",\"name\":\"exist_type\",\"tip\":\"判断图像存在或不存在,分别执行对应代码块内容\",\"options\":[{\"label\":\"存在\",\"value\":\"exist\"},{\"label\":\"不存在\",\"value\":\"not_exist\"}],\"default\":\"exist\",\"required\":false},{\"types\":\"Float\",\"formType\":{\"type\":\"SLIDER\"},\"key\":\"match_similarity\",\"title\":\"匹配相似度\",\"name\":\"match_similarity\",\"tip\":\"查找目标图像与当前页面的相似度阈值(最高匹配精确度为99%),精准匹配表示当前界面存在于截取的目标图像完全一致的时候才能匹配成功\",\"default\":0.95,\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"wait_time\",\"title\":\"等待图像时间(秒)\",\"name\":\"wait_time\",\"tip\":\"超过该时间停止等待,默认为10秒\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"required\":false}],\"outputList\":[],\"icon\":\"if-image-exists\",\"helpManual\":\"在当前(激活)窗口检索图像,判断是否存在。\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(243,'cv','CV.wait_image','{\"key\":\"CV.wait_image\",\"title\":\"等待图像\",\"version\":\"1.0.0\",\"src\":\"astronverse.vision.cv.CV().wait_image\",\"comment\":\"等待图像(@{input_data})(@{wait_type})\",\"inputList\":[{\"types\":\"IMGPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"CV\"}},\"key\":\"input_data\",\"title\":\"目标图像\",\"name\":\"input_data\",\"tip\":\"支持从图形库中选择或拾取图像获取图像元素\",\"required\":true,\"noInput\":true},{\"types\":\"WaitType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"wait_type\",\"title\":\"等待类型\",\"name\":\"wait_type\",\"tip\":\"等待图像出现或消失\",\"options\":[{\"label\":\"图像出现\",\"value\":\"appear\"},{\"label\":\"图像消失\",\"value\":\"disappear\"}],\"default\":\"appear\",\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"wait_time\",\"title\":\"等待时间(秒)\",\"name\":\"wait_time\",\"tip\":\"超过该时间停止等待,默认为10秒\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Float\",\"formType\":{\"type\":\"SLIDER\"},\"key\":\"match_similarity\",\"title\":\"匹配相似度\",\"name\":\"match_similarity\",\"tip\":\"查找目标图像与当前页面的相似度阈值(最高匹配精确度为99%),精准匹配表示当前界面存在于截取的目标图像完全一致的时候才能匹配成功\",\"default\":0.95,\"required\":false}],\"outputList\":[{\"types\":\"Bool\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"image_wait_result\",\"title\":\"等待结果\",\"tip\":\"目标图像是否出现/消失,在等待时间内出现/消失为true,反之为false\"}],\"icon\":\"wait-image\",\"helpManual\":\"等待目标图像出现或消失,再继续执行流程。\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(244,'cv','CV.image_input','{\"key\":\"CV.image_input\",\"title\":\"图像输入框输入\",\"version\":\"1.0.0\",\"src\":\"astronverse.vision.cv.CV().image_input\",\"comment\":\"拾取图像输入框(@{input_data})以(@{input_type})输入(@{input_content})\",\"inputList\":[{\"types\":\"IMGPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"CV\"}},\"key\":\"input_data\",\"title\":\"目标图像\",\"name\":\"input_data\",\"tip\":\"支持从图形库中选择或拾取图像获取图像元素\",\"required\":true,\"noInput\":true},{\"types\":\"InputType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"input_type\",\"title\":\"输入方式\",\"name\":\"input_type\",\"tip\":\"\",\"options\":[{\"label\":\"字符输入\",\"value\":\"text\"},{\"label\":\"剪切板输入\",\"value\":\"clip\"}],\"default\":\"text\",\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"input_content\",\"title\":\"输入内容\",\"name\":\"input_content\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.input_content.show\",\"expression\":\"return $this.input_type.value == \'text\'\"}],\"required\":true},{\"types\":\"Simulate_flag\",\"formType\":{\"type\":\"SWITCH\"},\"key\":\"simulate_flag\",\"title\":\"模拟人工输入\",\"name\":\"simulate_flag\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":\"yes\"},{\"label\":\"否\",\"value\":\"no\"}],\"default\":\"yes\",\"dynamics\":[{\"key\":\"$this.simulate_flag.show\",\"expression\":\"return $this.input_type.value == \'text\'\"}],\"required\":false},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"interval\",\"title\":\"输入间隔\",\"name\":\"interval\",\"tip\":\"\",\"default\":0.1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.interval.show\",\"expression\":\"return $this.input_type.value == \'text\'\"}],\"required\":false},{\"types\":\"Float\",\"formType\":{\"type\":\"SLIDER\"},\"key\":\"match_similarity\",\"title\":\"匹配相似度\",\"name\":\"match_similarity\",\"tip\":\"\",\"default\":0.95,\"required\":false},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"wait_time\",\"title\":\"等待图像出现时间(秒)\",\"name\":\"wait_time\",\"tip\":\"超过该时间停止等待,默认为10秒\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false}],\"outputList\":[],\"icon\":\"image-input-box\",\"helpManual\":\"点击目标输入框的图像,并输入内容\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(245,'desktop/desktop.window','Window.exist','{\"key\":\"Window.exist\",\"title\":\"IF 窗口存在\",\"version\":\"1.0.0\",\"src\":\"astronverse.window.window.Window().exist\",\"comment\":\"判断拾取窗口(@{pick})是否(@{check_type}),是就执行以下操作\",\"inputList\":[{\"types\":\"WinPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WINDOW\"}},\"key\":\"pick\",\"title\":\"窗口拾取\",\"name\":\"pick\",\"tip\":\"选择需要判断是否存在的窗口对象\",\"required\":true,\"noInput\":true},{\"types\":\"WindowExistType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"check_type\",\"title\":\"判断方式\",\"name\":\"check_type\",\"tip\":\"选择判断方式,默认为存在\",\"options\":[{\"label\":\"存在\",\"value\":\"exist\"},{\"label\":\"不存在\",\"value\":\"not_exist\"}],\"default\":\"exist\",\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"wait_time\",\"title\":\"等待时间(秒)\",\"name\":\"wait_time\",\"tip\":\"等待判断结果的时间\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"check-window-exists\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(246,'desktop/desktop.window','Window.top','{\"key\":\"Window.top\",\"title\":\"置顶窗口\",\"version\":\"1.0.0\",\"src\":\"astronverse.window.window.Window().top\",\"comment\":\"置顶窗口对象(@{pick})\",\"inputList\":[{\"types\":\"WinPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WINDOW\"}},\"key\":\"pick\",\"title\":\"窗口拾取\",\"name\":\"pick\",\"tip\":\"拾取需要置顶的窗口对象\",\"required\":true,\"noInput\":true}],\"outputList\":[],\"icon\":\"pin-window\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(247,'desktop/desktop.window','Window.close','{\"key\":\"Window.close\",\"title\":\"关闭窗口\",\"version\":\"1.0.0\",\"src\":\"astronverse.window.window.Window().close\",\"comment\":\"关闭桌面软件窗口对象(@{pick})\",\"inputList\":[{\"types\":\"WinPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WINDOW\"}},\"key\":\"pick\",\"title\":\"窗口拾取\",\"name\":\"pick\",\"tip\":\"拾取需要置顶的窗口对象\",\"required\":true,\"noInput\":true}],\"outputList\":[],\"icon\":\"close-window\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(248,'desktop/desktop.window','Window.set_size','{\"key\":\"Window.set_size\",\"title\":\"调整窗口大小\",\"version\":\"1.0.0\",\"src\":\"astronverse.window.window.Window().set_size\",\"comment\":\"调整拾取到的窗口(@{pick})大小,通过(@{size_type:自定义})的形式将窗口宽度和高度分别设置为(@{width}) (@{height})\",\"inputList\":[{\"types\":\"WinPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WINDOW\"}},\"key\":\"pick\",\"title\":\"窗口拾取\",\"name\":\"pick\",\"tip\":\"拾取需要调整大小的桌面软件窗口\",\"required\":true,\"noInput\":true},{\"types\":\"WindowSizeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"size_type\",\"title\":\"调整方式\",\"name\":\"size_type\",\"tip\":\"\",\"options\":[{\"label\":\"自定义\",\"value\":\"custom\"},{\"label\":\"最大化\",\"value\":\"max\"},{\"label\":\"最小化\",\"value\":\"min\"}],\"default\":\"max\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"width\",\"title\":\"窗口宽度\",\"name\":\"width\",\"tip\":\"设置指定窗口宽度值,单位为屏幕的分辨率像素px,一般为0-9999之间的数值\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.width.show\",\"expression\":\"return $this.size_type.value == \'custom\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"height\",\"title\":\"窗口高度\",\"name\":\"height\",\"tip\":\"设置指定窗口高度值,单位为屏幕的分辨率像素px,一般为0-9999之间的数值\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.height.show\",\"expression\":\"return $this.size_type.value == \'custom\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"resize-window\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(249,'desktop','WinEle.click_element','{\"key\":\"WinEle.click_element\",\"title\":\"点击元素(桌面)\",\"version\":\"1.0.0\",\"src\":\"astronverse.winelement.winele.WinEle().click_element\",\"comment\":\"@{click_type} 拾取到的元素 @{pick} ,最长等待 @{wait_time} 秒直到此元素出现\",\"inputList\":[{\"types\":\"WinPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"ELEMENT\"}},\"key\":\"pick\",\"title\":\"元素拾取\",\"name\":\"pick\",\"tip\":\"\",\"required\":true,\"noInput\":true},{\"types\":\"MouseClickButton\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"click_button\",\"title\":\"点击按钮\",\"name\":\"click_button\",\"tip\":\"\",\"options\":[{\"label\":\"左键\",\"value\":\"left\"},{\"label\":\"右键\",\"value\":\"right\"},{\"label\":\"中键\",\"value\":\"middle\"}],\"default\":\"left\",\"required\":true},{\"types\":\"MouseClickType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"click_type\",\"title\":\"点击类型\",\"name\":\"click_type\",\"tip\":\"\",\"options\":[{\"label\":\"单击\",\"value\":\"click\"},{\"label\":\"双击\",\"value\":\"double_click\"}],\"default\":\"click\",\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"wait_time\",\"title\":\"等待元素出现时间\",\"name\":\"wait_time\",\"tip\":\"\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"horizontals_offset\",\"title\":\"横向偏移量\",\"name\":\"horizontals_offset\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"verticals_offset\",\"title\":\"纵向偏移量\",\"name\":\"verticals_offset\",\"tip\":\"\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"MouseClickKeyboard\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"keyboard_input\",\"title\":\"键盘辅助输入\",\"name\":\"keyboard_input\",\"tip\":\"点击时同时按下键盘上的某些键\",\"options\":[{\"label\":\"不使用\",\"value\":\"none\"},{\"label\":\"Alt键\",\"value\":\"alt\"},{\"label\":\"Ctrl键\",\"value\":\"ctrl\"},{\"label\":\"Shift键\",\"value\":\"shift\"},{\"label\":\"Win键\",\"value\":\"win\"}],\"default\":\"none\",\"required\":true}],\"outputList\":[],\"icon\":\"click-element-win\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(250,'desktop','WinEle.screenshot_element','{\"key\":\"WinEle.screenshot_element\",\"title\":\"元素截图(桌面)\",\"version\":\"1.0.0\",\"src\":\"astronverse.winelement.winele.WinEle().screenshot_element\",\"comment\":\"截图拾取到的元素 @{pick} ,并保存至文件夹 @{file_path}\",\"inputList\":[{\"types\":\"WinPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"ELEMENT\"}},\"key\":\"pick\",\"title\":\"元素拾取\",\"name\":\"pick\",\"tip\":\"\",\"required\":true,\"noInput\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"file_path\",\"title\":\"文件保存路径\",\"name\":\"file_path\",\"tip\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"file_name\",\"title\":\"文件名\",\"name\":\"file_name\",\"tip\":\"\",\"default\":\"桌面元素截图\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_type\",\"title\":\"文件同名时处理方式\",\"name\":\"exist_type\",\"tip\":\"\",\"options\":[{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"required\":true}],\"outputList\":[],\"icon\":\"element-screenshot-win\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(251,'desktop','WinEle.hover_element','{\"key\":\"WinEle.hover_element\",\"title\":\"鼠标悬停元素(桌面)\",\"version\":\"1.0.0\",\"src\":\"astronverse.winelement.winele.WinEle().hover_element\",\"comment\":\"鼠标悬停拾取到的元素 @{pick} ,并设置等待时间 @{wait_time} 秒\",\"inputList\":[{\"types\":\"WinPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"ELEMENT\"}},\"key\":\"pick\",\"title\":\"元素拾取\",\"name\":\"pick\",\"tip\":\"\",\"required\":true,\"noInput\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"wait_time\",\"title\":\"等待元素出现时间\",\"name\":\"wait_time\",\"tip\":\"\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"mouse-hover-element-win\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(252,'desktop','WinEle.input_text_element','{\"key\":\"WinEle.input_text_element\",\"title\":\"填写输入框(桌面)\",\"version\":\"1.0.0\",\"src\":\"astronverse.winelement.winele.WinEle().input_text_element\",\"comment\":\"填写输入框 @{pick} ,并设置输入类型为 @{input_type} ,输入内容为 @{text}\",\"inputList\":[{\"types\":\"WinPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"ELEMENT\"}},\"key\":\"pick\",\"title\":\"元素拾取\",\"name\":\"pick\",\"tip\":\"\",\"required\":true,\"noInput\":true},{\"types\":\"ElementInputType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"input_type\",\"title\":\"输入类型\",\"name\":\"input_type\",\"tip\":\"\",\"options\":[{\"label\":\"键盘输入\",\"value\":\"keyboard\"},{\"label\":\"剪贴板输入\",\"value\":\"clipboard\"}],\"default\":\"keyboard\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"text\",\"title\":\"输入内容\",\"name\":\"text\",\"tip\":\"\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.text.show\",\"expression\":\"return $this.input_type.value == \'keyboard\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"clear_first\",\"title\":\"是否清空输入框内容\",\"name\":\"clear_first\",\"tip\":\"\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"wait_time\",\"title\":\"等待元素出现时间\",\"name\":\"wait_time\",\"tip\":\"\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"fill-input-win\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(253,'desktop','WinEle.get_element_text','{\"key\":\"WinEle.get_element_text\",\"title\":\"获取元素文本(桌面)\",\"version\":\"1.0.0\",\"src\":\"astronverse.winelement.winele.WinEle().get_element_text\",\"comment\":\"从元素 @{pick} 提取文本并保存到 @{ele_text}\",\"inputList\":[{\"types\":\"WinPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"ELEMENT\"}},\"key\":\"pick\",\"title\":\"元素拾取\",\"name\":\"pick\",\"tip\":\"\",\"required\":true,\"noInput\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"wait_time\",\"title\":\"等待元素出现时间\",\"name\":\"wait_time\",\"tip\":\"\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"ele_text\",\"title\":\"元素文本\",\"tip\":\"\"}],\"icon\":\"get-element-text-win\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(254,'desktop','WinEle.similar','{\"key\":\"WinEle.similar\",\"title\":\"获取相似元素列表(桌面)\",\"version\":\"1.0.0\",\"src\":\"astronverse.winelement.winele.WinEle().similar\",\"comment\":\"获取拾取到的元素 @{pick} 相似的元素,并将相似元素数组输出至 @{get_similar_ele}\",\"inputList\":[{\"types\":\"WinPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WinPick\"}},\"key\":\"pick\",\"title\":\"相识元素拾取\",\"name\":\"pick\",\"tip\":\"在桌面上拾取不同位置的两个相似元素\",\"required\":true,\"noInput\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"wait_time\",\"title\":\"等待元素出现时间(秒)\",\"name\":\"wait_time\",\"tip\":\"超过该时间停止等待\",\"default\":10,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"get_similar_ele\",\"title\":\"元素信息\",\"tip\":\"\"}],\"icon\":\"get-similar-elements-win\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(255,'','Docx.open_document','{\"key\":\"Docx.open_document\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().open_document\",\"inputList\":[{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"name\":\"file_path\",\"default\":\"\",\"required\":true},{\"types\":\"ApplicationType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"default_application\",\"name\":\"default_application\",\"options\":[{\"label\":\"Word\",\"value\":\"Word\"},{\"label\":\"WPS\",\"value\":\"WPS\"},{\"label\":\"默认软件\",\"value\":\"Default\"}],\"default\":\"Default\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"visible_flag\",\"name\":\"visible_flag\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"EncodingType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"encoding\",\"name\":\"encoding\",\"options\":[{\"label\":\"utf-8\",\"value\":\"utf-8\"},{\"label\":\"gbk\",\"value\":\"gbk\"}],\"default\":\"utf-8\",\"level\":\"advanced\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"open_pwd_flag\",\"name\":\"open_pwd_flag\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"level\":\"advanced\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"open_pwd\",\"name\":\"open_pwd\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.open_pwd.show\",\"expression\":\"return $this.open_pwd_flag.value == true\"}],\"required\":false},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"write_pwd_flag\",\"name\":\"write_pwd_flag\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"level\":\"advanced\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"write_pwd\",\"name\":\"write_pwd\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.write_pwd.show\",\"expression\":\"return $this.write_pwd_flag.value == true\"}],\"required\":false}],\"outputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"doc_obj\"}]}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(256,'','Docx.read_document_content','{\"key\":\"Docx.read_document_content\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().read_document_content\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"name\":\"doc\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"SelectRangeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"select_range\",\"name\":\"select_range\",\"options\":[{\"label\":\"整个文档\",\"value\":\"all\"},{\"label\":\"选中区域\",\"value\":\"selected\"}],\"default\":\"all\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"doc_data\"}]}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(257,'document/document.Word','Docx.create_docx','{\"key\":\"Docx.create_docx\",\"title\":\"新建Word文档\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().create_docx\",\"comment\":\"新建Word文档,保存到路径为 @{file_path} 的位置,文件名为 @{file_name} ,返回Word对象 @{doc_obj} 和保存路径 @{doc_create_path}\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"file_path\",\"title\":\"文档保存文件夹\",\"name\":\"file_path\",\"tip\":\"填写Word文档的保存文件夹路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"file_name\",\"title\":\"文档名称\",\"name\":\"file_name\",\"tip\":\"填写Word文档的名称\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"ApplicationType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"default_application\",\"title\":\"驱动方式\",\"name\":\"default_application\",\"tip\":\"选择Word文档的打开方式,如Word或WPS\",\"options\":[{\"label\":\"Word\",\"value\":\"Word\"},{\"label\":\"WPS\",\"value\":\"WPS\"},{\"label\":\"默认软件\",\"value\":\"Default\"}],\"default\":\"Word\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"visible_flag\",\"title\":\"是否可见\",\"name\":\"visible_flag\",\"tip\":\"是否显示Word文档窗口\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_handle_type\",\"title\":\"存在同名文件处理方式\",\"name\":\"exist_handle_type\",\"tip\":\"选择存在文件处理方式,支持覆盖原有文件、创建文件副本、取消保存操作\",\"options\":[{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"required\":true}],\"outputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"doc_obj\",\"title\":\"Word对象\",\"tip\":\"\"},{\"types\":\"PATH\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"doc_create_path\",\"title\":\"文档保存路径\",\"tip\":\"保存的Word文档的完整路径\"}],\"icon\":\"word-new-document\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(258,'document/document.Word','Docx.save_docx','{\"key\":\"Docx.save_docx\",\"title\":\"保存Word文档\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().save_docx\",\"comment\":\"保存Word文档对象 @{doc} ,保存方式为 @{save_type}, 并输出保存路径 @{save_file_path}\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"SaveType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"save_type\",\"title\":\"保存类型\",\"name\":\"save_type\",\"tip\":\"选择保存类型,如保存、另存为、不保存\",\"options\":[{\"label\":\"保存\",\"value\":\"save\"},{\"label\":\"另存为\",\"value\":\"save_as\"},{\"label\":\"不保存\",\"value\":\"abort\"}],\"default\":\"save\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"file_path\",\"title\":\"文档路径\",\"name\":\"file_path\",\"tip\":\"填写Word文档的保存路径\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.file_path.show\",\"expression\":\"return $this.save_type.value == \'save_as\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"file_name\",\"title\":\"文档名称\",\"name\":\"file_name\",\"tip\":\"填写Word文档的名称\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.file_name.show\",\"expression\":\"return $this.save_type.value == \'save_as\'\"}],\"required\":true},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_handle_type\",\"title\":\"存在同名文件处理方式\",\"name\":\"exist_handle_type\",\"tip\":\"选择存在文件处理方式,支持覆盖原有文件、创建文件副本、取消保存操作\",\"options\":[{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"dynamics\":[{\"key\":\"$this.exist_handle_type.show\",\"expression\":\"return $this.save_type.value == \'save_as\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"close_flag\",\"title\":\"是否关闭文档\",\"name\":\"close_flag\",\"tip\":\"选择是否关闭文档窗口\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true}],\"outputList\":[{\"types\":\"PATH\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"save_file_path\",\"title\":\"保存路径\",\"tip\":\"保存的Word文档的完整路径\"}],\"icon\":\"word-save-document\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(259,'document/document.Word','Docx.close_docx','{\"key\":\"Docx.close_docx\",\"title\":\"关闭Word文档\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().close_docx\",\"comment\":\"关闭Word文档对象 @{doc}\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"CloseRangeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"close_range_flag\",\"title\":\"关闭文档范围\",\"name\":\"close_range_flag\",\"tip\":\"选择关闭文档的范围,如关闭当前文档或关闭所有文档\",\"options\":[{\"label\":\"关闭当前文档\",\"value\":\"one\"},{\"label\":\"关闭所有文档\",\"value\":\"all\"}],\"default\":\"one\",\"required\":true},{\"types\":\"SaveType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"save_type\",\"title\":\"保存类型\",\"name\":\"save_type\",\"tip\":\"选择保存类型,如保存、另存为、不保存\",\"options\":[{\"label\":\"保存\",\"value\":\"save\"},{\"label\":\"另存为\",\"value\":\"save_as\"},{\"label\":\"不保存\",\"value\":\"abort\"}],\"default\":\"save\",\"dynamics\":[{\"key\":\"$this.save_type.show\",\"expression\":\"return $this.close_range_flag.value == \'one\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"file_path\",\"title\":\"另存为文档路径\",\"name\":\"file_path\",\"tip\":\"填写Word文档的保存路径\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.file_path.show\",\"expression\":\"return $this.save_type.value == \'save_as\' && $this.close_range_flag.value == \'one\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"file_name\",\"title\":\"另存为文档名称\",\"name\":\"file_name\",\"tip\":\"填写Word文档的名称\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.file_name.show\",\"expression\":\"return $this.save_type.value == \'save_as\' && $this.close_range_flag.value == \'one\'\"}],\"required\":true},{\"types\":\"FileExistenceType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"exist_handle_type\",\"title\":\"存在同名文件处理方式\",\"name\":\"exist_handle_type\",\"tip\":\"选择存在文件处理方式,支持覆盖原有文件、创建文件副本、取消保存操作\",\"options\":[{\"label\":\"覆盖原有文件\",\"value\":\"overwrite\"},{\"label\":\"创建文件副本\",\"value\":\"rename\"},{\"label\":\"取消保存操作\",\"value\":\"cancel\"}],\"default\":\"rename\",\"dynamics\":[{\"key\":\"$this.exist_handle_type.show\",\"expression\":\"return $this.close_range_flag.value == \'one\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"pkill_flag\",\"title\":\"是否结束Word或WPS进程\",\"name\":\"pkill_flag\",\"tip\":\"选择是否结束Word或WPS进程\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"dynamics\":[{\"key\":\"$this.pkill_flag.show\",\"expression\":\"return $this.close_range_flag.value == \'all\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"word-close-document\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(260,'document/document.Word','Docx.insert_docx','{\"key\":\"Docx.insert_docx\",\"title\":\"插入文本到Word文档\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().insert_docx\",\"comment\":\"向Word文档对象 @{doc} 插入文本 @{text}\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"text\",\"title\":\"插入文本\",\"name\":\"text\",\"tip\":\"填写要插入的文本\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"enter_flag\",\"title\":\"是否在插入前换行\",\"name\":\"enter_flag\",\"tip\":\"选择是否在插入前换行\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"font_size\",\"title\":\"字体大小\",\"name\":\"font_size\",\"tip\":\"填写字体大小\",\"default\":12,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"bold_flag\",\"title\":\"是否加粗\",\"name\":\"bold_flag\",\"tip\":\"选择是否加粗\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"italic_flag\",\"title\":\"是否斜体\",\"name\":\"italic_flag\",\"tip\":\"选择是否斜体\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"UnderLineStyle\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"underline_flag\",\"title\":\"是否添加下划线\",\"name\":\"underline_flag\",\"tip\":\"选择是否添加下划线\",\"options\":[{\"label\":\"无下划线\",\"value\":0},{\"label\":\"有下划线\",\"value\":1}],\"default\":0,\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"font_name\",\"title\":\"字体名称\",\"name\":\"font_name\",\"tip\":\"填写字体名称\",\"default\":\"宋体\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":false},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_COLOR\"},\"key\":\"font_color\",\"title\":\"字体颜色\",\"name\":\"font_color\",\"tip\":\"选择字体颜色\",\"default\":\"0,0,0\",\"required\":false}],\"outputList\":[],\"icon\":\"word-insert-text\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(261,'document/document.Word','Docx.select_text','{\"key\":\"Docx.select_text\",\"title\":\"选择Word文本\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().select_text\",\"comment\":\"从Word文档对象 @{doc} 中选择文本\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"SelectTextType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"select_type\",\"title\":\"选择文本方式\",\"name\":\"select_type\",\"tip\":\"支持选择全文、段落、行\",\"options\":[{\"label\":\"全文\",\"value\":\"all\"},{\"label\":\"段落\",\"value\":\"paragraph\"},{\"label\":\"行\",\"value\":\"row\"}],\"default\":\"all\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"p_start\",\"title\":\"起始段落号\",\"name\":\"p_start\",\"tip\":\"输入起始段落号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.p_start.show\",\"expression\":\"return $this.select_type.value == \'paragraph\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"p_end\",\"title\":\"结束段落号\",\"name\":\"p_end\",\"tip\":\"输入结束段落号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.p_end.show\",\"expression\":\"return $this.select_type.value == \'paragraph\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"r_start\",\"title\":\"起始行号\",\"name\":\"r_start\",\"tip\":\"输入起始行号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.r_start.show\",\"expression\":\"return $this.select_type.value == \'row\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"r_end\",\"title\":\"结束行号\",\"name\":\"r_end\",\"tip\":\"输入结束行号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.r_end.show\",\"expression\":\"return $this.select_type.value == \'row\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"word-select-text\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(262,'document/document.Word','Docx.get_cursor_position','{\"key\":\"Docx.get_cursor_position\",\"title\":\"定位Word光标\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().get_cursor_position\",\"comment\":\"在Word文档对象 @{doc} 中定位光标位置\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"CursorPointerType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"by\",\"title\":\"光标定位方式\",\"name\":\"by\",\"tip\":\"选择定位到全文、段落、行、文本\",\"options\":[{\"label\":\"文档\",\"value\":\"all\"},{\"label\":\"段落\",\"value\":\"paragraph\"},{\"label\":\"行\",\"value\":\"row\"},{\"label\":\"文本内容\",\"value\":\"content\"}],\"default\":\"all\",\"required\":true},{\"types\":\"CursorPositionType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"pos\",\"title\":\"光标相对位置\",\"name\":\"pos\",\"tip\":\"所选内容之前/所选内容之后\",\"options\":[{\"label\":\"所选内容之前\",\"value\":\"head\"},{\"label\":\"所选内容之后\",\"value\":\"tail\"}],\"default\":\"head\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"content\",\"title\":\"文本内容\",\"name\":\"content\",\"tip\":\"如果选择定位文本,输入文本内容\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.content.show\",\"expression\":\"return $this.by.value == \'content\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"c_idx\",\"title\":\"文本序号\",\"name\":\"c_idx\",\"tip\":\"输入定位文本的序号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.c_idx.show\",\"expression\":\"return $this.by.value == \'content\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"p_idx\",\"title\":\"段落号\",\"name\":\"p_idx\",\"tip\":\"输入定位段落号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.p_idx.show\",\"expression\":\"return $this.by.value == \'paragraph\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"r_idx\",\"title\":\"行号\",\"name\":\"r_idx\",\"tip\":\"选择定位的行号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.r_idx.show\",\"expression\":\"return $this.by.value == \'row\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"word-position-cursor\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(263,'document/document.Word','Docx.move_cursor','{\"key\":\"Docx.move_cursor\",\"title\":\"移动Word光标\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().move_cursor\",\"comment\":\"在Word文档对象 @{doc} 中移动光标\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"MoveDirectionType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"direction\",\"title\":\"光标移动方向\",\"name\":\"direction\",\"tip\":\"可选择向上、向下、向左、向右\",\"options\":[{\"label\":\"向上\",\"value\":\"up\"},{\"label\":\"向下\",\"value\":\"down\"},{\"label\":\"向左\",\"value\":\"left\"},{\"label\":\"向右\",\"value\":\"right\"}],\"default\":\"up\",\"required\":true},{\"types\":\"MoveUpDownType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"unitupdown\",\"title\":\"上下移动单位\",\"name\":\"unitupdown\",\"tip\":\"可选择行、段落\",\"options\":[{\"label\":\"段落\",\"value\":\"paragraph\"},{\"label\":\"行\",\"value\":\"row\"}],\"default\":\"row\",\"dynamics\":[{\"key\":\"$this.unitupdown.show\",\"expression\":\"return [\'up\', \'down\'].includes($this.direction.value)\"}],\"required\":true},{\"types\":\"MoveLeftRightType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"unitleftright\",\"title\":\"左右移动单位\",\"name\":\"unitleftright\",\"tip\":\"可选择字符、单词\",\"options\":[{\"label\":\"字符\",\"value\":\"character\"},{\"label\":\"单词\",\"value\":\"word\"}],\"default\":\"character\",\"dynamics\":[{\"key\":\"$this.unitleftright.show\",\"expression\":\"return [\'left\', \'right\'].includes($this.direction.value)\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"distance\",\"title\":\"移动距离\",\"name\":\"distance\",\"tip\":\"输入移动的距离\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"with_shift\",\"title\":\"是否按下Shift\",\"name\":\"with_shift\",\"tip\":\"选择是否按下Shift\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true}],\"outputList\":[],\"icon\":\"word-move-cursor\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(264,'document/document.Word','Docx.insert_sep','{\"key\":\"Docx.insert_sep\",\"title\":\"Word插入页/段落\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().insert_sep\",\"comment\":\"在Word文档对象 @{doc} 中插入页/段落\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"InsertionType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"sep_type\",\"title\":\"插入类型\",\"name\":\"sep_type\",\"tip\":\"选择页、段落\",\"options\":[{\"label\":\"页\",\"value\":\"page\"},{\"label\":\"段落\",\"value\":\"paragraph\"}],\"default\":\"paragraph\",\"required\":true}],\"outputList\":[],\"icon\":\"word-insert-page\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(265,'document/document.Word','Docx.insert_hyperlink','{\"key\":\"Docx.insert_hyperlink\",\"title\":\"Word插入超链接\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().insert_hyperlink\",\"comment\":\"在Word文档对象 @{doc} 中插入超链接\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"url\",\"title\":\"链接\",\"name\":\"url\",\"tip\":\"输入插入的链接\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"display\",\"title\":\"显示文本\",\"name\":\"display\",\"tip\":\"输入要显示的文本\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"word-insert-hyperlink\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(266,'document/document.Word','Docx.insert_img','{\"key\":\"Docx.insert_img\",\"title\":\"Word插入图片\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().insert_img\",\"comment\":\"在Word文档对象 @{doc} 中,从路径 @{img_path} 或剪贴板插入图片\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"InsertImgType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"img_from\",\"title\":\"图片来源\",\"name\":\"img_from\",\"tip\":\"选择通过文件路径、剪贴板\",\"options\":[{\"label\":\"文件\",\"value\":\"file\"},{\"label\":\"剪贴板\",\"value\":\"clipboard\"}],\"default\":\"file\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"img_path\",\"title\":\"文件路径\",\"name\":\"img_path\",\"tip\":\"输入文件路径\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.img_path.show\",\"expression\":\"return $this.img_from.value == \'file\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"scale\",\"title\":\"缩放比例(%)\",\"name\":\"scale\",\"tip\":\"默认为100%,可以输入其他值,不需要输入百分号\",\"default\":100,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"newline\",\"title\":\"是否换行\",\"name\":\"newline\",\"tip\":\"选择插入前是否换行\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true}],\"outputList\":[],\"icon\":\"word-insert-image\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(267,'document/document.Word','Docx.read_table','{\"key\":\"Docx.read_table\",\"title\":\"Word读取表格\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().read_table\",\"comment\":\"在Word文档对象 @{doc} 中,读取表格内容并返回表格数据对象 @{table_content}\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"SearchTableType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"search_type\",\"title\":\"查找表格方式\",\"name\":\"search_type\",\"tip\":\"选择查找表格方式\",\"options\":[{\"label\":\"文本\",\"value\":\"text\"},{\"label\":\"序号\",\"value\":\"idx\"}],\"default\":\"idx\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"idx\",\"title\":\"序号\",\"name\":\"idx\",\"tip\":\"输入查找表格的序号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"text\",\"title\":\"文本\",\"name\":\"text\",\"tip\":\"输入查找表格的文本\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.text.show\",\"expression\":\"return $this.search_type.value == \'text\'\"}],\"required\":true}],\"outputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"table_content\",\"title\":\"表格内容\",\"tip\":\"\"}],\"icon\":\"word-read-table\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(268,'document/document.Word','Docx.insert_table','{\"key\":\"Docx.insert_table\",\"title\":\"Word插入表格\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().insert_table\",\"comment\":\"在Word文档对象 @{doc} 中,插入表格内容\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"List\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"table_content\",\"title\":\"表格内容\",\"name\":\"table_content\",\"tip\":\"要创建的表格内容,格式为二维数组或者为读取的Excel表格内容\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"TableBehavior\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"table_behavior\",\"title\":\"表格大小\",\"name\":\"table_behavior\",\"tip\":\"选择默认还是适应大小\",\"options\":[{\"label\":\"默认\",\"value\":0},{\"label\":\"适应大小\",\"value\":1}],\"default\":0,\"required\":true},{\"types\":\"RowAlignment\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"alignment\",\"title\":\"文本左右位置\",\"name\":\"alignment\",\"tip\":\"选择左对齐、居中对齐、右对齐\",\"options\":[{\"label\":\"左对齐\",\"value\":0},{\"label\":\"居中对齐\",\"value\":1},{\"label\":\"右对齐\",\"value\":2}],\"default\":0,\"required\":true},{\"types\":\"VerticalAlignment\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"v_alignment\",\"title\":\"文本垂直位置\",\"name\":\"v_alignment\",\"tip\":\"选择顶部对齐、居中对齐、底部对齐\",\"options\":[{\"label\":\"顶部对齐\",\"value\":0},{\"label\":\"居中对齐\",\"value\":1},{\"label\":\"底部对齐\",\"value\":3}],\"default\":0,\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"border\",\"title\":\"表格边框\",\"name\":\"border\",\"tip\":\"选择是否有边框\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"if_change_font\",\"title\":\"是否改变字体\",\"name\":\"if_change_font\",\"tip\":\"选择是否改变字体\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"font_size\",\"title\":\"大小\",\"name\":\"font_size\",\"tip\":\"选择字体大小\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.font_size.show\",\"expression\":\"return $this.if_change_font.value == true\"}],\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_COLOR\"},\"key\":\"font_color\",\"title\":\"颜色\",\"name\":\"font_color\",\"tip\":\"选择字体颜色\",\"dynamics\":[{\"key\":\"$this.font_color.show\",\"expression\":\"return $this.if_change_font.value == true\"}],\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"font_set\",\"title\":\"字体\",\"name\":\"font_set\",\"tip\":\"选择字体\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.font_set.show\",\"expression\":\"return $this.if_change_font.value == true\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"font_bold\",\"title\":\"加粗\",\"name\":\"font_bold\",\"tip\":\"选择是否加粗\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"dynamics\":[{\"key\":\"$this.font_bold.show\",\"expression\":\"return $this.if_change_font.value == true\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"font_italic\",\"title\":\"斜体\",\"name\":\"font_italic\",\"tip\":\"选择是否斜体\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"dynamics\":[{\"key\":\"$this.font_italic.show\",\"expression\":\"return $this.if_change_font.value == true\"}],\"required\":true},{\"types\":\"UnderLineStyle\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"underline\",\"title\":\"下划线\",\"name\":\"underline\",\"tip\":\"选择是否下划线\",\"options\":[{\"label\":\"无下划线\",\"value\":0},{\"label\":\"有下划线\",\"value\":1}],\"default\":0,\"dynamics\":[{\"key\":\"$this.underline.show\",\"expression\":\"return $this.if_change_font.value == true\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"newline\",\"title\":\"在新的一行插入\",\"name\":\"newline\",\"tip\":\"选择是否在新的一行插入\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true}],\"outputList\":[],\"icon\":\"word-insert-table\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(269,'document/document.Word','Docx.delete','{\"key\":\"Docx.delete\",\"title\":\"Word删除内容\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().delete\",\"comment\":\"在Word文档对象 @{doc} 中,删除内容\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"DeleteMode\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"delete_mode\",\"title\":\"删除方式\",\"name\":\"delete_mode\",\"tip\":\"选择删除方式\",\"options\":[{\"label\":\"全部\",\"value\":\"all\"},{\"label\":\"指定文本\",\"value\":\"content\"},{\"label\":\"指定范围\",\"value\":\"range\"}],\"default\":\"all\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"delete_str\",\"title\":\"文本\",\"name\":\"delete_str\",\"tip\":\"选择要删除的文本\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.delete_str.show\",\"expression\":\"return $this.delete_mode.value == \'content\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"delete_idx\",\"title\":\"序号\",\"name\":\"delete_idx\",\"tip\":\"选择删除第几个文本\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.delete_idx.show\",\"expression\":\"return $this.str_delete_all.value == false && $this.delete_mode.value == \'content\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"str_delete_all\",\"title\":\"删除所有找到的文本\",\"name\":\"str_delete_all\",\"tip\":\"选择是否删除所有找到的文本\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"dynamics\":[{\"key\":\"$this.str_delete_all.show\",\"expression\":\"return $this.delete_mode.value == \'content\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"p_start\",\"title\":\"起始段落\",\"name\":\"p_start\",\"tip\":\"输入起始段落\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.p_start.show\",\"expression\":\"return $this.delete_mode.value == \'range\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"c_start\",\"title\":\"起始字符\",\"name\":\"c_start\",\"tip\":\"输入起始字符\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.c_start.show\",\"expression\":\"return $this.delete_mode.value == \'range\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"p_end\",\"title\":\"结束段落\",\"name\":\"p_end\",\"tip\":\"输入结束段落\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.p_end.show\",\"expression\":\"return $this.delete_mode.value == \'range\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"c_end\",\"title\":\"结束字符\",\"name\":\"c_end\",\"tip\":\"输入结束字符\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.c_end.show\",\"expression\":\"return $this.delete_mode.value == \'range\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"word-delete-content\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(270,'document/document.Word','Docx.replace','{\"key\":\"Docx.replace\",\"title\":\"Word替换内容\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().replace\",\"comment\":\"在Word文档对象 @{doc} 中,查找内容并替换\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"origin_word\",\"title\":\"查找内容\",\"name\":\"origin_word\",\"tip\":\"输入要查找的内容\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"ReplaceType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"replace_type\",\"title\":\"替换为\",\"name\":\"replace_type\",\"tip\":\"选择替换为图片或文本\",\"options\":[{\"label\":\"图片\",\"value\":\"img\"},{\"label\":\"文本\",\"value\":\"str\"}],\"default\":\"str\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"new_word\",\"title\":\"新内容\",\"name\":\"new_word\",\"tip\":\"输入要替换为的内容\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.new_word.show\",\"expression\":\"return $this.replace_type.value == \'str\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"img_path\",\"title\":\"图片路径\",\"name\":\"img_path\",\"tip\":\"选择图片路径\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.img_path.show\",\"expression\":\"return $this.replace_type.value == \'img\'\"}],\"required\":true},{\"types\":\"ReplaceMethodType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"replace_method\",\"title\":\"替换模式\",\"name\":\"replace_method\",\"tip\":\"选择替换全部、替换首个\",\"options\":[{\"label\":\"首个\",\"value\":\"first\"},{\"label\":\"全部\",\"value\":\"all\"}],\"default\":\"all\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"ignore_case\",\"title\":\"大小写忽略\",\"name\":\"ignore_case\",\"tip\":\"选择是否大小写忽略\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true}],\"outputList\":[],\"icon\":\"word-replace-content\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(271,'document/document.Word','Docx.create_comment','{\"key\":\"Docx.create_comment\",\"title\":\"Word创建批注\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().create_comment\",\"comment\":\"在Word文档对象 @{doc} 中,创建批注\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"comment\",\"title\":\"批注内容\",\"name\":\"comment\",\"tip\":\"输入批注内容\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"CommentType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"comment_type\",\"title\":\"批注对象\",\"name\":\"comment_type\",\"tip\":\"选择指定范围还是指定内容\",\"options\":[{\"label\":\"指定位置\",\"value\":\"position\"},{\"label\":\"指定内容\",\"value\":\"content\"}],\"default\":\"position\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"paragraph_idx\",\"title\":\"段落号\",\"name\":\"paragraph_idx\",\"tip\":\"输入创建批注的段落号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.paragraph_idx.show\",\"expression\":\"return $this.comment_type.value == \'position\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"start\",\"title\":\"起始字符序号\",\"name\":\"start\",\"tip\":\"输入批注的起始字符序号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.start.show\",\"expression\":\"return $this.comment_type.value == \'position\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"end\",\"title\":\"结束字符序号\",\"name\":\"end\",\"tip\":\"输入批注的结束字符序号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.end.show\",\"expression\":\"return $this.comment_type.value == \'position\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"target_str\",\"title\":\"目标内容\",\"name\":\"target_str\",\"tip\":\"输入批注的目标内容\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.target_str.show\",\"expression\":\"return $this.comment_type.value == \'content\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"comment_all\",\"title\":\"全部批注\",\"name\":\"comment_all\",\"tip\":\"选择是否全部批注\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"dynamics\":[{\"key\":\"$this.comment_all.show\",\"expression\":\"return $this.comment_type.value == \'content\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"comment_index\",\"title\":\"序号\",\"name\":\"comment_index\",\"tip\":\"选择批注内容的序号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.comment_index.show\",\"expression\":\"return $this.comment_all.value == false\"}],\"required\":true}],\"outputList\":[],\"icon\":\"word-create-comment\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(272,'document/document.Word','Docx.delete_comment','{\"key\":\"Docx.delete_comment\",\"title\":\"Word删除批注\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().delete_comment\",\"comment\":\"在Word文档对象 @{doc} 中,删除指定批注\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"delete_all\",\"title\":\"删除全部\",\"name\":\"delete_all\",\"tip\":\"选择是否删除全部批注\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"comment_index\",\"title\":\"批注序号\",\"name\":\"comment_index\",\"tip\":\"输入要删除批注的序号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.comment_index.show\",\"expression\":\"return $this.delete_all.value == false\"}],\"required\":true}],\"outputList\":[],\"icon\":\"word-delete-comment\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(273,'document/document.Word','Docx.convert_format','{\"key\":\"Docx.convert_format\",\"title\":\"Word导出为PDF/TXT\",\"version\":\"1.0.0\",\"src\":\"astronverse.word.docx.Docx().convert_format\",\"comment\":\"在Word文档对象 @{doc} 中,导出指定内容为PDF或TXT文件\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"output_path\",\"title\":\"导出路径\",\"name\":\"output_path\",\"tip\":\"选择要导出的文件夹\",\"default\":\"\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"default_name\",\"title\":\"是否使用默认名称\",\"name\":\"default_name\",\"tip\":\"选择是否使用默认名称\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"output_name\",\"title\":\"导出文件名\",\"name\":\"output_name\",\"tip\":\"输入不含格式后缀的文件名\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.output_name.show\",\"expression\":\"return $this.default_name.value == false\"}],\"required\":true},{\"types\":\"FileType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"output_file_type\",\"title\":\"导出文件格式\",\"name\":\"output_file_type\",\"tip\":\"选中导出为pdf还是txt\",\"options\":[{\"label\":\"PDF\",\"value\":\"pdf\"},{\"label\":\"TXT\",\"value\":\"txt\"}],\"default\":\"pdf\",\"required\":true},{\"types\":\"ConvertPageType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"page_type\",\"title\":\"页面范围\",\"name\":\"page_type\",\"tip\":\"选择要导出全部页面、指定页面范围、当前页面、当前选中内容\",\"options\":[{\"label\":\"全部页面\",\"value\":0},{\"label\":\"当前页面\",\"value\":2},{\"label\":\"指定页面范围\",\"value\":3},{\"label\":\"选中内容\",\"value\":1}],\"default\":0,\"dynamics\":[{\"key\":\"$this.page_type.show\",\"expression\":\"return $this.output_file_type.value == \'pdf\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page_start\",\"title\":\"起始页面\",\"name\":\"page_start\",\"tip\":\"输入导出的起始页面\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.page_start.show\",\"expression\":\"return $this.page_type.value == \'3\' && $this.output_file_type.value == \'pdf\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page_end\",\"title\":\"结束页面\",\"name\":\"page_end\",\"tip\":\"输入要导出的结束页面\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.page_end.show\",\"expression\":\"return $this.page_type.value == \'3\' && $this.output_file_type.value == \'pdf\'\"}],\"required\":true},{\"types\":\"SaveFileType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"save_type\",\"title\":\"重名保存方式\",\"name\":\"save_type\",\"tip\":\"选择存在重名文件时报错、覆盖、自动重命名\",\"options\":[{\"label\":\"重名提示\",\"value\":\"warn\"},{\"label\":\"自动生成名称\",\"value\":\"generate\"},{\"label\":\"覆盖同名文件\",\"value\":\"overwrite\"}],\"default\":\"warn\",\"required\":true}],\"outputList\":[],\"icon\":\"word-export-pdf-txt\",\"helpManual\":\"\"}',0,'1','2025-10-11 14:12:21',1,'2025-10-11 14:12:21','1.0.0',NULL,'1000000'),(274,'','Docx.open_document','{\"key\":\"Docx.open_document\",\"title\":\"打开Word\",\"version\":\"1.0.3\",\"src\":\"astronverse.word.docx.Docx().open_document\",\"comment\":\"打开路径为 @{file_path} 的Word文档,返回Word对象 @{doc_obj}\",\"inputList\":[{\"types\":\"PATH\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"file\"}},\"key\":\"file_path\",\"title\":\"文档路径\",\"name\":\"file_path\",\"tip\":\"填写Word文档的路径\",\"default\":\"\",\"required\":true},{\"types\":\"ApplicationType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"default_application\",\"title\":\"驱动方式\",\"name\":\"default_application\",\"tip\":\"选择Word文档的打开方式,如Word或WPS\",\"options\":[{\"label\":\"Word\",\"value\":\"Word\"},{\"label\":\"WPS\",\"value\":\"WPS\"},{\"label\":\"默认软件\",\"value\":\"Default\"}],\"default\":\"Default\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"visible_flag\",\"title\":\"是否可见\",\"name\":\"visible_flag\",\"tip\":\"是否显示Word文档窗口\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"EncodingType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"encoding\",\"title\":\"编码模式\",\"name\":\"encoding\",\"tip\":\"选择文档的编码模式,如UTF-8或GBK\",\"options\":[{\"label\":\"utf-8\",\"value\":\"utf-8\"},{\"label\":\"gbk\",\"value\":\"gbk\"}],\"default\":\"utf-8\",\"level\":\"advanced\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"open_pwd_flag\",\"title\":\"是否填写Word打开密码\",\"name\":\"open_pwd_flag\",\"tip\":\"选择是否需要输入密码打开文档\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"level\":\"advanced\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"open_pwd\",\"title\":\"Word打开密码\",\"name\":\"open_pwd\",\"tip\":\"输入Word打开密码\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"dynamics\":[{\"key\":\"$this.open_pwd.show\",\"expression\":\"return $this.open_pwd_flag.value == true\"}],\"required\":false},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"write_pwd_flag\",\"title\":\"是否填写Word写入密码\",\"name\":\"write_pwd_flag\",\"tip\":\"选择是否需要输入密码写入文档\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"level\":\"advanced\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"write_pwd\",\"title\":\"Word写入密码\",\"name\":\"write_pwd\",\"tip\":\"输入Word写入密码\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.write_pwd.show\",\"expression\":\"return $this.write_pwd_flag.value == true\"}],\"required\":false}],\"outputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"doc_obj\",\"title\":\"Word对象\",\"tip\":\"返回Word对象,用于后续操作\"}],\"icon\":\"open-atom\",\"helpManual\":\"\"}',0,'1','2025-10-14 08:41:00',1,'2025-10-14 08:41:00','1.0.3',NULL,'1000003'),(275,'','Docx.read_document_content','{\"key\":\"Docx.read_document_content\",\"title\":\"读取Word内容\",\"version\":\"1.0.2\",\"src\":\"astronverse.word.docx.Docx().read_document_content\",\"comment\":\"读取Word文档对象 @{doc} 内容,返回文档内容 @{doc_data}\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"SelectRangeType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"select_range\",\"title\":\"读取范围\",\"name\":\"select_range\",\"tip\":\"选择读取文档的范围,如整个文档或选中区域\",\"options\":[{\"label\":\"整个文档\",\"value\":\"all\"},{\"label\":\"选中区域\",\"value\":\"selected\"}],\"default\":\"all\",\"required\":true}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"doc_data\",\"title\":\"文档内容\",\"tip\":\"\"}],\"icon\":\"icon-list-read-word\",\"helpManual\":\"\"}',0,'1','2025-10-14 08:41:00',1,'2025-10-14 08:41:00','1.0.2',NULL,'1000002'),(276,'document/document.Word','Docx.delete','{\"key\":\"Docx.delete\",\"title\":\"Word删除内容\",\"version\":\"1.0.1\",\"src\":\"astronverse.word.docx.Docx().delete\",\"comment\":\"在Word文档对象 @{doc} 中,删除内容\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"DeleteMode\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"delete_mode\",\"title\":\"删除方式\",\"name\":\"delete_mode\",\"tip\":\"选择删除方式\",\"options\":[{\"label\":\"全部\",\"value\":\"all\"},{\"label\":\"指定文本\",\"value\":\"content\"},{\"label\":\"指定范围\",\"value\":\"range\"}],\"default\":\"all\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"delete_str\",\"title\":\"文本\",\"name\":\"delete_str\",\"tip\":\"选择要删除的文本\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.delete_str.show\",\"expression\":\"return $this.delete_mode.value == \'content\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"delete_idx\",\"title\":\"序号\",\"name\":\"delete_idx\",\"tip\":\"选择删除第几个文本\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.delete_idx.show\",\"expression\":\"return $this.str_delete_all.value == False && $this.delete_mode.value == \'content\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"str_delete_all\",\"title\":\"删除所有找到的文本\",\"name\":\"str_delete_all\",\"tip\":\"选择是否删除所有找到的文本\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"dynamics\":[{\"key\":\"$this.str_delete_all.show\",\"expression\":\"return $this.delete_mode.value == \'content\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"p_start\",\"title\":\"起始段落\",\"name\":\"p_start\",\"tip\":\"输入起始段落\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.p_start.show\",\"expression\":\"return $this.delete_mode.value == \'range\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"c_start\",\"title\":\"起始字符\",\"name\":\"c_start\",\"tip\":\"输入起始字符\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.c_start.show\",\"expression\":\"return $this.delete_mode.value == \'range\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"p_end\",\"title\":\"结束段落\",\"name\":\"p_end\",\"tip\":\"输入结束段落\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.p_end.show\",\"expression\":\"return $this.delete_mode.value == \'range\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"c_end\",\"title\":\"结束字符\",\"name\":\"c_end\",\"tip\":\"输入结束字符\",\"default\":0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.c_end.show\",\"expression\":\"return $this.delete_mode.value == \'range\'\"}],\"required\":true}],\"outputList\":[],\"icon\":\"word-delete-content\",\"helpManual\":\"\"}',0,'1','2025-10-14 08:41:00',1,'2025-10-14 08:41:00','1.0.1',NULL,'1000001'),(277,'document/document.Word','Docx.create_comment','{\"key\":\"Docx.create_comment\",\"title\":\"Word创建批注\",\"version\":\"1.0.1\",\"src\":\"astronverse.word.docx.Docx().create_comment\",\"comment\":\"在Word文档对象 @{doc} 中,创建批注\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"comment\",\"title\":\"批注内容\",\"name\":\"comment\",\"tip\":\"输入批注内容\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"CommentType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"comment_type\",\"title\":\"批注对象\",\"name\":\"comment_type\",\"tip\":\"选择指定范围还是指定内容\",\"options\":[{\"label\":\"指定位置\",\"value\":\"position\"},{\"label\":\"指定内容\",\"value\":\"content\"}],\"default\":\"position\",\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"paragraph_idx\",\"title\":\"段落号\",\"name\":\"paragraph_idx\",\"tip\":\"输入创建批注的段落号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.paragraph_idx.show\",\"expression\":\"return $this.comment_type.value == \'position\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"start\",\"title\":\"起始字符序号\",\"name\":\"start\",\"tip\":\"输入批注的起始字符序号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.start.show\",\"expression\":\"return $this.comment_type.value == \'position\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"end\",\"title\":\"结束字符序号\",\"name\":\"end\",\"tip\":\"输入批注的结束字符序号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.end.show\",\"expression\":\"return $this.comment_type.value == \'position\'\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"target_str\",\"title\":\"目标内容\",\"name\":\"target_str\",\"tip\":\"输入批注的目标内容\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.target_str.show\",\"expression\":\"return $this.comment_type.value == \'content\'\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"comment_all\",\"title\":\"全部批注\",\"name\":\"comment_all\",\"tip\":\"选择是否全部批注\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"dynamics\":[{\"key\":\"$this.comment_all.show\",\"expression\":\"return $this.comment_type.value == \'content\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"comment_index\",\"title\":\"序号\",\"name\":\"comment_index\",\"tip\":\"选择批注内容的序号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.comment_index.show\",\"expression\":\"return $this.comment_all.value == False\"}],\"required\":true}],\"outputList\":[],\"icon\":\"word-create-comment\",\"helpManual\":\"\"}',0,'1','2025-10-14 08:41:00',1,'2025-10-14 08:41:00','1.0.1',NULL,'1000001'),(278,'document/document.Word','Docx.delete_comment','{\"key\":\"Docx.delete_comment\",\"title\":\"Word删除批注\",\"version\":\"1.0.1\",\"src\":\"astronverse.word.docx.Docx().delete_comment\",\"comment\":\"在Word文档对象 @{doc} 中,删除指定批注\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"delete_all\",\"title\":\"删除全部\",\"name\":\"delete_all\",\"tip\":\"选择是否删除全部批注\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":false,\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"comment_index\",\"title\":\"批注序号\",\"name\":\"comment_index\",\"tip\":\"输入要删除批注的序号\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.comment_index.show\",\"expression\":\"return $this.delete_all.value == False\"}],\"required\":true}],\"outputList\":[],\"icon\":\"word-delete-comment\",\"helpManual\":\"\"}',0,'1','2025-10-14 08:41:00',1,'2025-10-14 08:41:00','1.0.1',NULL,'1000001'),(279,'document/document.Word','Docx.convert_format','{\"key\":\"Docx.convert_format\",\"title\":\"Word导出为PDF/TXT\",\"version\":\"1.0.1\",\"src\":\"astronverse.word.docx.Docx().convert_format\",\"comment\":\"在Word文档对象 @{doc} 中,导出指定内容为PDF或TXT文件\",\"inputList\":[{\"types\":\"DocumentObject\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"doc\",\"title\":\"Word对象\",\"name\":\"doc\",\"tip\":\"本软件前序原子能力(如打开、新建)返回的Word对象\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[],\"file_type\":\"folder\"}},\"key\":\"output_path\",\"title\":\"导出路径\",\"name\":\"output_path\",\"tip\":\"选择要导出的文件夹\",\"default\":\"\",\"required\":true},{\"types\":\"Bool\",\"formType\":{\"type\":\"SWITCH\",\"params\":{}},\"key\":\"default_name\",\"title\":\"是否使用默认名称\",\"name\":\"default_name\",\"tip\":\"选择是否使用默认名称\",\"options\":[{\"label\":\"是\",\"value\":true},{\"label\":\"否\",\"value\":false}],\"default\":true,\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"output_name\",\"title\":\"导出文件名\",\"name\":\"output_name\",\"tip\":\"输入不含格式后缀的文件名\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.output_name.show\",\"expression\":\"return $this.default_name.value == False\"}],\"required\":true},{\"types\":\"FileType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"output_file_type\",\"title\":\"导出文件格式\",\"name\":\"output_file_type\",\"tip\":\"选中导出为pdf还是txt\",\"options\":[{\"label\":\"PDF\",\"value\":\"pdf\"},{\"label\":\"TXT\",\"value\":\"txt\"}],\"default\":\"pdf\",\"required\":true},{\"types\":\"ConvertPageType\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"page_type\",\"title\":\"页面范围\",\"name\":\"page_type\",\"tip\":\"选择要导出全部页面、指定页面范围、当前页面、当前选中内容\",\"options\":[{\"label\":\"全部页面\",\"value\":0},{\"label\":\"当前页面\",\"value\":2},{\"label\":\"指定页面范围\",\"value\":3},{\"label\":\"选中内容\",\"value\":1}],\"default\":0,\"dynamics\":[{\"key\":\"$this.page_type.show\",\"expression\":\"return $this.output_file_type.value == \'pdf\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page_start\",\"title\":\"起始页面\",\"name\":\"page_start\",\"tip\":\"输入导出的起始页面\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.page_start.show\",\"expression\":\"return $this.page_type.value == \'3\' && $this.output_file_type.value == \'pdf\'\"}],\"required\":true},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"page_end\",\"title\":\"结束页面\",\"name\":\"page_end\",\"tip\":\"输入要导出的结束页面\",\"default\":1,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"dynamics\":[{\"key\":\"$this.page_end.show\",\"expression\":\"return $this.page_type.value == \'3\' && $this.output_file_type.value == \'pdf\'\"}],\"required\":true},{\"types\":\"SaveFileType\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"save_type\",\"title\":\"重名保存方式\",\"name\":\"save_type\",\"tip\":\"选择存在重名文件时报错、覆盖、自动重命名\",\"options\":[{\"label\":\"重名提示\",\"value\":\"warn\"},{\"label\":\"自动生成名称\",\"value\":\"generate\"},{\"label\":\"覆盖同名文件\",\"value\":\"overwrite\"}],\"default\":\"warn\",\"required\":true}],\"outputList\":[],\"icon\":\"word-export-pdf-txt\",\"helpManual\":\"\"}',0,'1','2025-10-14 08:41:00',1,'2025-10-14 08:41:00','1.0.1',NULL,'1000001'),(280,'','Code.ElseIfEnd','{\"key\":\"Code.ElseIfEnd\",\"title\":\"判断结束\",\"version\":\"1\",\"comment\":\"判断结束\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(281,'','Code.ForDictEnd','{\"key\":\"Code.ForDictEnd\",\"title\":\"字典For循环结束\",\"version\":\"1\",\"comment\":\"字典For循环结束\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(282,'code/error','Code.Try','{\"key\":\"Code.Try\",\"title\":\"捕获异常(Try)\",\"version\":\"1\",\"comment\":\"可能发生异常的try流程,发生异常后执行catch流程,最终执行finally流程\",\"icon\":\"try-exception\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(283,'','Code.GroupEnd','{\"key\":\"Code.GroupEnd\",\"title\":\"编组结束\",\"version\":\"1\",\"comment\":\"编组结束\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(284,'','Code.ElseEnd','{\"key\":\"Code.ElseEnd\",\"title\":\"判断结束\",\"version\":\"1\",\"comment\":\"判断结束\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(285,'code/for','Code.ForDict','{\"key\":\"Code.ForDict\",\"title\":\"字典For循环\",\"version\":\"1\",\"comment\":\"用key值(@{key})和value值(@{value})遍历字典,进行循环操作,输出循环项键名至(@{key}), 输出循环项键值至(@{value})\",\"inputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"dicts\",\"title\":\"字典对象\",\"name\":\"dicts\",\"tip\":\"循环中遍历的字典,可自行创建或选择前面组件创建的字典\",\"default\":\"\"}],\"outputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"key\",\"title\":\"循环项位置\",\"tip\":\"循环项位置\",\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"value\",\"title\":\"循环项\",\"tip\":\"循环项\",\"required\":true}],\"icon\":\"dictionary-for-loop\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(286,'','Code.CatchEnd','{\"key\":\"Code.CatchEnd\",\"title\":\"捕获结束\",\"version\":\"1\",\"comment\":\"捕获结束\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(287,'code/for','Code.While','{\"key\":\"Code.While\",\"title\":\"While循环\",\"version\":\"1.0.2\",\"comment\":\"如果(@{args1})(@{condition})(@{args2}),则执行以下操作\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"args1\",\"title\":\"对象1\",\"name\":\"args1\",\"default\":\"\"},{\"types\":\"Str\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"condition\",\"title\":\"关系\",\"name\":\"condition\",\"options\":[{\"label\":\"等于\",\"value\":\"==\"},{\"label\":\"不等于\",\"value\":\"!=\"},{\"label\":\"大于\",\"value\":\">\"},{\"label\":\"大于等于\",\"value\":\">=\"},{\"label\":\"小于\",\"value\":\"<\"},{\"label\":\"小于等于\",\"value\":\"<=\"},{\"label\":\"包含\",\"value\":\"in\"},{\"label\":\"不包含\",\"value\":\"notin\"},{\"label\":\"为真\",\"value\":\"true\"},{\"label\":\"为假\",\"value\":\"false\"},{\"label\":\"为空\",\"value\":\"empty\"},{\"label\":\"不为空\",\"value\":\"notempty\"}],\"default\":\"==\"},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"args2\",\"title\":\"对象2\",\"name\":\"args2\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.args2.show\",\"expression\":\"return [\'==\', \'!=\', \'>\', \'>=\', \'<\', \'<=\', \'in\', \'notin\'].includes($this.condition.value)\"}]}],\"icon\":\"while-loop\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1.0.2',NULL,'1000002'),(288,'code/if','Code.ElseIf','{\"key\":\"Code.ElseIf\",\"title\":\"ELSE IF条件\",\"version\":\"1.0.1\",\"comment\":\"如果(@{args1})(@{condition})(@{args2}),则执行以下操作\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"args1\",\"title\":\"对象1\",\"name\":\"args1\",\"default\":\"\"},{\"types\":\"Str\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"condition\",\"title\":\"关系\",\"name\":\"condition\",\"options\":[{\"label\":\"等于\",\"value\":\"==\"},{\"label\":\"不等于\",\"value\":\"!=\"},{\"label\":\"大于\",\"value\":\">\"},{\"label\":\"大于等于\",\"value\":\">=\"},{\"label\":\"小于\",\"value\":\"<\"},{\"label\":\"小于等于\",\"value\":\"<=\"},{\"label\":\"包含\",\"value\":\"in\"},{\"label\":\"不包含\",\"value\":\"notin\"},{\"label\":\"为真\",\"value\":\"true\"},{\"label\":\"为假\",\"value\":\"false\"},{\"label\":\"为空\",\"value\":\"empty\"},{\"label\":\"不为空\",\"value\":\"notempty\"}],\"default\":\"==\"},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"args2\",\"title\":\"对象2\",\"name\":\"args2\",\"default\":\"\"}],\"icon\":\"else-if-condition\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1.0.1',NULL,'1000001'),(289,'process','Code.Process','{\"key\":\"Code.Process\",\"title\":\"运行子流程\",\"version\":\"1\",\"comment\":\"运行子流程(@{process:子流程})\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"SELECT\",\"params\":{\"filters\":[\"Process\"]}},\"key\":\"process\",\"title\":\"选择子流程\",\"name\":\"process\",\"tip\":\"选择要运行的子流程\",\"required\":true,\"default\":\"\"},{\"types\":\"Any\",\"formType\":{\"type\":\"PROCESSPARAM\",\"params\":{\"linkage\":\"process\"}},\"key\":\"process_param\",\"title\":\"输入参数\",\"name\":\"process_param\",\"tip\":\"\",\"need_parse\":\"str\",\"default\":\"\"}],\"outputList\":[{\"types\":\"Dict\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"process_res\",\"title\":\"保存流程输出结果至\",\"tip\":\"\"}],\"icon\":\"run-sub-process\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(290,'','Code.ForEnd','{\"key\":\"Code.ForEnd\",\"title\":\"循环结束\",\"version\":\"1\",\"comment\":\"循环结束\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(291,'','Code.TryEnd','{\"key\":\"Code.TryEnd\",\"title\":\"捕获结束\",\"version\":\"1\",\"comment\":\"捕获结束\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(292,'','Code.ForStepEnd','{\"key\":\"Code.ForStepEnd\",\"title\":\"计数For循环结束\",\"version\":\"1\",\"comment\":\"计数For循环结束\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(293,'','Code.IfEnd','{\"key\":\"Code.IfEnd\",\"title\":\"判断结束\",\"version\":\"1\",\"comment\":\"判断结束\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(294,'code/for','Code.Continue','{\"key\":\"Code.Continue\",\"title\":\"继续下次循环(Continue)\",\"version\":\"1\",\"comment\":\"继续下一次循环\",\"icon\":\"continue-next-loop\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(295,'','Code.Group','{\"key\":\"Code.Group\",\"title\":\"编组开始\",\"version\":\"1\",\"comment\":\"编组开始\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(296,'','Code.FinallyEnd','{\"key\":\"Code.FinallyEnd\",\"title\":\"捕获结束\",\"version\":\"1\",\"comment\":\"捕获结束\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(297,'','Code.Catch','{\"key\":\"Code.Catch\",\"title\":\"捕获异常(Catch)\",\"version\":\"1\",\"icon\":\"catch-exception\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(298,'','Code.WhileEnd','{\"key\":\"Code.WhileEnd\",\"title\":\"循环结束\",\"version\":\"1\",\"comment\":\"循环结束\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(299,'code/for','Code.ForList','{\"key\":\"Code.ForList\",\"title\":\"列表For循环\",\"version\":\"1\",\"comment\":\"在列表(@{list})中通过循环变量(@{item})遍历列表,进行循环操作,输出列表循环至(@{item}), 输出循环项位置为(@{index})\",\"inputList\":[{\"types\":\"List\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"list\",\"title\":\"列表对象\",\"name\":\"list\",\"tip\":\"循环中遍历的列表,可自行创建或引用前面组件已创建的列表\",\"default\":\"\"}],\"outputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"index\",\"title\":\"循环项位置\",\"tip\":\"默认变量可修改,用于遍历列表的变量索引数值\",\"required\":true},{\"types\":\"Any\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"item\",\"title\":\"循环项\",\"tip\":\"默认变量可修改,用于遍历列表的变量\",\"required\":true}],\"icon\":\"list-for-loop\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(300,'code/error','Code.Finally','{\"key\":\"Code.Finally\",\"title\":\"捕获异常(Finally)\",\"version\":\"1\",\"icon\":\"finally-exception\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(301,'code/for','Code.ForStep','{\"key\":\"Code.ForStep\",\"title\":\"计数For循环\",\"version\":\"1\",\"comment\":\"从(@{start})开始到(@{end})结束,递增值为(@{step:1}),执行循环内操作,输出循环项列表至(@{index})\",\"inputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"start\",\"title\":\"起始值\",\"name\":\"start\",\"tip\":\"循环从该值开始\",\"default\":\"\"},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"end\",\"title\":\"结束值\",\"name\":\"end\",\"tip\":\"循环至该值结束\",\"default\":\"\"},{\"types\":\"Int\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"step\",\"title\":\"步长\",\"name\":\"step\",\"tip\":\"循环一次后的增加值\",\"default\":1}],\"outputList\":[{\"types\":\"Int\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"index\",\"title\":\"循环项索引\",\"tip\":\"用于计数且可修改,随着循环进行而增加的数值结果\",\"required\":true}],\"icon\":\"count-for-loop\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(302,'code/for','Code.Break','{\"key\":\"Code.Break\",\"title\":\"退出循环(Break)\",\"version\":\"1\",\"comment\":\"退出该次循环\",\"icon\":\"break-loop\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(303,'code/if','Code.If','{\"key\":\"Code.If\",\"title\":\"IF条件\",\"version\":\"1.0.2\",\"comment\":\"如果(@{args1})(@{condition})(@{args2}),则执行以下操作\",\"inputList\":[{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"args1\",\"title\":\"对象1\",\"name\":\"args1\",\"default\":\"\"},{\"types\":\"Str\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"condition\",\"title\":\"关系\",\"name\":\"condition\",\"options\":[{\"label\":\"等于\",\"value\":\"==\"},{\"label\":\"不等于\",\"value\":\"!=\"},{\"label\":\"大于\",\"value\":\">\"},{\"label\":\"大于等于\",\"value\":\">=\"},{\"label\":\"小于\",\"value\":\"<\"},{\"label\":\"小于等于\",\"value\":\"<=\"},{\"label\":\"包含\",\"value\":\"in\"},{\"label\":\"不包含\",\"value\":\"notin\"},{\"label\":\"为真\",\"value\":\"true\"},{\"label\":\"为假\",\"value\":\"false\"},{\"label\":\"为空\",\"value\":\"empty\"},{\"label\":\"不为空\",\"value\":\"notempty\"}],\"default\":\"==\"},{\"types\":\"Any\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"args2\",\"title\":\"对象2\",\"name\":\"args2\",\"default\":\"\",\"dynamics\":[{\"key\":\"$this.args2.show\",\"expression\":\"return [\'==\', \'!=\', \'>\', \'>=\', \'<\', \'<=\', \'in\', \'notin\'].includes($this.condition.value)\"}]}],\"icon\":\"if-condition\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1.0.2',NULL,'1000002'),(304,'code/if','Code.Else','{\"key\":\"Code.Else\",\"title\":\"Else条件\",\"version\":\"1\",\"comment\":\"Else条件\",\"icon\":\"else-condition\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(305,'','Code.ForListEnd','{\"key\":\"Code.ForListEnd\",\"title\":\"列表For循环结束\",\"version\":\"1\",\"comment\":\"列表For循环结束\",\"helpManual\":\"\",\"noAdvanced\":true}',0,'1','2025-10-14 08:56:48',1,'2025-10-14 08:56:48','1',NULL,'1000000'),(306,'web','BrowserElement.slider_hover','{\"key\":\"BrowserElement.slider_hover\",\"title\":\"拾取滑块拖拽(web)\",\"version\":\"1.0.1\",\"src\":\"astronverse.browser.browser_element.BrowserElement().slider_hover\",\"comment\":\"将滑块 @{element_slider} 从 @{drag_type} 向 @{drag_direction} 拖拽 @{percent_value} %\",\"inputList\":[{\"types\":\"Browser\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"browser_obj\",\"title\":\"浏览器对象\",\"name\":\"browser_obj\",\"tip\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"slider_element\",\"title\":\"拾取滑块\",\"name\":\"slider_element\",\"tip\":\"\",\"required\":true,\"noInput\":true},{\"types\":\"WebPick\",\"formType\":{\"type\":\"PICK\",\"params\":{\"use\":\"WebPick\"}},\"key\":\"progress_element\",\"title\":\"拾取轨道\",\"name\":\"progress_element\",\"tip\":\"\",\"required\":true,\"noInput\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"percent_value\",\"title\":\"滑块移动比例\",\"name\":\"percent_value\",\"tip\":\"\",\"default\":0.0,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true},{\"types\":\"ElementDragDirectionTypeFlag\",\"formType\":{\"type\":\"SELECT\"},\"key\":\"drag_direction\",\"title\":\"拖拽方向\",\"name\":\"drag_direction\",\"tip\":\"\",\"options\":[{\"label\":\"左\",\"value\":\"left\"},{\"label\":\"右\",\"value\":\"right\"},{\"label\":\"上\",\"value\":\"up\"},{\"label\":\"下\",\"value\":\"down\"}],\"default\":\"left\",\"required\":true},{\"types\":\"ElementDragTypeFlag\",\"formType\":{\"type\":\"RADIO\"},\"key\":\"drag_type\",\"title\":\"拖拽类型\",\"name\":\"drag_type\",\"tip\":\"\",\"options\":[{\"label\":\"起始位置\",\"value\":\"start\"},{\"label\":\"当前位置\",\"value\":\"current\"}],\"default\":\"start\",\"required\":true},{\"types\":\"Float\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"duration\",\"title\":\"拖动的持续时间\",\"name\":\"duration\",\"tip\":\"\",\"default\":0.25,\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"required\":true}],\"outputList\":[],\"icon\":\"pick-slider-drag-web\",\"helpManual\":\"\"}',0,'1','2025-10-14 09:05:51',1,'2025-10-14 09:05:51','1.0.1',NULL,'1000001'),(307,'desktop','Software.open','{\"key\":\"Software.open\",\"title\":\"打开程序\",\"version\":\"1.0.1\",\"src\":\"astronverse.software.software.Software().open\",\"comment\":\"打开应用程序路径(@{app_absolute_path}),并设置运行参数为(@{app_arguments}),将结果输出为(@{software_open})\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[]}},\"key\":\"app_absolute_path\",\"title\":\"应用程序路径\",\"name\":\"app_absolute_path\",\"tip\":\"输入需要打开的应用程序文件路径\",\"default\":\"\",\"required\":true},{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON\"},\"key\":\"app_arguments\",\"title\":\"运行参数\",\"name\":\"app_arguments\",\"tip\":\"用于部分程序依赖的运行参数,例:程序环境变量\",\"default\":\"\",\"value\":[{\"type\":\"str\",\"value\":\"\"}],\"level\":\"advanced\",\"required\":false}],\"outputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"RESULT\"},\"key\":\"software_open\",\"title\":\"应用程序路径\",\"tip\":\"输出该被打开的应用程序路径\"}],\"icon\":\"open-program\",\"helpManual\":\"\"}',0,'1','2025-10-14 09:14:46',1,'2025-10-14 09:14:46','1.0.1',NULL,'1000001'),(308,'desktop','Software.close','{\"key\":\"Software.close\",\"title\":\"关闭程序\",\"version\":\"1.0.1\",\"src\":\"astronverse.software.software.Software().close\",\"comment\":\"关闭应用程序路径为(@{app_absolute_path})的程序\",\"inputList\":[{\"types\":\"Str\",\"formType\":{\"type\":\"INPUT_VARIABLE_PYTHON_FILE\",\"params\":{\"filters\":[]}},\"key\":\"app_absolute_path\",\"title\":\"应用程序路径\",\"name\":\"app_absolute_path\",\"tip\":\"需要被关闭的应用程序路径\",\"required\":true}],\"outputList\":[],\"icon\":\"close-program\",\"helpManual\":\"\"}',0,'1','2025-10-14 09:14:46',1,'2025-10-14 09:14:46','1.0.1',NULL,'1000001'); diff --git a/docker/astronAgent/astronRPA/volumes/mysql/init_his_data_enum_data.sql b/docker/astronAgent/astronRPA/volumes/mysql/init_his_data_enum_data.sql new file mode 100644 index 0000000000000000000000000000000000000000..fc473e311e2fae4a592408b8ab23fec2b396c557 --- /dev/null +++ b/docker/astronAgent/astronRPA/volumes/mysql/init_his_data_enum_data.sql @@ -0,0 +1,28 @@ +INSERT INTO rpa.his_data_enum (parent_code,icon,field,text,num,unit,percent,tip,`order`) VALUES + ('sourceData','icon-usercount','userNum','用户数量',NULL,'个',NULL,'企业中注册的用户总数(不包括禁用状态下的用户)',0), + ('sourceData','icon-chanpin','terminal','终端数量',NULL,'个',NULL,'企业中总的终端数量',1), + ('sourceData','icon-jiqiren','robotNum','机器人数量',NULL,'个',NULL,'企业中所有已发版的机器人',2), + ('executeData','icon-zhenshikexin','executeSuccess','执行成功次数',NULL,'次',NULL,'企业中所有的机器人执行成功的总次数',0), + ('executeData','icon-zhanbi','executeSuccessRate','执行成功率',NULL,'%',NULL,'执行成功率=成功次数/(成功次数+失败次数+中止次数)',1), + ('executeData','icon-shijian','executeTimeTotalHour','累计执行时长',NULL,'小时',NULL,'机器人成功执行的总时长(不包括正在执行、失败、中止的时长)',2), + ('executeData','icon-renyuan','laborSaveHour','累计节省人力',NULL,'人/天',NULL,'成功执行时长(小时)/8(小时)8倍人的效率',3), + ('robotExecuteToday','icon-todaycount','executeTotal','今日执行次数',NULL,NULL,NULL,'今日执行次数',0), + ('robotExecuteToday','icon-running','executeRunning','今日正在执行',NULL,NULL,'占比{executeRunningRate}%','今日正在执行',1), + ('robotExecuteToday','icon-zhenshikexin','executeSuccess','今日执行成功',NULL,NULL,'占比{executeSuccessRate}%','今日执行成功',2), + ('robotExecuteToday','icon-shibai','executeFail','今日执行失败',NULL,NULL,'占比{executeFailRate}%','今日执行失败',3), + ('robotExecuteToday','icon-zanting','executeAbort','今日执行中止',NULL,NULL,'占比{executeAbortRate}%','今日执行中止',4), + ('terminalRealTime','icon-chanpin','TerminalTotal','终端总数',NULL,NULL,NULL,'总的终端数量',0), + ('terminalRealTime','icon-manglu','busyNum','忙碌数',NULL,NULL,NULL,'正在执行的终端数量',1), + ('terminalRealTime','icon-kongxian','freeNum','空闲数',NULL,NULL,NULL,'已经连接未执行的终端数量',2), + ('terminalRealTime','icon-lixian','offlineNum','离线数',NULL,NULL,NULL,'未连接的终端数量',3), + ('terminalDataOverview','icon-shijian','terminalTimeHour','执行时长',NULL,'h',NULL,'成功执行的时长',0), + ('terminalDataOverview','icon-zhenshikexin','terminalNum','执行成功次数',NULL,NULL,NULL,'成功执行的次数',1), + ('robotOverview','icon-todaycount','executeTotal','累计执行次数',NULL,NULL,NULL,'累计执行次数',0), + ('robotOverview','icon-zhenshikexin','executeSuccess','累计成功次数',NULL,'次','占比{executeSuccessRate}%','累计成功次数',1), + ('robotOverview','icon-shibai','executeFail','累计失败次数',NULL,'次','占比{executeFailRate}%','累计失败次数',2), + ('robotOverview','icon-zanting','executeAbort','累计中止次数',NULL,'次','占比{executeAbortRate}%','累计中止次数',3), + ('robotExecutionData','icon-todaycount','executeTotal','执行次数',NULL,NULL,NULL,'执行次数',0), + ('robotExecutionData','icon-shijian','executeTimeHour','执行时长',NULL,'小时',NULL,'执行时长(不包括正在执行、失败、中止的时长)',1), + ('robotExecutionData','icon-zhenshikexin','executeSuccess','执行成功',NULL,NULL,'占比{executeSuccessRate}%','执行成功次数',2), + ('robotExecutionData','icon-shibai','executeFail','执行失败',NULL,NULL,'占比{executeFailRate}%','执行失败次数',3), + ('robotExecutionData','icon-zanting','executeAbort','执行中止',NULL,NULL,'占比{executeAbortRate}%','执行中止次数',4); \ No newline at end of file diff --git a/docker/astronAgent/astronRPA/volumes/mysql/init_robot_example_data.sql b/docker/astronAgent/astronRPA/volumes/mysql/init_robot_example_data.sql new file mode 100644 index 0000000000000000000000000000000000000000..c3903efacecfd99e9ca28b9614ec3c20bf3d0d91 --- /dev/null +++ b/docker/astronAgent/astronRPA/volumes/mysql/init_robot_example_data.sql @@ -0,0 +1,14 @@ +-- user id from casdoor.user +SET @user_id = (SELECT id FROM casdoor.user WHERE name = 'example-user'); + +-- ---------------------------- +-- Records of robot_design +-- ---------------------------- +INSERT INTO rpa.robot_design (id, robot_id, name, creator_id, create_time, updater_id, update_time, deleted, tenant_id, app_id, app_version, market_id, resource_status, data_source, transform_status, edit_enable) VALUES (3483, '1978748427445473280', '示例机器人', @user_id, '2025-10-16 09:02:43', @user_id, '2025-10-16 09:03:14', 0, 'example-org', null, null, null, null, 'create', 'editing', '1'); + +-- ---------------------------- +-- Records of c_process +-- ---------------------------- +INSERT INTO rpa.c_process (id, project_id, process_id, process_content, process_name, deleted, creator_id, create_time, updater_id, update_time, robot_id, robot_version) VALUES (3571, null, '1978748427479027712', '[{"key":"Report.print","version":"1.0.0","id":"bh748620057231429","alias":"日志打印","inputList":[{"key":"report_type","value":"info"},{"key":"msg","value":[{"type":"other","value":"Hello world"}]}],"outputList":[],"advanced":[{"key":"__delay_before__","value":[{"type":"other","value":0}]},{"key":"__delay_after__","value":[{"type":"other","value":0}]}],"exception":[{"key":"__skip_err__","value":"exit"},{"key":"__retry_time__","value":[{"type":"other","value":0}],"show":false},{"key":"__retry_interval__","value":[{"type":"other","value":0}],"show":false}]}]', '主流程', 0, @user_id, '2025-10-16 09:02:43', @user_id, '2025-10-16 09:03:15', '1978748427445473280', 0); + + diff --git a/docker/astronAgent/astronRPA/volumes/mysql/my.cnf b/docker/astronAgent/astronRPA/volumes/mysql/my.cnf new file mode 100644 index 0000000000000000000000000000000000000000..f0288f8ccbefe78c99549ed5e92f21e8eca11e41 --- /dev/null +++ b/docker/astronAgent/astronRPA/volumes/mysql/my.cnf @@ -0,0 +1,8 @@ +[client] +default-character-set=utf8mb4 +[mysql] +default-character-set=utf8mb4 +[mysqld] +init_connect='SET NAMES utf8mb4 COLLATE utf8mb4_general_ci' +character-set-server=utf8mb4 +collation-server=utf8mb4_general_ci \ No newline at end of file diff --git a/docker/astronAgent/astronRPA/volumes/mysql/schema.sql b/docker/astronAgent/astronRPA/volumes/mysql/schema.sql new file mode 100644 index 0000000000000000000000000000000000000000..fabe4f6a9e8e87d0195dd1b1028e2849053a263b --- /dev/null +++ b/docker/astronAgent/astronRPA/volumes/mysql/schema.sql @@ -0,0 +1,1343 @@ +-- global +SET GLOBAL character_set_client = utf8mb4; +SET GLOBAL character_set_connection = utf8mb4; +SET GLOBAL character_set_results = utf8mb4; +SET GLOBAL collation_connection = utf8mb4_general_ci; + +-- casdoor database init + +CREATE DATABASE IF NOT EXISTS casdoor COLLATE utf8mb4_general_ci; + +-- rpa database init + +CREATE DATABASE IF NOT EXISTS rpa COLLATE utf8mb4_general_ci; + +USE rpa; +-- rpa.alarm_rule definition + +CREATE TABLE `alarm_rule` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `enable` tinyint(3) DEFAULT NULL COMMENT '是否启用', + `name` varchar(255) DEFAULT NULL COMMENT '规则名', + `condition` varchar(100) DEFAULT NULL COMMENT '条件JSON字符串:{"hours":23,"minutes":59,"count":10}', + `duration` char(17) DEFAULT NULL COMMENT 'HH:MM:SS-HH:MM:SS 时间段(开始-结束)', + `role_id` char(36) DEFAULT NULL COMMENT '操作者角色id', + `process_id_list` mediumtext COMMENT 'processId', + `event_module_code` int(11) DEFAULT NULL COMMENT '事件模块代码', + `event_module_name` varchar(255) DEFAULT NULL COMMENT '事件模块', + `event_type_code` int(11) DEFAULT NULL COMMENT '事件代码', + `event_type_name` varchar(255) DEFAULT NULL COMMENT '事件类型', + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(6) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1966060594098135041 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + +-- rpa.alarm_rule_user definition + +CREATE TABLE `alarm_rule_user` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `alarm_rule_id` bigint(20) DEFAULT NULL COMMENT 'alarm_rule表id', + `phone` varchar(200) DEFAULT NULL COMMENT '电话', + `name` varchar(100) DEFAULT NULL COMMENT '用户姓名', + `deleted` smallint(6) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1966061018251321345 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + +-- rpa.app_application definition + +CREATE TABLE `app_application` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `robot_id` varchar(100) NOT NULL COMMENT '机器人ID', + `robot_version` int(11) NOT NULL COMMENT '机器人版本ID', + `status` varchar(20) NOT NULL COMMENT '状态: 待审核pending, 已通过approved, 未通过rejected, 已撤销canceled,作废nullify', + `application_type` varchar(20) NOT NULL COMMENT '申请类型: release(上架)/use(使用)', + `security_level` varchar(10) DEFAULT NULL COMMENT '审核设置的密级red,green,yellow', + `allowed_dept` varchar(5000) DEFAULT NULL COMMENT '允许使用的部门ID列表', + `expire_time` timestamp NULL DEFAULT NULL COMMENT '使用期限(截止日期)', + `audit_opinion` varchar(500) DEFAULT NULL COMMENT '审核意见', + `creator_id` char(36) DEFAULT NULL COMMENT '申请人ID', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updater_id` char(36) DEFAULT NULL COMMENT '更新者或审核者id', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted` smallint(1) DEFAULT '0', + `tenant_id` char(36) CHARACTER SET utf8 DEFAULT NULL, + `client_deleted` smallint(1) DEFAULT '0' COMMENT '客户端的申请记录-是否删除', + `cloud_deleted` smallint(1) DEFAULT '0' COMMENT '卓越中心的申请记录-是否删除', + `default_pass` smallint(1) DEFAULT NULL COMMENT '选择绿色密级时,后续更新发版是否默认通过', + `market_info` varchar(500) DEFAULT NULL COMMENT '团队市场id等信息,用于第一次发起上架申请,审核通过后自动分享到该市场', + `publish_info` varchar(500) DEFAULT NULL COMMENT '发版JSON信息', + PRIMARY KEY (`id`), + KEY `idx_app_robot` (`robot_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1967839071050592259 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='上架/使用审核表'; + + +-- rpa.app_application_tenant definition + +CREATE TABLE `app_application_tenant` ( + `tenant_id` varchar(36) NOT NULL, + `audit_enable` smallint(6) DEFAULT NULL COMMENT '是否开启审核,1开启,0不开启', + `audit_enable_time` timestamp NULL DEFAULT NULL, + `audit_enable_operator` char(36) DEFAULT NULL, + `audit_enable_reason` varchar(100) DEFAULT NULL, + PRIMARY KEY (`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='租户是否开启审核配置表'; + + +-- rpa.app_market definition + +CREATE TABLE `app_market` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `tenant_id` char(36) DEFAULT NULL, + `market_id` varchar(20) DEFAULT NULL COMMENT '团队市场id', + `market_name` varchar(60) DEFAULT NULL COMMENT '市场名称', + `market_describe` varchar(800) DEFAULT NULL COMMENT '市场描述', + `market_type` varchar(10) DEFAULT NULL COMMENT '市场类型:team,official', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`), + KEY `app_market_creator_id_IDX` (`creator_id`), + KEY `app_market_market_id_IDX` (`market_id`), + KEY `app_market_tenant_id_IDX` (`tenant_id`) +) ENGINE=InnoDB AUTO_INCREMENT=134 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='团队市场-团队表'; + + +-- rpa.app_market_dict definition + +CREATE TABLE `app_market_dict` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `business_code` varchar(100) DEFAULT NULL COMMENT '业务编码:1、行业类型,2、角色功能marketRoleFunc', + `name` varchar(64) DEFAULT NULL COMMENT '行业名称,角色功能名称', + `dict_code` varchar(64) DEFAULT NULL COMMENT '行业编码,功能编码', + `dict_value` varchar(100) DEFAULT NULL COMMENT 'T有权限,F无权限', + `user_type` varchar(100) DEFAULT NULL COMMENT 'owner,admin,acquirer,author', + `description` varchar(256) DEFAULT NULL COMMENT '描述', + `seq` int(11) DEFAULT NULL COMMENT '排序', + `creator_id` char(36) DEFAULT '73', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updater_id` char(36) DEFAULT '73', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `deleted` smallint(1) DEFAULT '0', + PRIMARY KEY (`id`), + KEY `app_market_dict_dict_code_IDX` (`dict_code`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=80 DEFAULT CHARSET=utf8; + + +-- rpa.app_market_resource definition + +CREATE TABLE `app_market_resource` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `market_id` varchar(20) DEFAULT NULL COMMENT '团队市场id', + `app_id` varchar(50) DEFAULT NULL COMMENT '应用id,模板id,组件id', + `download_num` bigint(20) DEFAULT '0' COMMENT '下载次数', + `check_num` bigint(20) DEFAULT '0' COMMENT '查看次数', + `creator_id` char(36) DEFAULT NULL COMMENT '发布人', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '发布时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `tenant_id` char(36) DEFAULT NULL, + `robot_id` varchar(100) CHARACTER SET utf8 DEFAULT NULL COMMENT '机器人id', + `app_name` varchar(64) CHARACTER SET utf8 DEFAULT NULL COMMENT '资源名称', + PRIMARY KEY (`id`), + KEY `app_market_resource_app_id_IDX` (`app_id`), + KEY `app_market_resource_creator_id_IDX` (`creator_id`), + KEY `app_market_resource_market_id_IDX` (`market_id`), + KEY `app_market_resource_tenant_id_IDX` (`tenant_id`) +) ENGINE=InnoDB AUTO_INCREMENT=196 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='团队市场-资源映射表'; + + +-- rpa.app_market_user definition + +CREATE TABLE `app_market_user` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `tenant_id` char(36) DEFAULT NULL COMMENT '根据id找在对应租户的信息', + `market_id` varchar(20) DEFAULT NULL COMMENT '团队市场id', + `user_type` varchar(10) DEFAULT NULL COMMENT '成员类型:owner,admin,acquirer,author', + `creator_id` char(36) DEFAULT NULL COMMENT '成员id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '加入时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`), + KEY `app_market_user_creator_id_IDX` (`creator_id`), + KEY `app_market_user_market_id_IDX` (`market_id`), + KEY `app_market_user_tenant_id_IDX` (`tenant_id`) +) ENGINE=InnoDB AUTO_INCREMENT=201 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='团队市场-人员表,n:n的关系'; + + +-- rpa.app_market_version definition + +CREATE TABLE `app_market_version` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `market_id` varchar(100) DEFAULT NULL COMMENT '团队市场id', + `app_id` varchar(50) DEFAULT NULL, + `app_version` int(11) DEFAULT NULL COMMENT '应用版本,同机器人版本', + `edit_flag` tinyint(1) DEFAULT '1' COMMENT '自己创建的分享到市场,是否支持编辑/开放源码;0不支持,1支持', + `category` varchar(100) DEFAULT NULL COMMENT '分享到市场的机器人行业:政务、医疗、商业等', + `creator_id` char(36) DEFAULT NULL COMMENT '发布人', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '发布时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `app_market_version_app_id_IDX` (`app_id`) USING BTREE, + KEY `app_market_version_market_id_IDX` (`market_id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=280 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='团队市场-应用版本表'; + + +-- rpa.atom_like definition + +CREATE TABLE `atom_like` ( + `id` int(20) NOT NULL AUTO_INCREMENT, + `like_id` varchar(20) NOT NULL, + `atom_key` varchar(100) NOT NULL COMMENT '原子能力的key,全局唯一', + `creator_id` char(36) NOT NULL, + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `is_deleted` smallint(1) NOT NULL DEFAULT '0', + `updater_id` char(36) DEFAULT NULL, + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=81 DEFAULT CHARSET=utf8 COMMENT='原子能力收藏'; + + +-- rpa.atom_meta_duplicate_log definition + +CREATE TABLE `atom_meta_duplicate_log` ( + `id` bigint(20) NOT NULL DEFAULT '0', + `atom_key` varchar(100) DEFAULT NULL, + `version` varchar(20) DEFAULT NULL COMMENT '原子能力版本', + `request_body` mediumtext COMMENT '完整请求体', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除', + `creator_id` bigint(20) DEFAULT '73', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updater_id` bigint(20) DEFAULT '73', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + +-- rpa.audit_checkpoint definition + +CREATE TABLE `audit_checkpoint` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `audit_object_type` varchar(36) DEFAULT NULL COMMENT 'robot,dept', + `last_processed_id` varchar(36) DEFAULT NULL, + `audit_status` varchar(20) DEFAULT NULL COMMENT '统计进度:counting, completed, pending,to_count', + `count_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '删除标识', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=324 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='监控管理统计断点表'; + + +-- rpa.audit_record definition + +CREATE TABLE `audit_record` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `event_module_code` int(11) DEFAULT NULL COMMENT '事件模块代码', + `event_module_name` varchar(255) DEFAULT NULL COMMENT '事件模块', + `event_type_code` int(11) DEFAULT NULL COMMENT '事件代码', + `event_type_name` varchar(255) DEFAULT NULL COMMENT '事件类型', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `creator_name` varchar(255) DEFAULT NULL COMMENT '创建者名称', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `event_detail` varchar(255) DEFAULT NULL COMMENT '事件详情', + `process_id_list` mediumtext COMMENT 'processId', + `role_id_list` mediumtext COMMENT '角色id列表', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=150 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + +-- rpa.c_atom_meta definition + +CREATE TABLE `c_atom_meta` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `parent_key` varchar(100) DEFAULT NULL, + `atom_key` varchar(100) DEFAULT NULL, + `atom_content` mediumtext COMMENT '原子能力所有配置信息,json', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除', + `creator_id` char(36) DEFAULT '73', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updater_id` bigint(20) DEFAULT '73', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `version` varchar(20) DEFAULT NULL COMMENT '原子能力版本', + `sort` int(11) DEFAULT NULL COMMENT '原子能力展示顺序', + `version_num` varchar(100) DEFAULT NULL COMMENT '大版本', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=274 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + +-- rpa.c_element definition + +CREATE TABLE `c_element` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `element_id` varchar(100) DEFAULT NULL COMMENT '元素id', + `element_name` varchar(100) DEFAULT NULL COMMENT '元素名称', + `icon` varchar(100) DEFAULT NULL COMMENT '图标', + `image_id` varchar(100) DEFAULT NULL COMMENT '图片下载地址', + `parent_image_id` varchar(100) DEFAULT NULL COMMENT '元素的父级图片下载地址', + `element_data` mediumtext COMMENT '元素内容', + `deleted` smallint(6) DEFAULT '0', + `creator_id` char(36) DEFAULT NULL, + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updater_id` char(36) DEFAULT NULL, + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `robot_id` varchar(100) DEFAULT NULL, + `robot_version` int(11) DEFAULT NULL, + `group_id` varchar(30) DEFAULT NULL, + `common_sub_type` varchar(50) DEFAULT NULL COMMENT 'cv图像, sigle普通拾取,batch数据抓取', + `group_name` varchar(100) DEFAULT NULL, + `element_type` varchar(20) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6205 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='客户端,元素信息'; + + +-- rpa.c_global_var definition + +CREATE TABLE `c_global_var` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `project_id` varchar(100) DEFAULT NULL, + `global_id` varchar(100) DEFAULT NULL, + `var_name` varchar(100) DEFAULT NULL, + `var_type` varchar(100) DEFAULT NULL, + `var_value` varchar(100) DEFAULT NULL, + `var_describe` varchar(100) DEFAULT NULL, + `deleted` smallint(6) DEFAULT NULL, + `creator_id` char(36) DEFAULT NULL, + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updater_id` char(36) DEFAULT NULL, + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `robot_id` varchar(100) DEFAULT NULL, + `robot_version` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=506 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='客户端-全局变量'; + + +-- rpa.c_group definition + +CREATE TABLE `c_group` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `group_id` varchar(100) DEFAULT NULL, + `group_name` varchar(100) DEFAULT NULL, + `creator_id` char(36) DEFAULT NULL, + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updater_id` char(36) DEFAULT NULL, + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `deleted` smallint(6) DEFAULT '0', + `robot_id` varchar(100) DEFAULT NULL, + `robot_version` int(11) DEFAULT NULL, + `element_type` varchar(20) DEFAULT NULL COMMENT 'cv:cv拾取; common:普通元素拾取', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1505 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='元素或图像的分组'; + + +-- rpa.c_module definition + +CREATE TABLE `c_module` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `module_id` varchar(100) DEFAULT NULL COMMENT '流程id', + `module_content` mediumtext COMMENT '全量python代码数据', + `module_name` varchar(100) DEFAULT NULL COMMENT 'python文件名', + `deleted` smallint(6) DEFAULT '0', + `creator_id` char(36) DEFAULT '73', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updater_id` char(36) DEFAULT '73', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `robot_id` varchar(100) DEFAULT NULL, + `robot_version` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=285 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='客户端-python模块数据'; + + +-- rpa.c_param definition + +CREATE TABLE `c_param` ( + `id` varchar(20) NOT NULL COMMENT '参数id', + `var_direction` int(11) DEFAULT NULL COMMENT '输入/输出', + `var_name` varchar(100) DEFAULT NULL COMMENT '参数名称', + `var_type` varchar(100) DEFAULT NULL COMMENT '参数类型', + `var_value` varchar(100) DEFAULT NULL COMMENT '参数内容', + `var_describe` varchar(100) DEFAULT NULL COMMENT '参数描述', + `process_id` varchar(100) DEFAULT NULL COMMENT '流程id', + `creator_id` char(36) DEFAULT NULL, + `updater_id` char(36) DEFAULT NULL, + `create_time` timestamp NULL DEFAULT NULL, + `update_time` timestamp NULL DEFAULT NULL, + `deleted` int(11) DEFAULT NULL, + `robot_id` varchar(100) DEFAULT NULL, + `robot_version` int(11) DEFAULT NULL, + KEY `c_param_id_IDX` (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + +-- rpa.c_process definition + +CREATE TABLE `c_process` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `project_id` varchar(100) DEFAULT NULL COMMENT '工程id', + `process_id` varchar(100) DEFAULT NULL COMMENT '流程id', + `process_content` mediumtext COMMENT '全量流程数据', + `process_name` varchar(100) DEFAULT NULL COMMENT '流程名称', + `deleted` smallint(6) DEFAULT '0', + `creator_id` char(36) DEFAULT '73', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updater_id` char(36) DEFAULT '73', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `robot_id` varchar(100) DEFAULT NULL, + `robot_version` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3568 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='客户端-流程数据'; + + +-- rpa.c_project definition + +CREATE TABLE `c_project` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `project_id` varchar(100) DEFAULT NULL, + `project_name` varchar(200) CHARACTER SET utf8 DEFAULT NULL COMMENT '项目名称', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` datetime DEFAULT NULL COMMENT '创建时间', + `deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除 0:未删除 1:已删除', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='工程表'; + + +-- rpa.c_require definition + +CREATE TABLE `c_require` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `project_id` varchar(100) DEFAULT NULL, + `package_name` varchar(100) CHARACTER SET utf8 DEFAULT NULL COMMENT '项目名称', + `package_version` varchar(20) DEFAULT NULL, + `mirror` varchar(100) DEFAULT NULL, + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` datetime DEFAULT NULL COMMENT '创建时间', + `deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除 0:未删除 1:已删除', + `robot_id` varchar(100) DEFAULT NULL, + `robot_version` int(11) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=116 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='python依赖管理'; + + +-- rpa.cloud_terminal definition + +CREATE TABLE `cloud_terminal` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `dept_id_path` varchar(100) DEFAULT NULL COMMENT '部门全路径id', + `name` varchar(100) DEFAULT NULL COMMENT '终端名称', + `terminal_mac` varchar(100) DEFAULT NULL COMMENT '设备号,终端唯一标识', + `terminal_ip` varchar(100) DEFAULT NULL COMMENT 'ip', + `terminal_status` varchar(100) DEFAULT NULL COMMENT '当前状态,忙碌busy,空闲free,离线offline', + `terminal_des` varchar(100) DEFAULT NULL COMMENT '终端描述', + `user_id` char(36) DEFAULT NULL COMMENT '最近登陆用户id', + `dept_name` varchar(100) DEFAULT NULL COMMENT '部门名称', + `account_last` varchar(100) DEFAULT NULL COMMENT '最近登陆账号', + `user_name_last` varchar(100) DEFAULT NULL COMMENT '最近登陆用户名', + `time_last` timestamp NULL DEFAULT NULL COMMENT '最近登陆时间', + `execute_time_total` bigint(20) DEFAULT '0' COMMENT '单个终端累计执行时长,用于终端列表展示,更新机器人执行记录表时同步更新该表', + `execute_num` bigint(20) DEFAULT '0' COMMENT '单个终端累计执行次数,更新机器人执行记录表时同步更新该表', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '终端记录创建时间', + `terminal_type` varchar(50) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `cloud_terminal_mac_tenant_index` (`terminal_mac`,`tenant_id`), + KEY `cloud_terminal_tenant_id_IDX` (`tenant_id`,`dept_id_path`), + KEY `cloud_terminal_terminal_mac_IDX` (`terminal_mac`), + KEY `cloud_terminal_user_id_IDX` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='终端表'; + + +-- rpa.component definition + +CREATE TABLE `component` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `component_id` varchar(100) NOT NULL COMMENT '机器人唯一id,获取的应用id', + `name` varchar(100) NOT NULL COMMENT '当前名字,用于列表展示', + `creator_id` char(36) NOT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` char(36) NOT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `is_shown` smallint(1) NOT NULL DEFAULT '1' COMMENT '是否在用户列表页显示 0:不显示,1:显示', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `tenant_id` char(36) DEFAULT NULL, + `app_id` varchar(50) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT 'appmarketResource中的应用id', + `app_version` int(11) DEFAULT NULL COMMENT '获取的应用:应用市场版本', + `market_id` varchar(20) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '获取的应用:市场id', + `resource_status` varchar(20) DEFAULT NULL COMMENT '资源状态:toObtain, obtained, toUpdate', + `data_source` varchar(20) DEFAULT NULL COMMENT '来源:create 自己创建 ; market 市场获取 ', + `transform_status` varchar(20) DEFAULT NULL COMMENT 'editing 编辑中,published 已发版,shared 已上架,locked锁定(无法编辑)', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=95 DEFAULT CHARSET=utf8 COMMENT='组件表'; + + +-- rpa.component_robot_block definition + +CREATE TABLE `component_robot_block` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `robot_id` varchar(100) CHARACTER SET utf8 NOT NULL COMMENT '机器人id', + `robot_version` int(10) NOT NULL COMMENT '机器人版本号', + `component_id` varchar(100) CHARACTER SET utf8 NOT NULL COMMENT '组件id', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `tenant_id` char(36) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='机器人对组件屏蔽表'; + + +-- rpa.component_robot_use definition + +CREATE TABLE `component_robot_use` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `robot_id` varchar(100) CHARACTER SET utf8 NOT NULL COMMENT '机器人id', + `robot_version` int(10) NOT NULL COMMENT '机器人版本号', + `component_id` varchar(100) CHARACTER SET utf8 NOT NULL COMMENT '组件id', + `component_version` int(10) NOT NULL COMMENT '组件版本号', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `tenant_id` char(36) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='机器人对组件引用表'; + + +-- rpa.component_version definition + +CREATE TABLE `component_version` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `component_id` varchar(100) CHARACTER SET utf8 NOT NULL COMMENT '机器人id', + `version` int(10) NOT NULL COMMENT '版本号', + `introduction` longtext CHARACTER SET utf8 COMMENT '简介', + `update_log` longtext CHARACTER SET utf8 COMMENT '更新日志', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `tenant_id` char(36) DEFAULT NULL, + `param` text CHARACTER SET utf8, + `param_detail` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '发版时拖的表单参数信息', + `icon` varchar(30) NOT NULL COMMENT '图标', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=68 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='组件版本表'; + + +-- rpa.dispatch_day_task_info definition + +CREATE TABLE `dispatch_day_task_info` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `terminal_id` varchar(20) DEFAULT NULL COMMENT '终端id', + `task_id` varchar(30) DEFAULT NULL COMMENT '任务ID', + `task_name` varchar(30) DEFAULT NULL COMMENT '任务名', + `robot_id` varchar(30) DEFAULT NULL COMMENT '机器人ID', + `robot_name` varchar(30) DEFAULT NULL COMMENT '机器人名', + `status` varchar(10) DEFAULT NULL COMMENT '当前状态 待执行 todo /已执行 done /在执行 doing', + `execute_time` varchar(10) DEFAULT NULL COMMENT '任务执行时间', + `sort` int(11) DEFAULT NULL COMMENT '排序, 越小越靠前', + `tenant_id` bigint(20) DEFAULT NULL, + `creator_id` bigint(20) DEFAULT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` bigint(20) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_task_id` (`task_id`), + KEY `idx_robot_id` (`robot_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='调度模式:终端每日上传的任务情况信息'; + + +-- rpa.dispatch_task definition + +CREATE TABLE `dispatch_task` ( + `dispatch_task_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '调度模式计划任务id', + `status` varchar(10) NOT NULL DEFAULT '0' COMMENT '任务状态:启用中active、关闭stop、已过期expired', + `name` varchar(50) DEFAULT NULL COMMENT '调度模式计划任务名称', + `cron_json` mediumtext COMMENT '构建调度计划任务的灵活参数;定时schedule存计划执行的对应JSON', + `type` varchar(10) DEFAULT NULL COMMENT '触发条件:手动触发manual、定时schedule、定时触发trigger', + `exceptional` varchar(20) NOT NULL DEFAULT 'stop' COMMENT '报错如何处理:跳过jump、停止stop、重试后跳过retry_jump、重试后停止retry_stop', + `retry_num` int(11) DEFAULT NULL COMMENT '只有exceptional为retry时,记录的重试次数', + `timeout_enable` smallint(6) DEFAULT NULL COMMENT '是否启用超时时间 1:启用 0:不启用', + `timeout` int(11) DEFAULT '9999' COMMENT '超时时间', + `queue_enable` smallint(6) DEFAULT '0' COMMENT '是否启用排队 1:启用 0:不启用', + `screen_record_enable` smallint(6) DEFAULT '0' COMMENT '是否开启录屏 1:启用 0:不启用', + `virtual_desktop_enable` smallint(6) DEFAULT '0' COMMENT '是否开启虚拟桌面 1:启用 0:不启用', + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(6) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`dispatch_task_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1965712054394085377 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + +-- rpa.dispatch_task_execute_record definition + +CREATE TABLE `dispatch_task_execute_record` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `dispatch_task_id` bigint(20) DEFAULT NULL COMMENT '调度模式计划任务id', + `dispatch_task_execute_id` bigint(20) DEFAULT NULL COMMENT '调度模式计划任务执行id', + `count` int(11) DEFAULT NULL COMMENT '执行批次,1,2,3....', + `dispatch_task_type` varchar(20) DEFAULT NULL COMMENT '触发条件:手动触发manual、定时schedule、定时触发trigger', + `result` varchar(20) DEFAULT NULL COMMENT '执行结果枚举:成功success、失败error、执行中executing、中止cancel、下发失败dispatch_error、执行失败exe_error', + `start_time` datetime DEFAULT NULL COMMENT '执行开始时间', + `end_time` datetime DEFAULT NULL COMMENT '执行结束时间', + `execute_time` bigint(20) DEFAULT NULL COMMENT '执行耗时 单位秒', + `terminal_id` char(36) DEFAULT NULL COMMENT '终端唯一标识,如设备mac地址', + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `task_detail_json` mediumtext COMMENT '任务详情', + `deleted` smallint(6) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`), + KEY `idx_dispatch_task_teminal_task_id` (`dispatch_task_id`) +) ENGINE=InnoDB AUTO_INCREMENT=113 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + +-- rpa.dispatch_task_robot definition + +CREATE TABLE `dispatch_task_robot` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `dispatch_task_id` bigint(20) DEFAULT NULL COMMENT '调度模式计划任务id', + `robot_id` varchar(30) DEFAULT NULL COMMENT '机器人ID', + `online` tinyint(3) DEFAULT NULL COMMENT '是否启用版本: 0:未启用,1:已启用', + `version` int(11) DEFAULT NULL COMMENT '机器人版本', + `param_json` mediumtext COMMENT '机器人配置参数', + `sort` int(11) DEFAULT NULL COMMENT '排序, 越小越靠前', + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(6) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`), + KEY `idx_dispatch_task_teminal_task_id` (`dispatch_task_id`) +) ENGINE=InnoDB AUTO_INCREMENT=86 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + +-- rpa.dispatch_task_robot_execute_record definition + +CREATE TABLE `dispatch_task_robot_execute_record` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `execute_id` bigint(20) DEFAULT NULL COMMENT '机器人执行id', + `dispatch_task_execute_id` bigint(20) DEFAULT NULL COMMENT '调度模式计划任务执行id', + `robot_id` varchar(100) DEFAULT NULL COMMENT '机器人id', + `robot_version` int(11) DEFAULT NULL COMMENT '机器人版本号', + `start_time` timestamp NULL DEFAULT NULL COMMENT '开始时间', + `end_time` timestamp NULL DEFAULT NULL COMMENT '结束时间', + `execute_time` bigint(20) DEFAULT NULL COMMENT '执行耗时 单位秒', + `result` varchar(20) DEFAULT NULL COMMENT '执行结果枚举::robotFail:失败, robotSuccess:成功,robotCancel:取消(中止),robotExecute:正在执行', + `param_json` mediumtext COMMENT '机器人执行参数', + `error_reason` varchar(255) DEFAULT NULL COMMENT '错误原因', + `execute_log` longtext COMMENT '日志内容', + `video_local_path` varchar(200) DEFAULT NULL COMMENT '视频记录的本地存储路径', + `dept_id_path` varchar(100) DEFAULT NULL COMMENT '部门全路径编码', + `terminal_id` char(36) DEFAULT NULL COMMENT '终端唯一标识,如设备mac地址', + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(6) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=85 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + +-- rpa.dispatch_task_terminal definition + +CREATE TABLE `dispatch_task_terminal` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `dispatch_task_id` bigint(20) DEFAULT NULL COMMENT '调度模式计划任务id', + `terminal_or_group` varchar(10) DEFAULT NULL COMMENT '触发条件:终端teminal、终端分组group', + `execute_method` varchar(10) DEFAULT NULL COMMENT '执行方式:随机一台random_one、全部执行all', + `value` mediumtext COMMENT '具体值:存储 list ; 其中终端对应:terminal_id(表terminal) 分组对应:id (terminal_group_name)', + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(6) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`), + KEY `idx_dispatch_task_teminal_task_id` (`dispatch_task_id`) +) ENGINE=InnoDB AUTO_INCREMENT=62 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + +-- rpa.file definition + +CREATE TABLE `file` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `file_id` varchar(50) DEFAULT NULL COMMENT '文件对应的uuid', + `path` varchar(100) DEFAULT NULL COMMENT '文件在s3上对应的路径', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `deleted` int(11) DEFAULT 0 COMMENT '逻辑删除标志位', + `file_name` varchar(1000) DEFAULT NULL COMMENT '文件真实名称', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4406 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='文件表'; + + +-- rpa.his_base definition + +CREATE TABLE `his_base` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `dept_id_path` varchar(100) DEFAULT NULL COMMENT '部门全路径编码', + `execute_success` bigint(20) DEFAULT NULL COMMENT '累计执行成功次数', + `execute_fail` bigint(20) DEFAULT NULL COMMENT '累计执行失败次数', + `execute_abort` bigint(20) DEFAULT NULL COMMENT '累计执行中止次数', + `robot_num` bigint(20) DEFAULT NULL COMMENT '累计机器人总数', + `execute_total` bigint(20) DEFAULT NULL COMMENT '机器人累计执行次数', + `execute_time_total` bigint(20) DEFAULT NULL COMMENT '全部机器人或全部终端累计执行时长,单位秒,只计算成功的', + `execute_success_rate` decimal(5,2) DEFAULT NULL COMMENT '累计执行成功率', + `user_num` bigint(20) DEFAULT NULL COMMENT '累计用户数量', + `count_time` timestamp NULL DEFAULT NULL COMMENT '统计时间', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) NOT NULL DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `terminal` bigint(20) DEFAULT NULL COMMENT '终端数量', + `labor_save` bigint(20) DEFAULT NULL COMMENT '节省的人力', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=295 DEFAULT CHARSET=utf8 COMMENT='全部机器人和全部终端趋势表'; + + +-- rpa.his_data_enum definition + +CREATE TABLE `his_data_enum` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `parent_code` varchar(100) DEFAULT NULL, + `icon` varchar(100) DEFAULT NULL, + `field` varchar(100) DEFAULT NULL, + `text` varchar(100) DEFAULT NULL, + `num` varchar(100) DEFAULT NULL, + `unit` varchar(100) DEFAULT NULL, + `percent` varchar(100) DEFAULT NULL, + `tip` varchar(100) DEFAULT NULL, + `order` bigint(20) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8 COMMENT='监控管理数据概览卡片配置数据枚举'; + + +-- rpa.his_robot definition + +CREATE TABLE `his_robot` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `execute_num_total` bigint(20) DEFAULT NULL COMMENT '当日执行总次数', + `execute_success` bigint(20) DEFAULT NULL COMMENT '每日成功次数', + `execute_fail` bigint(20) DEFAULT NULL COMMENT '每日失败次数', + `execute_abort` bigint(20) DEFAULT NULL COMMENT '每日中止次数', + `execute_success_rate` decimal(5,2) DEFAULT NULL COMMENT '每日成功率', + `execute_time` bigint(20) DEFAULT NULL COMMENT '每日执行时长,单位秒', + `count_time` timestamp NULL DEFAULT NULL COMMENT '统计时间', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `robot_id` varchar(100) DEFAULT NULL, + `user_id` char(36) DEFAULT NULL COMMENT '用户id', + `dept_id_path` varchar(100) DEFAULT NULL COMMENT '部门全路径id', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=147 DEFAULT CHARSET=utf8 COMMENT='单个机器人趋势表,当日数据'; + + +-- rpa.his_terminal definition + +CREATE TABLE `his_terminal` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `dept_id_path` varchar(36) DEFAULT NULL COMMENT '部门全路径id', + `terminal_id` varchar(100) DEFAULT NULL COMMENT '设备mac', + `execute_time` bigint(20) DEFAULT NULL COMMENT '每日执行时长', + `execute_num` bigint(20) DEFAULT NULL COMMENT '终端每日执行次数', + `count_time` timestamp NULL DEFAULT NULL COMMENT '统计时间', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`), + KEY `his_terminal_terminal_id_IDX` (`terminal_id`) USING BTREE, + KEY `his_terminal_tenant_id_IDX` (`tenant_id`,`dept_id_path`) USING BTREE, + KEY `his_terminal_count_time_IDX` (`count_time`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=46 DEFAULT CHARSET=utf8 COMMENT='单个终端趋势表'; + + +-- rpa.notify_send definition + +CREATE TABLE `notify_send` ( + `tenant_id` varchar(100) CHARACTER SET utf8 DEFAULT NULL COMMENT '接受者所在租户', + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `user_id` varchar(50) CHARACTER SET utf8 DEFAULT NULL COMMENT '接收者', + `message_info` varchar(100) CHARACTER SET utf8 DEFAULT NULL COMMENT '消息体id', + `message_type` varchar(20) CHARACTER SET utf8 DEFAULT NULL COMMENT '消息类型:邀人消息teamMarketInvite,更新消息teamMarketUpdate', + `operate_result` smallint(2) DEFAULT NULL COMMENT '操作结果:未读1, 已读2,已加入3,已拒绝4', + `market_id` varchar(500) CHARACTER SET utf8 DEFAULT NULL COMMENT '市场id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(2) DEFAULT '0' COMMENT '删除标识', + `user_type` varchar(10) CHARACTER SET utf8 DEFAULT NULL COMMENT '成员类型:owner,admin,consumer', + `app_name` varchar(200) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=202 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='消息通知-消息表'; + + +-- rpa.openapi_auth definition + +CREATE TABLE `openapi_auth` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(50) DEFAULT NULL, + `user_id` char(36) DEFAULT NULL COMMENT '用户id', + `api_key` varchar(100) DEFAULT NULL, + `prefix` varchar(10) DEFAULT NULL, + `created_at` datetime DEFAULT NULL, + `updated_at` datetime DEFAULT NULL, + `is_active` tinyint(1) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UNIQUE` (`api_key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='openapi鉴权储存'; + + +-- rpa.openai_workflows definition + +CREATE TABLE `openai_workflows` ( + `project_id` varchar(100) NOT NULL COMMENT '项目ID(主键)', + `name` varchar(100) NOT NULL COMMENT '工作流名称', + `description` varchar(500) DEFAULT NULL COMMENT '工作流描述', + `version` int(11) NOT NULL DEFAULT '1' COMMENT '工作流版本号', + `status` int(11) NOT NULL DEFAULT '1' COMMENT '工作流状态(1=激活,0=禁用)', + `user_id` varchar(50) NOT NULL COMMENT '用户ID', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `english_name` varchar(100) DEFAULT NULL COMMENT '翻译后的英文名称', + `parameters` text COMMENT '存储JSON字符串格式的参数', + PRIMARY KEY (`project_id`), + KEY `idx_name` (`name`), + KEY `idx_user_id` (`user_id`), + KEY `idx_status` (`status`), + KEY `idx_created_at` (`created_at`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + + +-- rpa.openai_executions definition + +CREATE TABLE `openai_executions` ( + `id` varchar(36) NOT NULL COMMENT '执行记录ID(UUID)', + `project_id` varchar(100) NOT NULL COMMENT '项目ID(关联工作流)', + `status` varchar(20) NOT NULL DEFAULT 'PENDING' COMMENT '执行状态(PENDING/RUNNING/COMPLETED/FAILED/CANCELLED)', + `parameters` text COMMENT '执行参数(JSON格式)', + `result` text COMMENT '执行结果(JSON格式)', + `error` text COMMENT '错误信息', + `user_id` varchar(50) NOT NULL COMMENT '用户ID', + `exec_position` varchar(50) NOT NULL DEFAULT 'EXECUTOR' COMMENT '执行位置', + `version` int(11) DEFAULT NULL COMMENT '工作流版本号', + `start_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '开始时间', + `end_time` datetime DEFAULT NULL COMMENT '结束时间', + PRIMARY KEY (`id`), + KEY `idx_project_id` (`project_id`), + KEY `idx_user_id` (`user_id`), + KEY `idx_status` (`status`), + KEY `idx_start_time` (`start_time`), + CONSTRAINT `openai_executions_ibfk_1` FOREIGN KEY (`project_id`) REFERENCES `openai_workflows` (`project_id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + + +-- rpa.pypi_packages definition + +CREATE TABLE `pypi_packages` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `package_name` varchar(255) NOT NULL, + `oss_path` varchar(255) NOT NULL, + `visibility` tinyint(1) DEFAULT '1' COMMENT 'visibility 1:公共可见包 2:个人私有包 3:灰度包,部分人可见', + `user_id` char(36) DEFAULT '0' COMMENT '发布用户id', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP, + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `unique_key` (`package_name`,`visibility`,`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +-- rpa.robot_design definition + +CREATE TABLE `robot_design` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `robot_id` varchar(100) DEFAULT NULL COMMENT '机器人唯一id,获取的应用id', + `name` varchar(100) DEFAULT NULL COMMENT '当前名字,用于列表展示', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `tenant_id` char(36) DEFAULT NULL, + `app_id` varchar(50) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT 'appmarketResource中的应用id', + `app_version` int(11) DEFAULT NULL COMMENT '获取的应用:应用市场版本', + `market_id` varchar(20) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '获取的应用:市场id', + `resource_status` varchar(20) DEFAULT NULL COMMENT '资源状态:toObtain, obtained, toUpdate', + `data_source` varchar(20) DEFAULT NULL COMMENT '来源:create 自己创建 ; market 市场获取 ', + `transform_status` varchar(20) DEFAULT NULL COMMENT 'editing 编辑中,published 已发版,shared 已上架,locked锁定(无法编辑)', + `edit_enable` varchar(100) DEFAULT NULL COMMENT '废弃', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3481 DEFAULT CHARSET=utf8 COMMENT='云端机器人表'; + + +-- rpa.robot_execute definition + +CREATE TABLE `robot_execute` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `robot_id` varchar(100) DEFAULT NULL COMMENT '机器人唯一id,获取的应用id', + `name` varchar(100) DEFAULT NULL COMMENT '当前名字,用于列表展示', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `tenant_id` char(36) DEFAULT NULL, + `app_id` varchar(50) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT 'appmarketResource中的应用id', + `app_version` int(11) DEFAULT NULL COMMENT '获取的应用:应用市场版本', + `market_id` varchar(20) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '获取的应用:市场id', + `resource_status` varchar(20) DEFAULT NULL COMMENT '资源状态:toObtain, obtained, toUpdate', + `data_source` varchar(20) DEFAULT NULL COMMENT '来源:create 自己创建 ; market 市场获取 ;deploy卓越中心部署', + `param_detail` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '运行前用户自定义的表单参数', + `dept_id_path` varchar(200) DEFAULT NULL COMMENT '部门全路径', + `type` varchar(10) DEFAULT NULL COMMENT '最新版本机器人的类型,web,other', + `latest_release_time` timestamp NULL DEFAULT NULL COMMENT '最新版本发版时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2667 DEFAULT CHARSET=utf8 COMMENT='云端机器人表'; + + +-- rpa.robot_execute_record definition + +CREATE TABLE `robot_execute_record` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `execute_id` varchar(30) DEFAULT NULL COMMENT '执行id', + `robot_id` varchar(100) DEFAULT NULL COMMENT '机器人id', + `robot_version` int(10) DEFAULT NULL COMMENT '机器人版本号', + `start_time` timestamp NULL DEFAULT NULL COMMENT '开始时间', + `end_time` timestamp NULL DEFAULT NULL COMMENT '结束时间', + `execute_time` bigint(20) DEFAULT NULL COMMENT '执行耗时 单位秒', + `mode` varchar(60) DEFAULT NULL COMMENT '运行位置:工程列表页PROJECT_LIST ; 工程编辑页EDIT_PAGE; 计划任务CRONTAB ; 执行器运行 EXECUTOR', + `task_execute_id` varchar(30) DEFAULT NULL COMMENT '计划任务执行id,即schedule_task_execute的execute_id', + `result` varchar(20) DEFAULT NULL COMMENT '执行结果:robotFail:失败, robotSuccess:成功,robotCancel:取消(中止),robotExecute:正在执行', + `error_reason` varchar(255) DEFAULT NULL COMMENT '错误原因', + `execute_log` longtext COMMENT '日志内容', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `tenant_id` char(36) DEFAULT NULL, + `video_local_path` varchar(200) DEFAULT NULL COMMENT '视频记录的本地存储路径', + `dept_id_path` varchar(100) DEFAULT NULL COMMENT '部门全路径编码', + `terminal_id` char(36) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '终端唯一标识,如设备mac地址', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=57946 DEFAULT CHARSET=utf8 COMMENT='云端机器人执行记录表'; + + +-- rpa.robot_version definition + +CREATE TABLE `robot_version` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `robot_id` varchar(100) CHARACTER SET utf8 DEFAULT NULL COMMENT '机器人id', + `version` int(10) DEFAULT NULL COMMENT '版本号', + `introduction` longtext CHARACTER SET utf8 COMMENT '简介', + `update_log` longtext CHARACTER SET utf8 COMMENT '更新日志', + `use_description` longtext CHARACTER SET utf8 COMMENT '使用说明', + `online` smallint(2) DEFAULT '0' COMMENT '是否启用 0:未启用,1:已启用', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `tenant_id` char(36) DEFAULT NULL, + `param` text CHARACTER SET utf8, + `param_detail` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '发版时拖的表单参数信息', + `video_id` varchar(100) DEFAULT NULL COMMENT '视频地址id', + `appendix_id` varchar(100) DEFAULT NULL COMMENT '附件地址id', + `icon` varchar(100) DEFAULT NULL COMMENT '图标', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2083 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='云端机器人版本表'; + + +-- rpa.schedule_task definition + +CREATE TABLE `schedule_task` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `task_id` varchar(100) DEFAULT NULL COMMENT '计划任务id', + `name` varchar(64) DEFAULT NULL COMMENT '任务名称', + `description` varchar(255) DEFAULT NULL COMMENT '描述', + `exception_handle_way` varchar(64) DEFAULT NULL COMMENT '异常处理方式:stop停止 skip跳过', + `run_mode` varchar(64) DEFAULT NULL COMMENT '执行模式,循环cycle, 定时fixed,自定义custom', + `cycle_frequency` varchar(10) DEFAULT NULL COMMENT '循环频率,单位秒,-1为只有一次,3600,,,custom', + `cycle_num` varchar(64) DEFAULT NULL COMMENT '自定义循环,循环类型,每1小时,每3小时,,自定义', + `cycle_unit` varchar(20) DEFAULT NULL COMMENT '自定义循环,循环单位:minutes, hour', + `status` varchar(64) DEFAULT NULL COMMENT '状态:doing执行中 close已结束 ready待执行', + `enable` tinyint(1) DEFAULT NULL COMMENT '启/禁用', + `schedule_type` varchar(64) DEFAULT NULL COMMENT '定时方式,day,month,week', + `schedule_rule` varchar(255) DEFAULT NULL COMMENT '定时配置(配置对象)', + `start_at` datetime DEFAULT NULL COMMENT '开始时间', + `end_at` datetime DEFAULT NULL COMMENT '结束时间', + `tenant_id` char(36) DEFAULT NULL, + `enable_queue_execution` tinyint(1) DEFAULT NULL COMMENT '是否排队执行', + `cron_expression` varchar(50) DEFAULT NULL COMMENT 'cron表达式', + `last_time` timestamp NULL DEFAULT NULL COMMENT '上次拉取时的nextTime', + `next_time` timestamp NULL DEFAULT NULL COMMENT '下次执行时间', + `creator_id` char(36) DEFAULT NULL COMMENT '创建人ID', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(6) DEFAULT NULL, + `pull_time` timestamp NULL DEFAULT NULL COMMENT '上次拉取时间', + `log_enable` varchar(5) CHARACTER SET utf8mb4 DEFAULT 'F' COMMENT '是否开启日志记录', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='调度任务'; + + +-- rpa.schedule_task_execute definition + +CREATE TABLE `schedule_task_execute` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `task_id` varchar(20) DEFAULT NULL COMMENT '任务ID', + `task_execute_id` varchar(20) DEFAULT NULL COMMENT '计划任务执行id', + `count` int(11) DEFAULT NULL COMMENT '执行批次,1,2,3....', + `result` varchar(20) DEFAULT NULL COMMENT '任务状态枚举 成功 "success" # 启动失败 "start_error" # 执行失败 "exe_error" # 取消 CANCEL = "cancel" # 执行中 "executing"', + `start_time` datetime DEFAULT NULL COMMENT '执行开始时间', + `end_time` datetime DEFAULT NULL COMMENT '执行结束时间', + `tenant_id` char(36) DEFAULT NULL, + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=894952 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='计划任务执行记录'; + + +-- rpa.schedule_task_pull_log definition + +CREATE TABLE `schedule_task_pull_log` ( + `id` bigint(20) DEFAULT NULL, + `task_id` varchar(100) CHARACTER SET utf8 DEFAULT NULL COMMENT '计划任务id', + `pull_time` timestamp NULL DEFAULT NULL COMMENT '上次拉取时间', + `last_time` timestamp NULL DEFAULT NULL COMMENT '上次拉取时的nextTime', + `next_time` timestamp NULL DEFAULT NULL COMMENT '下次执行时间', + `creator_id` char(36) DEFAULT NULL COMMENT '创建人ID', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + +-- rpa.schedule_task_robot definition + +CREATE TABLE `schedule_task_robot` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `task_id` varchar(30) DEFAULT NULL COMMENT '任务ID', + `robot_id` varchar(30) DEFAULT NULL COMMENT '机器人ID', + `sort` int(11) DEFAULT NULL COMMENT '排序, 越小越靠前', + `tenant_id` char(36) DEFAULT NULL, + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `param_json` mediumtext COMMENT '计划任务相关参数', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=1070 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='计划任务机器人列表'; + + +-- rpa.shared_file definition + +CREATE TABLE `shared_file` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', + `file_id` bigint(20) DEFAULT NULL COMMENT '文件对应的uuid', + `path` varchar(500) DEFAULT NULL COMMENT '文件在s3上对应的路径', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `file_name` varchar(1000) DEFAULT NULL COMMENT '文件真实名称', + `tags` varchar(512) DEFAULT NULL COMMENT '文件标签名称集合', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者ID', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `file_type` tinyint(4) DEFAULT NULL COMMENT '文件类型: 0-位置类型 1-文本 2-WORD 3-PDF', + `file_index_status` tinyint(4) DEFAULT NULL COMMENT '文件向量化状态:1-初始化 2-完成 3-失败', + `dept_id` varchar(100) DEFAULT NULL COMMENT '部门id', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='共享文件表'; + + +-- rpa.shared_file_tag definition + +CREATE TABLE `shared_file_tag` ( + `tag_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '标签id', + `tag_name` varchar(255) DEFAULT NULL COMMENT '标签真实名称', + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者ID', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者ID', + PRIMARY KEY (`tag_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1963072518379114497 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='共享文件标签表'; + + +-- rpa.shared_sub_var definition + +CREATE TABLE `shared_sub_var` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '子变量id', + `shared_var_id` bigint(20) unsigned NOT NULL COMMENT '共享变量id', + `var_name` varchar(255) DEFAULT NULL COMMENT '子变量名', + `var_type` varchar(20) DEFAULT NULL COMMENT '变量类型:text/password/array', + `var_value` varchar(750) DEFAULT NULL COMMENT '变量具体值,加密则为密文,否则为明文', + `encrypt` tinyint(1) DEFAULT NULL COMMENT '是否加密:1-加密', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_shared_var_id` (`shared_var_id`) +) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='共享变量-子变量'; + + +-- rpa.shared_var definition + +CREATE TABLE `shared_var` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `shared_var_name` varchar(255) DEFAULT NULL COMMENT '共享变量名', + `status` tinyint(1) DEFAULT NULL COMMENT '启用状态:1启用', + `remark` varchar(255) DEFAULT NULL COMMENT '变量说明', + `dept_id` char(36) DEFAULT NULL COMMENT '所屬部门ID', + `usage_type` varchar(10) DEFAULT NULL COMMENT '可使用账号类别(all/dept/select):所有人:all、所属部门所有人:dept、指定人:select', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `shared_var_type` varchar(20) DEFAULT NULL COMMENT '共享变量类型:text/password/array/group', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_dept_id_path` (`dept_id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='共享变量信息'; + + +-- rpa.shared_var_key_tenant definition + +CREATE TABLE `shared_var_key_tenant` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `tenant_id` varchar(36) NOT NULL, + `key` varchar(500) DEFAULT NULL COMMENT '共享变量租户密钥', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_tenant_id` (`tenant_id`) +) ENGINE=InnoDB AUTO_INCREMENT=1967981807948963842 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='共享变量租户密钥表'; + + +-- rpa.shared_var_user definition + +CREATE TABLE `shared_var_user` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `shared_var_id` bigint(20) unsigned NOT NULL COMMENT '共享变量id', + `user_id` char(36) DEFAULT NULL COMMENT '用户id', + `user_name` varchar(100) DEFAULT NULL COMMENT '用户姓名', + `user_phone` varchar(100) DEFAULT NULL COMMENT '用户手机号', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_shared_var_id` (`shared_var_id`), + KEY `idx_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='共享变量与用户的映射表;N:N映射'; + + +-- rpa.sms_record definition + +CREATE TABLE `sms_record` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID', + `receiver` varchar(30) CHARACTER SET utf8 DEFAULT NULL COMMENT '短信接收者', + `send_type` varchar(30) CHARACTER SET utf8 DEFAULT NULL COMMENT '短信类型', + `send_result` varchar(20) CHARACTER SET utf8 DEFAULT NULL COMMENT '发送结果', + `fail_reason` varchar(3000) CHARACTER SET utf8 DEFAULT NULL COMMENT '失败原因', + `create_by` int(11) DEFAULT NULL COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` int(11) DEFAULT NULL COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `deleted` int(11) DEFAULT NULL COMMENT '是否已删除', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + +-- rpa.task_mail definition + +CREATE TABLE `task_mail` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `user_id` char(36) DEFAULT NULL, + `tenant_id` char(36) DEFAULT NULL, + `resource_id` varchar(255) DEFAULT NULL, + `email_service` varchar(50) DEFAULT NULL COMMENT '邮箱服务器,163Email、126Email、qqEmail、customEmail', + `email_protocol` varchar(50) DEFAULT NULL COMMENT '使用协议,POP3,IMAP', + `email_service_address` varchar(255) DEFAULT NULL COMMENT '邮箱服务器地址', + `port` varchar(50) DEFAULT NULL COMMENT '邮箱服务器端口', + `enable_ssl` tinyint(1) DEFAULT NULL COMMENT '是否使用SSL', + `email_account` varchar(255) DEFAULT NULL COMMENT '邮箱账号', + `authorization_code` varchar(255) DEFAULT NULL COMMENT '邮箱授权码', + `deleted` tinyint(1) DEFAULT '0' COMMENT '是否删除', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + +-- rpa.terminal definition + +CREATE TABLE `terminal` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id,用于数据定时统计的进度管理', + `terminal_id` char(36) NOT NULL COMMENT '终端唯一标识,如设备mac地址', + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `dept_id` varchar(100) DEFAULT NULL COMMENT '部门id', + `dept_id_path` varchar(100) DEFAULT NULL COMMENT '部门全路径id', + `name` varchar(200) DEFAULT NULL COMMENT '终端名称', + `account` varchar(100) DEFAULT NULL COMMENT '设备账号', + `os` varchar(50) DEFAULT NULL COMMENT '操作系统', + `ip` varchar(200) DEFAULT NULL COMMENT 'ip列表', + `actual_client_ip` varchar(100) DEFAULT NULL COMMENT '实际连接源IP,服务端检测后的推荐ip', + `custom_ip` varchar(20) DEFAULT NULL COMMENT '用户自定义ip', + `port` int(11) DEFAULT NULL COMMENT '端口', + `status` varchar(20) DEFAULT NULL COMMENT '当前状态,运行中busy,空闲free,离线offline,单机中standalone', + `remark` varchar(100) DEFAULT NULL COMMENT '终端描述', + `user_id` varchar(100) DEFAULT NULL COMMENT '最后登录的用户的id,用于根据姓名筛选', + `os_name` char(36) DEFAULT NULL COMMENT '信息维护:电脑设备用户名', + `os_pwd` varchar(200) DEFAULT NULL COMMENT '信息维护:电脑设备用户密码', + `is_dispatch` smallint(6) DEFAULT NULL COMMENT '是否调度模式', + `monitor_url` varchar(100) DEFAULT NULL COMMENT '视频监控url', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '终端记录创建时间', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) NOT NULL DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `custom_port` int(11) DEFAULT NULL COMMENT '自定义端口', + PRIMARY KEY (`id`), + KEY `cloud_terminal_mac_tenant_index` (`tenant_id`), + KEY `cloud_terminal_tenant_id_IDX` (`tenant_id`,`dept_id_path`), + KEY `cloud_terminal_user_id_IDX` (`os_name`) +) ENGINE=InnoDB AUTO_INCREMENT=54 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='终端表'; + + +-- rpa.terminal_group definition + +CREATE TABLE `terminal_group` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `group_id` bigint(20) DEFAULT NULL COMMENT '分组名', + `terminal_id` bigint(20) DEFAULT NULL COMMENT '终端id', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_group_id` (`group_id`), + KEY `idx_terminal_id` (`terminal_id`) +) ENGINE=InnoDB AUTO_INCREMENT=95 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='终端分组-分组与终端的映射表;N:N映射'; + + +-- rpa.terminal_group_info definition + +CREATE TABLE `terminal_group_info` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `group_name` varchar(100) DEFAULT NULL COMMENT '分组名', + `terminal_id` varchar(20) DEFAULT NULL COMMENT '终端id', + `dept_id` char(36) DEFAULT NULL COMMENT '所屬部门ID', + `usage_type` varchar(10) DEFAULT NULL COMMENT '可使用账号类别(all/dept/select):所有人:all、所属部门所有人:dept、指定人:select', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_terminal_id` (`terminal_id`), + KEY `idx_dept_id_path` (`dept_id`) +) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='终端分组'; + + +-- rpa.terminal_group_user definition + +CREATE TABLE `terminal_group_user` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `group_id` varchar(20) DEFAULT NULL COMMENT '分组名', + `user_id` char(36) DEFAULT NULL COMMENT '用户id', + `creator_id` char(36) DEFAULT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` char(36) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + `user_name` varchar(100) DEFAULT NULL COMMENT '用户姓名', + `user_phone` varchar(100) DEFAULT NULL COMMENT '用户手机号', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_group_id` (`group_id`), + KEY `idx_user_id` (`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=54 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='终端分组-分组与用户的映射表;N:N映射'; + + +-- rpa.terminal_login_history definition + +CREATE TABLE `terminal_login_history` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `terminal_id` varchar(20) DEFAULT NULL COMMENT '终端id', + `account` varchar(100) DEFAULT NULL COMMENT '账号', + `user_name` varchar(100) DEFAULT NULL COMMENT '用户名', + `login_time` timestamp NULL DEFAULT NULL COMMENT '登录时间', + `logout_time` timestamp NULL DEFAULT NULL COMMENT '登出时间', + `creator_id` bigint(20) DEFAULT NULL COMMENT '创建者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` bigint(20) DEFAULT NULL COMMENT '更新者id', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='终端登录账号历史记录'; + + +-- rpa.terminal_login_record definition + +CREATE TABLE `terminal_login_record` ( + `id` char(36) COLLATE utf8mb4_bin NOT NULL, + `login_time` timestamp NULL DEFAULT NULL COMMENT '登录时间', + `logout_time` timestamp NULL DEFAULT NULL COMMENT '登出时间', + `terminal_id` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '终端id', + `dept_id` char(36) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '部门id', + `dept_id_path` varchar(100) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '部门全路径id', + `ip` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `login_status` int(11) NOT NULL COMMENT '是否登录成功{0:登录失败,1:登录成功}', + `remark` varchar(1000) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '操作描述', + `creator_id` char(36) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '创建者id', + `updater_id` char(36) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '更新者id', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` smallint(1) DEFAULT '0' COMMENT '是否删除 0:未删除,1:已删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COLLATE=utf8mb4_bin COMMENT='终端登录账号历史记录'; + + +-- rpa.trigger_task definition + +CREATE TABLE `trigger_task` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `task_id` bigint(20) DEFAULT NULL COMMENT '触发器计划任务id', + `name` varchar(50) DEFAULT NULL COMMENT '触发器计划任务名称', + `task_json` mediumtext COMMENT '构建计划任务的灵活参数', + `creator_id` char(36) DEFAULT NULL, + `updater_id` char(36) DEFAULT NULL, + `deleted` smallint(1) NOT NULL DEFAULT '0', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', + `task_type` varchar(20) DEFAULT NULL COMMENT '任务类型:定时schedule、邮件mail、文件file、热键hotKey:', + `enable` smallint(1) NOT NULL DEFAULT '0' COMMENT '是否启用', + `exceptional` varchar(20) NOT NULL DEFAULT 'stop' COMMENT '报错如何处理:跳过jump、停止stop', + `timeout` int(10) DEFAULT '9999' COMMENT '超时时间', + `tenant_id` char(36) DEFAULT NULL COMMENT '租户id', + `queue_enable` smallint(6) DEFAULT '0' COMMENT '是否启用排队 1:启用 0:不启用', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=194 DEFAULT CHARSET=utf8 COMMENT='触发器计划任务'; \ No newline at end of file diff --git a/docker/astronAgent/astronRPA/volumes/nginx/default.conf b/docker/astronAgent/astronRPA/volumes/nginx/default.conf new file mode 100644 index 0000000000000000000000000000000000000000..ec1b5de8f6c1890a858b2690bb588d426709baac --- /dev/null +++ b/docker/astronAgent/astronRPA/volumes/nginx/default.conf @@ -0,0 +1,150 @@ +# nginx.conf +resolver 127.0.0.11 valid=5s; + +# 模块加载路径,确保 OpenResty 能找到 resty.* 模块 +lua_package_path "/usr/local/openresty/lualib/?.lua;;;/usr/local/openresty/nginx/lua/?.lua;;"; +# 启用 LuaJIT 内存共享,用于存储一些全局配置或缓存(如果需要的话) +lua_shared_dict my_cache 10m; + +# 错误日志级别设置为 debug,以便查看 Lua 脚本的详细调试信息 +# 在生产环境中,可以切换到 info 或 warn +error_log /usr/local/openresty/nginx/logs/error.log error; # <-- !!! 调试关键 !!! + +# 上游服务定义,保持不变 +upstream resource-service { + server resource-service:8030; + keepalive 32; +} + +upstream robot-service { + server robot-service:8040; + keepalive 32; +} + +upstream ai-service { + server ai-service:8010; + keepalive 32; +} + +upstream openapi-service { + server openapi-service:8020; + keepalive 32; +} + +upstream casdoor { + server casdoor:8000; + keepalive 32; +} + +server { + listen 80; + server_name localhost; + + # 通用配置 + client_max_body_size 100M; + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # 定义一个方便在 Lua 脚本中判断当前上下文类型的变量 + set $context_type "HTTP"; + + # resource-service 路由 + location /api/resource/ { + access_by_lua_file lua/auth_handler.lua; # 调用外部 Lua 认证脚本 + + proxy_pass http://resource-service; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_connect_timeout 10s; + proxy_send_timeout 10s; + proxy_read_timeout 10s; + } + + # robot-service 路由 + # 默认不对此路由进行认证,以避免认证服务自身的循环调用 + # 如果需要保护 robot-service 的其他接口(排除 /user/info),则需要更细的粒度控制 + location /api/robot/ { + # 如果需要认证 /api/robot/ 其他接口,但排除 /user/info + # if ($request_uri != "/api/robot/user/info") { + # access_by_lua_file lua/auth_handler.lua; + # } + + proxy_pass http://robot-service; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + # ai-service 路由 + location /api/rpa-ai-service/ { + access_by_lua_file lua/auth_handler.lua; # 调用外部 Lua 认证脚本 + + rewrite ^/api/rpa-ai-service/(.*)$ /$1 break; + proxy_pass http://ai-service; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_connect_timeout 600s; + proxy_send_timeout 600s; + proxy_read_timeout 600s; + } + + # openapi-service 路由 + # WebSocket 专用 location + location /api/rpa-openapi/ws { + # 为 WebSocket 认证设置上下文类型 + set $context_type "WebSocket"; + access_by_lua_file lua/auth_handler.lua; # 调用外部 Lua 认证脚本 + + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; # WebSocket 升级需要 + proxy_http_version 1.1; + proxy_read_timeout 60s; + + rewrite ^/api/rpa-openapi/(.*)$ /$1 break; + proxy_pass http://openapi-service; + } + # 通用 API location + location /api/rpa-openapi/ { + access_by_lua_file lua/auth_handler.lua; # 调用外部 Lua 认证脚本 + + rewrite ^/api/rpa-openapi/(.*)$ /$1 break; + proxy_pass http://openapi-service; + proxy_connect_timeout 600s; + proxy_send_timeout 600s; + proxy_read_timeout 600s; + } + + # casdoor 路由 + location /api/casdoor/ { + rewrite ^/api/casdoor/(.*)$ /$1 break; + proxy_pass http://casdoor; + proxy_connect_timeout 600s; + proxy_send_timeout 600s; + proxy_read_timeout 600s; + } + + # 健康检查 + location /health { + access_log off; + return 200 "healthy\n"; + add_header Content-Type text/plain; + } + + # 处理 favicon.ico 请求 + location /favicon.ico { + access_log off; + return 204; + } + + # 默认路由 + location / { + return 404 "Not Found"; + } +} diff --git a/docker/astronAgent/astronRPA/volumes/nginx/lua/auth_handler.lua b/docker/astronAgent/astronRPA/volumes/nginx/lua/auth_handler.lua new file mode 100644 index 0000000000000000000000000000000000000000..ef19db0c30aee104a71ad26dc6f2aaef90633ed0 --- /dev/null +++ b/docker/astronAgent/astronRPA/volumes/nginx/lua/auth_handler.lua @@ -0,0 +1,165 @@ +-- lua/auth_handler.lua + +local http = require("resty.http") +local json = require("cjson") +local ngx_log = ngx.log +local ngx_DEBUG = ngx.DEBUG -- 用于详细调试 +local ngx_ERR = ngx.ERR +local ngx_WARN = ngx.WARN +local ngx_HTTP_OK = ngx.HTTP_OK +local ngx_HTTP_UNAUTHORIZED = ngx.HTTP_UNAUTHORIZED +local ngx_HTTP_INTERNAL_SERVER_ERROR = ngx.HTTP_INTERNAL_SERVER_ERROR + +-- 定义一个函数来处理认证逻辑 +local function authenticate_user() + local ctx_type = ngx.var.context_type or "HTTP" + ngx_log(ngx_DEBUG, "Starting authentication for " .. ctx_type .. " request. URI: " .. ngx.var.request_uri) + + local session_token = nil + + -- 1. 尝试从 Authorization header 获取 Bearer Token + local authorization_header = ngx.req.get_headers()["authorization"] -- 注意,headers 都是小写键 + if authorization_header then + ngx_log(ngx_DEBUG, "Found Authorization header: " .. authorization_header) + local _, _, token_type, token_value = string.find(authorization_header, "^(%S+)%s+(.+)$") + if token_type and token_type:lower() == "bearer" then + -- session_token = token_value + -- ngx_log(ngx_DEBUG, "Extracted Bearer Token from Authorization header: " .. session_token) + return + else + ngx_log(ngx_DEBUG, "Authorization header is present but not Bearer type, type: " .. (token_type or "nil")) + end + else + ngx_log(ngx_DEBUG, "No Authorization header found.") + end + + -- 2. 如果 Authorization header 没有,尝试从自定义 'token' header 获取 (例如 X-Token 或 Token) + -- 假设你的 'http_token' 对应的是名为 'Token' 的自定义头 + if not session_token then + local custom_token_header = ngx.req.get_headers()["token"] + if custom_token_header then + session_token = custom_token_header + ngx_log(ngx_DEBUG, "Extracted Token from custom 'Token' header: " .. session_token) + else + ngx_log(ngx_DEBUG, "No custom 'Token' header found.") + end + end + + -- 3. 如果还没有token,尝试从Cookie中获取 JSESSIONID + if not session_token then + local cookie_header = ngx.var.http_cookie + if cookie_header then + ngx_log(ngx_DEBUG, "Found Cookie header: " .. cookie_header) + -- 解析Cookie,查找JSESSIONID + for cookie_pair in string.gmatch(cookie_header, "[^;]+") do + local cookie_name, cookie_value = string.match(cookie_pair, "^%s*(.-)%s*=%s*(.-)%s*$") + if cookie_name == "JSESSIONID" then + session_token = cookie_value + ngx_log(ngx_DEBUG, "Extracted Token from Cookie JSESSIONID: " .. session_token) + break + end + end + if not session_token then + ngx_log(ngx_DEBUG, "Cookie header present but no JSESSIONID found.") + end + else + ngx_log(ngx_DEBUG, "No Cookie header found.") + end + end + + if not session_token or session_token == "" or session_token == " " then + ngx_log(ngx_ERR, "Missing SESSION/Token in " .. ctx_type .. " request after trying all sources.") + ngx.status = ngx_HTTP_UNAUTHORIZED + ngx.say(json.encode({code = "4001", msg = "Missing SESSION/Token in request"})) + return ngx.exit(ngx_HTTP_UNAUTHORIZED) + end + + ngx_log(ngx_DEBUG, "Successfully extracted session_token: '" .. session_token .. "'") + + -- 调用 robot-service 进行认证 + local getUserUrl = "http://robot-service:8040/api/robot/user/now/userinfo" + local httpc = http.new() + + -- 准备发送给 robot-service 的 Headers + -- 使用Cookie方式传递JSESSIONID给robot-service + local headers_to_robot_service = { + ["Content-Type"] = "application/json", + -- 示例:如果 robot-service 期望 Authorization 头 + -- ["Authorization"] = "Bearer " .. session_token, + -- 或者,如果 robot-service 期望 Token 在 Cookie 里: + -- ["Cookie"] = "SESSION=" .. session_token + ["Cookie"] = "JSESSIONID=" .. session_token + } + + ngx_log(ngx_DEBUG, "Calling robot-service (" .. getUserUrl .. ") with headers: " .. json.encode(headers_to_robot_service)) + + local res, err = httpc:request_uri(getUserUrl, { + method = "GET", + headers = headers_to_robot_service, + ssl_verify_host = false, -- 内部通信通常不需要 SSL 验证 + ssl_verify_peer = false, + read_timeout = 5000, + connect_timeout = 5000 + }) + + if err then + ngx_log(ngx_ERR, "Failed to connect to robot-service for " .. ctx_type .. " auth: " .. err .. ", URL: " .. getUserUrl) + ngx.status = ngx_HTTP_INTERNAL_SERVER_ERROR + ngx.say(json.encode({code = "5000", message = "Internal Server Error: Auth service unavailable"})) + return ngx.exit(ngx_HTTP_INTERNAL_SERVER_ERROR) + end + + ngx_log(ngx_DEBUG, "robot-service response status: " .. res.status .. ", body (first 200 chars): " .. (res.body and string.sub(res.body, 1, 200) or "No body")) + + if res.status ~= ngx_HTTP_OK then + ngx_log(ngx_ERR, "robot-service returned unexpected status " .. res.status .. " for " .. ctx_type .. " auth, full body: " .. (res.body or "No body")) + ngx.status = res.status + ngx.say(res.body) -- 将 robot-service 的错误响应直接返回 + return ngx.exit(res.status) + end + + local userResponse, json_err = json.decode(res.body) + if json_err then + ngx_log(ngx_ERR, "Failed to decode robot-service response for " .. ctx_type .. " auth: " .. json_err .. ", full body: " .. (res.body or "No body")) + ngx.status = ngx_HTTP_INTERNAL_SERVER_ERROR + ngx.say(json.encode({code = "5000", message = "Internal Server Error: Invalid auth service response"})) + return ngx.exit(ngx_HTTP_INTERNAL_SERVER_ERROR) + end + + ngx_log(ngx_DEBUG, "Decoded robot-service response: " .. json.encode(userResponse)) + + if userResponse.code ~= 200 then + ngx_log(ngx_ERR, "robot-service returned error code: " .. (userResponse.code or "nil") .. ", message: " .. (userResponse.message or "nil") .. " for " .. ctx_type .. " auth. Full response: " .. json.encode(userResponse)) + ngx.status = ngx_HTTP_UNAUTHORIZED + ngx.say(json.encode({ + code = userResponse.code or "U_AUTH_FAIL", + data = userResponse.data, + message = userResponse.status or "Authentication failed by robot-service" + })) + return ngx.exit(ngx_HTTP_UNAUTHORIZED) + end + + local user_id = userResponse.data and userResponse.data["id"] + if not user_id then + ngx_log(ngx_ERR, "robot-service response missing 'id' in 'data' field for " .. ctx_type .. " auth: " .. json.encode(userResponse)) + ngx.status = ngx_HTTP_INTERNAL_SERVER_ERROR + ngx.say(json.encode({code = "5000", message = "Internal Server Error: Auth service response missing user_id"})) + return ngx.exit(ngx_HTTP_INTERNAL_SERVER_ERROR) + end + + ngx_log(ngx_WARN, "User authenticated successfully. user_id: " .. user_id .. " in " .. ctx_type .. " context. Setting headers.") + ngx.req.set_header("user_id", user_id) + ngx.req.set_header("user-info", json.encode({id = user_id})) + + return true -- 认证成功 +end + +-- 在 access_by_lua_file 执行时,脚本会直接运行。 +-- 所以我们需要直接调用 authenticate_user 函数。 +local _M = { + authenticate_user = authenticate_user +} + +_M.authenticate_user() + +return _M diff --git a/docker/astronAgent/astronRPA/volumes/nginx/lua/resty/http.lua b/docker/astronAgent/astronRPA/volumes/nginx/lua/resty/http.lua new file mode 100644 index 0000000000000000000000000000000000000000..a85f85af7c07f63d35ab1f8bf726f1aa3d38cbc3 --- /dev/null +++ b/docker/astronAgent/astronRPA/volumes/nginx/lua/resty/http.lua @@ -0,0 +1,1185 @@ +local http_headers = require "resty.http_headers" + +local ngx = ngx +local ngx_socket_tcp = ngx.socket.tcp +local ngx_req = ngx.req +local ngx_req_socket = ngx_req.socket +local ngx_req_get_headers = ngx_req.get_headers +local ngx_req_get_method = ngx_req.get_method +local str_lower = string.lower +local str_upper = string.upper +local str_find = string.find +local str_sub = string.sub +local tbl_concat = table.concat +local tbl_insert = table.insert +local ngx_encode_args = ngx.encode_args +local ngx_re_match = ngx.re.match +local ngx_re_gmatch = ngx.re.gmatch +local ngx_re_sub = ngx.re.sub +local ngx_re_gsub = ngx.re.gsub +local ngx_re_find = ngx.re.find +local ngx_log = ngx.log +local ngx_DEBUG = ngx.DEBUG +local ngx_ERR = ngx.ERR +local ngx_var = ngx.var +local ngx_print = ngx.print +local ngx_header = ngx.header +local co_yield = coroutine.yield +local co_create = coroutine.create +local co_status = coroutine.status +local co_resume = coroutine.resume +local setmetatable = setmetatable +local tonumber = tonumber +local tostring = tostring +local unpack = unpack +local rawget = rawget +local select = select +local ipairs = ipairs +local pairs = pairs +local pcall = pcall +local type = type + + +-- http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1 +local HOP_BY_HOP_HEADERS = { + ["connection"] = true, + ["keep-alive"] = true, + ["proxy-authenticate"] = true, + ["proxy-authorization"] = true, + ["te"] = true, + ["trailers"] = true, + ["transfer-encoding"] = true, + ["upgrade"] = true, + ["content-length"] = true, -- Not strictly hop-by-hop, but Nginx will deal + -- with this (may send chunked for example). +} + + +local EXPECTING_BODY = { + POST = true, + PUT = true, + PATCH = true, +} + + +-- Reimplemented coroutine.wrap, returning "nil, err" if the coroutine cannot +-- be resumed. This protects user code from infinite loops when doing things like +-- repeat +-- local chunk, err = res.body_reader() +-- if chunk then -- <-- This could be a string msg in the core wrap function. +-- ... +-- end +-- until not chunk +local co_wrap = function(func) + local co = co_create(func) + if not co then + return nil, "could not create coroutine" + else + return function(...) + if co_status(co) == "suspended" then + return select(2, co_resume(co, ...)) + else + return nil, "can't resume a " .. co_status(co) .. " coroutine" + end + end + end +end + + +-- Returns a new table, recursively copied from the one given. +-- +-- @param table table to be copied +-- @return table +local function tbl_copy(orig) + local orig_type = type(orig) + local copy + if orig_type == "table" then + copy = {} + for orig_key, orig_value in next, orig, nil do + copy[tbl_copy(orig_key)] = tbl_copy(orig_value) + end + else -- number, string, boolean, etc + copy = orig + end + return copy +end + + +local _M = { + _VERSION = '0.17.2', +} +_M._USER_AGENT = "lua-resty-http/" .. _M._VERSION .. " (Lua) ngx_lua/" .. ngx.config.ngx_lua_version + +local mt = { __index = _M } + + +local HTTP = { + [1.0] = " HTTP/1.0\r\n", + [1.1] = " HTTP/1.1\r\n", +} + + +local DEFAULT_PARAMS = { + method = "GET", + path = "/", + version = 1.1, +} + + +local DEBUG = false + + +function _M.new(_) + local sock, err = ngx_socket_tcp() + if not sock then + return nil, err + end + return setmetatable({ sock = sock, keepalive = true }, mt) +end + + +function _M.debug(d) + DEBUG = (d == true) +end + + +function _M.set_timeout(self, timeout) + local sock = self.sock + if not sock then + return nil, "not initialized" + end + + return sock:settimeout(timeout) +end + + +function _M.set_timeouts(self, connect_timeout, send_timeout, read_timeout) + local sock = self.sock + if not sock then + return nil, "not initialized" + end + + return sock:settimeouts(connect_timeout, send_timeout, read_timeout) +end + +do + local aio_connect = require "resty.http_connect" + -- Function signatures to support: + -- ok, err, ssl_session = httpc:connect(options_table) + -- ok, err = httpc:connect(host, port, options_table?) + -- ok, err = httpc:connect("unix:/path/to/unix.sock", options_table?) + function _M.connect(self, options, ...) + if type(options) == "table" then + -- all-in-one interface + return aio_connect(self, options) + else + -- backward compatible + return self:tcp_only_connect(options, ...) + end + end +end + +function _M.tcp_only_connect(self, ...) + ngx_log(ngx_DEBUG, "Use of deprecated `connect` method signature") + + local sock = self.sock + if not sock then + return nil, "not initialized" + end + + self.host = select(1, ...) + self.port = select(2, ...) + + -- If port is not a number, this is likely a unix domain socket connection. + if type(self.port) ~= "number" then + self.port = nil + end + + self.keepalive = true + self.ssl = false + + return sock:connect(...) +end + + +function _M.set_keepalive(self, ...) + local sock = self.sock + if not sock then + return nil, "not initialized" + end + + if self.keepalive == true then + return sock:setkeepalive(...) + else + -- The server said we must close the connection, so we cannot setkeepalive. + -- If close() succeeds we return 2 instead of 1, to differentiate between + -- a normal setkeepalive() failure and an intentional close(). + local res, err = sock:close() + if res then + return 2, "connection must be closed" + else + return res, err + end + end +end + + +function _M.get_reused_times(self) + local sock = self.sock + if not sock then + return nil, "not initialized" + end + + return sock:getreusedtimes() +end + + +function _M.close(self) + local sock = self.sock + if not sock then + return nil, "not initialized" + end + + return sock:close() +end + + +local function _should_receive_body(method, code) + if method == "HEAD" then return nil end + if code == 204 or code == 304 then return nil end + if code >= 100 and code < 200 then return nil end + return true +end + + +function _M.parse_uri(_, uri, query_in_path) + if query_in_path == nil then query_in_path = true end + + local m, err = ngx_re_match( + uri, + [[^(?:(http[s]?):)?//((?:[^\[\]:/\?]+)|(?:\[.+\]))(?::(\d+))?([^\?]*)\??(.*)]], + "jo" + ) + + if not m then + if err then + return nil, "failed to match the uri: " .. uri .. ", " .. err + end + + return nil, "bad uri: " .. uri + else + -- If the URI is schemaless (i.e. //example.com) try to use our current + -- request scheme. + if not m[1] then + -- Schema-less URIs can occur in client side code, implying "inherit + -- the schema from the current request". We support it for a fairly + -- specific case; if for example you are using the ESI parser in + -- ledge (https://github.com/ledgetech/ledge) to perform in-flight + -- sub requests on the edge based on instructions found in markup, + -- those URIs may also be schemaless with the intention that the + -- subrequest would inherit the schema just like JavaScript would. + local scheme = ngx_var.scheme + if scheme == "http" or scheme == "https" then + m[1] = scheme + else + return nil, "schemaless URIs require a request context: " .. uri + end + end + + if m[3] then + m[3] = tonumber(m[3]) + else + if m[1] == "https" then + m[3] = 443 + else + m[3] = 80 + end + end + if not m[4] or "" == m[4] then m[4] = "/" end + + if query_in_path and m[5] and m[5] ~= "" then + m[4] = m[4] .. "?" .. m[5] + m[5] = nil + end + + return m, nil + end +end + + +local function _format_request(self, params) + local version = params.version + local headers = params.headers or {} + + local query = params.query or "" + if type(query) == "table" then + query = ngx_encode_args(query) + end + + if query ~= "" and str_sub(query, 1, 1) ~= "?" then + query = "?" .. query + end + + -- Initialize request + local req = { + str_upper(params.method), + " ", + self.path_prefix or "", + params.path, + query, + HTTP[version], + -- Pre-allocate slots for minimum headers and carriage return. + true, + true, + true, + } + local c = 7 -- req table index it's faster to do this inline vs table.insert + + -- Append headers + for key, values in pairs(headers) do + key = tostring(key) + + if type(values) == "table" then + for _, value in pairs(values) do + req[c] = key .. ": " .. tostring(value) .. "\r\n" + c = c + 1 + end + + else + req[c] = key .. ": " .. tostring(values) .. "\r\n" + c = c + 1 + end + end + + -- Close headers + req[c] = "\r\n" + + return tbl_concat(req) +end + + +local function _receive_status(sock) + local line, err = sock:receive("*l") + if not line then + return nil, nil, nil, err + end + + local version = tonumber(str_sub(line, 6, 8)) + if not version then + return nil, nil, nil, + "couldn't parse HTTP version from response status line: " .. line + end + + local status = tonumber(str_sub(line, 10, 12)) + if not status then + return nil, nil, nil, + "couldn't parse status code from response status line: " .. line + end + + local reason = str_sub(line, 14) + + return status, version, reason +end + + +local function _receive_headers(sock) + local headers = http_headers.new() + + repeat + local line, err = sock:receive("*l") + if not line then + return nil, err + end + + local m, err = ngx_re_match(line, "([^:\\s]+):\\s*(.*)", "jo") + if err then ngx_log(ngx_ERR, err) end + + if not m then + break + end + + local key = m[1] + local val = m[2] + if headers[key] then + if type(headers[key]) ~= "table" then + headers[key] = { headers[key] } + end + tbl_insert(headers[key], tostring(val)) + else + headers[key] = tostring(val) + end + until ngx_re_find(line, "^\\s*$", "jo") + + return headers, nil +end + + +local function transfer_encoding_is_chunked(headers) + local te = headers["Transfer-Encoding"] + if not te then + return false + end + + -- Handle duplicate headers + -- This shouldn't happen but can in the real world + if type(te) ~= "string" then + te = tbl_concat(te, ",") + end + + return str_find(str_lower(te), "chunked", 1, true) ~= nil +end +_M.transfer_encoding_is_chunked = transfer_encoding_is_chunked + + +local function _chunked_body_reader(sock, default_chunk_size) + return co_wrap(function(max_chunk_size) + local remaining = 0 + local length + max_chunk_size = max_chunk_size or default_chunk_size + + repeat + -- If we still have data on this chunk + if max_chunk_size and remaining > 0 then + + if remaining > max_chunk_size then + -- Consume up to max_chunk_size + length = max_chunk_size + remaining = remaining - max_chunk_size + else + -- Consume all remaining + length = remaining + remaining = 0 + end + else -- This is a fresh chunk + + -- Receive the chunk size + local str, err = sock:receive("*l") + if not str then + co_yield(nil, err) + end + + length = tonumber(str, 16) + + if not length then + co_yield(nil, "unable to read chunksize") + end + + if max_chunk_size and length > max_chunk_size then + -- Consume up to max_chunk_size + remaining = length - max_chunk_size + length = max_chunk_size + end + end + + if length > 0 then + local str, err = sock:receive(length) + if not str then + co_yield(nil, err) + end + + max_chunk_size = co_yield(str) or default_chunk_size + + -- If we're finished with this chunk, read the carriage return. + if remaining == 0 then + sock:receive(2) -- read \r\n + end + else + -- Read the last (zero length) chunk's carriage return + sock:receive(2) -- read \r\n + end + + until length == 0 + end) +end + + +local function _body_reader(sock, content_length, default_chunk_size) + return co_wrap(function(max_chunk_size) + max_chunk_size = max_chunk_size or default_chunk_size + + if not content_length and max_chunk_size then + -- We have no length, but wish to stream. + -- HTTP 1.0 with no length will close connection, so read chunks to the end. + repeat + local str, err, partial = sock:receive(max_chunk_size) + if not str and err == "closed" then + co_yield(partial, err) + end + + max_chunk_size = tonumber(co_yield(str) or default_chunk_size) + if max_chunk_size and max_chunk_size < 0 then max_chunk_size = nil end + + if not max_chunk_size then + ngx_log(ngx_ERR, "Buffer size not specified, bailing") + break + end + until not str + + elseif not content_length then + -- We have no length but don't wish to stream. + -- HTTP 1.0 with no length will close connection, so read to the end. + co_yield(sock:receive("*a")) + + elseif not max_chunk_size then + -- We have a length and potentially keep-alive, but want everything. + co_yield(sock:receive(content_length)) + + else + -- We have a length and potentially a keep-alive, and wish to stream + -- the response. + local received = 0 + repeat + local length = max_chunk_size + if received + length > content_length then + length = content_length - received + end + + if length > 0 then + local str, err = sock:receive(length) + if not str then + co_yield(nil, err) + end + received = received + length + + max_chunk_size = tonumber(co_yield(str) or default_chunk_size) + if max_chunk_size and max_chunk_size < 0 then max_chunk_size = nil end + + if not max_chunk_size then + ngx_log(ngx_ERR, "Buffer size not specified, bailing") + break + end + end + + until length == 0 + end + end) +end + + +local function _no_body_reader() + return nil +end + + +local function _read_body(res) + local reader = res.body_reader + + if not reader then + -- Most likely HEAD or 304 etc. + return nil, "no body to be read" + end + + local chunks = {} + local c = 1 + + local chunk, err + repeat + chunk, err = reader() + + if err then + return nil, err, tbl_concat(chunks) -- Return any data so far. + end + if chunk then + chunks[c] = chunk + c = c + 1 + end + until not chunk + + return tbl_concat(chunks) +end + + +local function _trailer_reader(sock) + return co_wrap(function() + co_yield(_receive_headers(sock)) + end) +end + + +local function _read_trailers(res) + local reader = res.trailer_reader + if not reader then + return nil, "no trailers" + end + + local trailers = reader() + setmetatable(res.headers, { __index = trailers }) +end + + +local function _send_body(sock, body) + if type(body) == "function" then + repeat + local chunk, err, partial = body() + + if chunk then + local ok, err = sock:send(chunk) + + if not ok then + return nil, err + end + elseif err ~= nil then + return nil, err, partial + end + + until chunk == nil + elseif body ~= nil then + local bytes, err = sock:send(body) + + if not bytes then + return nil, err + end + end + return true, nil +end + + +local function _handle_continue(sock, body) + local status, version, reason, err = _receive_status(sock) --luacheck: no unused + if not status then + return nil, nil, nil, err + end + + -- Only send body if we receive a 100 Continue + if status == 100 then + -- Read headers + local headers, err = _receive_headers(sock) + if not headers then + return nil, nil, nil, err + end + + local ok, err = _send_body(sock, body) + if not ok then + return nil, nil, nil, err + end + end + return status, version, reason, err +end + + +function _M.send_request(self, params) + -- Apply defaults + setmetatable(params, { __index = DEFAULT_PARAMS }) + + local sock = self.sock + local body = params.body + local headers = http_headers.new() + + -- We assign one-by-one so that the metatable can handle case insensitivity + -- for us. You can blame the spec for this inefficiency. + local params_headers = params.headers or {} + for k, v in pairs(params_headers) do + headers[k] = v + end + + if not headers["Proxy-Authorization"] then + -- TODO: next major, change this to always override the provided + -- header. Can't do that yet because it would be breaking. + -- The connect method uses self.http_proxy_auth in the poolname so + -- that should be leading. + headers["Proxy-Authorization"] = self.http_proxy_auth + end + + -- Ensure we have appropriate message length or encoding. + do + local is_chunked = transfer_encoding_is_chunked(headers) + + if is_chunked then + -- If we have both Transfer-Encoding and Content-Length we MUST + -- drop the Content-Length, to help prevent request smuggling. + -- https://tools.ietf.org/html/rfc7230#section-3.3.3 + headers["Content-Length"] = nil + + elseif not headers["Content-Length"] then + -- A length was not given, try to calculate one. + + local body_type = type(body) + + if body_type == "function" then + return nil, "Request body is a function but a length or chunked encoding is not specified" + + elseif body_type == "table" then + local length = 0 + for _, v in ipairs(body) do + length = length + #tostring(v) + end + headers["Content-Length"] = length + + elseif body == nil and EXPECTING_BODY[str_upper(params.method)] then + headers["Content-Length"] = 0 + + elseif body ~= nil then + headers["Content-Length"] = #tostring(body) + end + end + end + + if not headers["Host"] then + if (str_sub(self.host, 1, 5) == "unix:") then + return nil, "Unable to generate a useful Host header for a unix domain socket. Please provide one." + end + -- If we have a port (i.e. not connected to a unix domain socket), and this + -- port is non-standard, append it to the Host header. + if self.port then + if self.ssl and self.port ~= 443 then + headers["Host"] = self.host .. ":" .. self.port + elseif not self.ssl and self.port ~= 80 then + headers["Host"] = self.host .. ":" .. self.port + else + headers["Host"] = self.host + end + else + headers["Host"] = self.host + end + end + if not headers["User-Agent"] then + headers["User-Agent"] = _M._USER_AGENT + end + if params.version == 1.0 and not headers["Connection"] then + headers["Connection"] = "Keep-Alive" + end + + params.headers = headers + + -- Format and send request + local req = _format_request(self, params) + if DEBUG then ngx_log(ngx_DEBUG, "\n", req) end + local bytes, err = sock:send(req) + + if not bytes then + return nil, err + end + + -- Send the request body, unless we expect: continue, in which case + -- we handle this as part of reading the response. + if headers["Expect"] ~= "100-continue" then + local ok, err, partial = _send_body(sock, body) + if not ok then + return nil, err, partial + end + end + + return true +end + + +function _M.read_response(self, params) + local sock = self.sock + + local status, version, reason, err + + -- If we expect: continue, we need to handle this, sending the body if allowed. + -- If we don't get 100 back, then status is the actual status. + if params.headers["Expect"] == "100-continue" then + local _status, _version, _reason, _err = _handle_continue(sock, params.body) + if not _status then + return nil, _err + elseif _status ~= 100 then + status, version, reason, err = _status, _version, _reason, _err -- luacheck: no unused + end + end + + -- Just read the status as normal. + if not status then + status, version, reason, err = _receive_status(sock) + if not status then + return nil, err + end + end + + + local res_headers, err = _receive_headers(sock) + if not res_headers then + return nil, err + end + + -- keepalive is true by default. Determine if this is correct or not. + local ok, connection = pcall(str_lower, res_headers["Connection"]) + if ok then + if (version == 1.1 and str_find(connection, "close", 1, true)) or + (version == 1.0 and not str_find(connection, "keep-alive", 1, true)) then + self.keepalive = false + end + else + -- no connection header + if version == 1.0 then + self.keepalive = false + end + end + + local body_reader = _no_body_reader + local trailer_reader, err + local has_body = false + + -- Receive the body_reader + if _should_receive_body(params.method, status) then + has_body = true + + if version == 1.1 and transfer_encoding_is_chunked(res_headers) then + body_reader, err = _chunked_body_reader(sock) + else + local ok, length = pcall(tonumber, res_headers["Content-Length"]) + if not ok then + -- No content-length header, read until connection is closed by server + length = nil + end + + body_reader, err = _body_reader(sock, length) + end + end + + if res_headers["Trailer"] then + trailer_reader, err = _trailer_reader(sock) + end + + if err then + return nil, err + else + return { + status = status, + reason = reason, + headers = res_headers, + has_body = has_body, + body_reader = body_reader, + read_body = _read_body, + trailer_reader = trailer_reader, + read_trailers = _read_trailers, + } + end +end + + +function _M.request(self, params) + params = tbl_copy(params) -- Take by value + local res, err = self:send_request(params) + if not res then + return res, err + else + return self:read_response(params) + end +end + + +function _M.request_pipeline(self, requests) + requests = tbl_copy(requests) -- Take by value + + for _, params in ipairs(requests) do + if params.headers and params.headers["Expect"] == "100-continue" then + return nil, "Cannot pipeline request specifying Expect: 100-continue" + end + + local res, err = self:send_request(params) + if not res then + return res, err + end + end + + local responses = {} + for i, params in ipairs(requests) do + responses[i] = setmetatable({ + params = params, + response_read = false, + }, { + -- Read each actual response lazily, at the point the user tries + -- to access any of the fields. + __index = function(t, k) + local res, err + if t.response_read == false then + res, err = _M.read_response(self, t.params) + t.response_read = true + + if not res then + ngx_log(ngx_ERR, err) + else + for rk, rv in pairs(res) do + t[rk] = rv + end + end + end + return rawget(t, k) + end, + }) + end + return responses +end + + +function _M.request_uri(self, uri, params) + params = tbl_copy(params or {}) -- Take by value + if self.proxy_opts then + params.proxy_opts = tbl_copy(self.proxy_opts or {}) + end + + do + local parsed_uri, err = self:parse_uri(uri, false) + if not parsed_uri then + return nil, err + end + + local path, query + params.scheme, params.host, params.port, path, query = unpack(parsed_uri) + params.path = params.path or path + params.query = params.query or query + params.ssl_server_name = params.ssl_server_name or params.host + end + + do + local proxy_auth = (params.headers or {})["Proxy-Authorization"] + if proxy_auth and params.proxy_opts then + params.proxy_opts.https_proxy_authorization = proxy_auth + params.proxy_opts.http_proxy_authorization = proxy_auth + end + end + + local ok, err = self:connect(params) + if not ok then + return nil, err + end + + local res, err = self:request(params) + if not res then + self:close() + return nil, err + end + + local body, err = res:read_body() + if not body then + self:close() + return nil, err + end + + res.body = body + + if params.keepalive == false then + local ok, err = self:close() + if not ok then + ngx_log(ngx_ERR, err) + end + + else + local ok, err = self:set_keepalive(params.keepalive_timeout, params.keepalive_pool) + if not ok then + ngx_log(ngx_ERR, err) + end + + end + + return res, nil +end + + +function _M.get_client_body_reader(_, chunksize, sock) + chunksize = chunksize or 65536 + + if not sock then + local ok, err + ok, sock, err = pcall(ngx_req_socket) + + if not ok then + return nil, sock -- pcall err + end + + if not sock then + if err == "no body" then + return nil + else + return nil, err + end + end + end + + local headers = ngx_req_get_headers() + local length = headers.content_length + if length then + return _body_reader(sock, tonumber(length), chunksize) + elseif transfer_encoding_is_chunked(headers) then + -- Not yet supported by ngx_lua but should just work... + return _chunked_body_reader(sock, chunksize) + else + return nil + end +end + + +function _M.set_proxy_options(self, opts) + -- TODO: parse and cache these options, instead of parsing them + -- on each request over and over again (lru-cache on module level) + self.proxy_opts = tbl_copy(opts) -- Take by value +end + + +function _M.get_proxy_uri(self, scheme, host) + if not self.proxy_opts then + return nil + end + + -- Check if the no_proxy option matches this host. Implementation adapted + -- from lua-http library (https://github.com/daurnimator/lua-http) + if self.proxy_opts.no_proxy then + if self.proxy_opts.no_proxy == "*" then + -- all hosts are excluded + return nil + end + + local no_proxy_set = {} + -- wget allows domains in no_proxy list to be prefixed by "." + -- e.g. no_proxy=.mit.edu + for host_suffix in ngx_re_gmatch(self.proxy_opts.no_proxy, "\\.?([^,]+)", "jo") do + no_proxy_set[host_suffix[1]] = true + end + + -- From curl docs: + -- matched as either a domain which contains the hostname, or the + -- hostname itself. For example local.com would match local.com, + -- local.com:80, and www.local.com, but not www.notlocal.com. + -- + -- Therefore, we keep stripping subdomains from the host, compare + -- them to the ones in the no_proxy list and continue until we find + -- a match or until there's only the TLD left + repeat + if no_proxy_set[host] then + return nil + end + + -- Strip the next level from the domain and check if that one + -- is on the list + host = ngx_re_sub(host, "^[^.]+\\.", "", "jo") + until not ngx_re_find(host, "\\.", "jo") + end + + if scheme == "http" and self.proxy_opts.http_proxy then + return self.proxy_opts.http_proxy + end + + if scheme == "https" and self.proxy_opts.https_proxy then + return self.proxy_opts.https_proxy + end + + return nil +end + + +-- ---------------------------------------------------------------------------- +-- The following functions are considered DEPRECATED and may be REMOVED in +-- future releases. Please see the notes in `README.md`. +-- ---------------------------------------------------------------------------- + +function _M.ssl_handshake(self, ...) + ngx_log(ngx_DEBUG, "Use of deprecated function `ssl_handshake`") + + local sock = self.sock + if not sock then + return nil, "not initialized" + end + + self.ssl = true + + return sock:sslhandshake(...) +end + + +function _M.connect_proxy(self, proxy_uri, scheme, host, port, proxy_authorization) + ngx_log(ngx_DEBUG, "Use of deprecated function `connect_proxy`") + + -- Parse the provided proxy URI + local parsed_proxy_uri, err = self:parse_uri(proxy_uri, false) + if not parsed_proxy_uri then + return nil, err + end + + -- Check that the scheme is http (https is not supported for + -- connections between the client and the proxy) + local proxy_scheme = parsed_proxy_uri[1] + if proxy_scheme ~= "http" then + return nil, "protocol " .. proxy_scheme .. " not supported for proxy connections" + end + + -- Make the connection to the given proxy + local proxy_host, proxy_port = parsed_proxy_uri[2], parsed_proxy_uri[3] + local c, err = self:tcp_only_connect(proxy_host, proxy_port) + if not c then + return nil, err + end + + if scheme == "https" then + -- Make a CONNECT request to create a tunnel to the destination through + -- the proxy. The request-target and the Host header must be in the + -- authority-form of RFC 7230 Section 5.3.3. See also RFC 7231 Section + -- 4.3.6 for more details about the CONNECT request + local destination = host .. ":" .. port + local res, err = self:request({ + method = "CONNECT", + path = destination, + headers = { + ["Host"] = destination, + ["Proxy-Authorization"] = proxy_authorization, + } + }) + + if not res then + return nil, err + end + + if res.status < 200 or res.status > 299 then + return nil, "failed to establish a tunnel through a proxy: " .. res.status + end + end + + return c, nil +end + + +function _M.proxy_request(self, chunksize) + ngx_log(ngx_DEBUG, "Use of deprecated function `proxy_request`") + + return self:request({ + method = ngx_req_get_method(), + path = ngx_re_gsub(ngx_var.uri, "\\s", "%20", "jo") .. ngx_var.is_args .. (ngx_var.query_string or ""), + body = self:get_client_body_reader(chunksize), + headers = ngx_req_get_headers(), + }) +end + + +function _M.proxy_response(_, response, chunksize) + ngx_log(ngx_DEBUG, "Use of deprecated function `proxy_response`") + + if not response then + ngx_log(ngx_ERR, "no response provided") + return + end + + ngx.status = response.status + + -- Filter out hop-by-hop headeres + for k, v in pairs(response.headers) do + if not HOP_BY_HOP_HEADERS[str_lower(k)] then + ngx_header[k] = v + end + end + + local reader = response.body_reader + + repeat + local chunk, ok, read_err, print_err + + chunk, read_err = reader(chunksize) + if read_err then + ngx_log(ngx_ERR, read_err) + end + + if chunk then + ok, print_err = ngx_print(chunk) + if not ok then + ngx_log(ngx_ERR, print_err) + end + end + + if read_err or print_err then + break + end + until not chunk +end + + +return _M diff --git a/docker/astronAgent/astronRPA/volumes/nginx/lua/resty/http_connect.lua b/docker/astronAgent/astronRPA/volumes/nginx/lua/resty/http_connect.lua new file mode 100644 index 0000000000000000000000000000000000000000..83b6d2f4243a9faa32665a76fd92e760ed0d3b84 --- /dev/null +++ b/docker/astronAgent/astronRPA/volumes/nginx/lua/resty/http_connect.lua @@ -0,0 +1,341 @@ +local ffi = require "ffi" +local ngx_re_gmatch = ngx.re.gmatch +local ngx_re_sub = ngx.re.sub +local ngx_re_find = ngx.re.find +local ngx_log = ngx.log +local ngx_WARN = ngx.WARN +local ngx_DEBUG = ngx.DEBUG +local to_hex = require("resty.string").to_hex +local ffi_gc = ffi.gc +local ffi_cast = ffi.cast +local type = type + +local lib_chain, lib_x509, lib_pkey +local openssl_available, res = xpcall(function() + lib_chain = require("resty.openssl.x509.chain") + lib_x509 = require("resty.openssl.x509") + lib_pkey = require("resty.openssl.pkey") +end, debug.traceback) + +if not openssl_available then + ngx_log(ngx_WARN, "failed to load module `resty.openssl.*`, \z + mTLS isn't supported without lua-resty-openssl:\n", res) +end + +--[[ +A connection function that incorporates: + - tcp connect + - ssl handshake + - http proxy +Due to this it will be better at setting up a socket pool where connections can +be kept alive. + + +Call it with a single options table as follows: + +client:connect { + scheme = "https" -- scheme to use, or nil for unix domain socket + host = "myhost.com", -- target machine, or a unix domain socket + port = nil, -- port on target machine, will default to 80/443 based on scheme + pool = nil, -- connection pool name, leave blank! this function knows best! + pool_size = nil, -- options as per: https://github.com/openresty/lua-nginx-module#tcpsockconnect + backlog = nil, + + -- ssl options as per: https://github.com/openresty/lua-nginx-module#tcpsocksslhandshake + ssl_reused_session = nil + ssl_server_name = nil, + ssl_send_status_req = nil, + ssl_verify = true, -- NOTE: defaults to true + ctx = nil, -- NOTE: not supported + + -- mTLS options: These require support for mTLS in cosockets, which first + -- appeared in `ngx_http_lua_module` v0.10.23. + ssl_client_cert = nil, + ssl_client_priv_key = nil, + + proxy_opts, -- proxy opts, defaults to global proxy options +} +]] +local function connect(self, options) + local sock = self.sock + if not sock then + return nil, "not initialized" + end + + local ok, err + + local request_scheme = options.scheme + local request_host = options.host + local request_port = options.port + + local poolname = options.pool + local pool_size = options.pool_size + local backlog = options.backlog + + if request_scheme and not request_port then + request_port = (request_scheme == "https" and 443 or 80) + elseif request_port and not request_scheme then + return nil, "'scheme' is required when providing a port" + end + + -- ssl settings + local ssl, ssl_reused_session, ssl_server_name + local ssl_verify, ssl_send_status_req, ssl_client_cert, ssl_client_priv_key + if request_scheme == "https" then + ssl = true + ssl_reused_session = options.ssl_reused_session + ssl_server_name = options.ssl_server_name + ssl_send_status_req = options.ssl_send_status_req + ssl_verify = true -- default + if options.ssl_verify == false then + ssl_verify = false + end + ssl_client_cert = options.ssl_client_cert + ssl_client_priv_key = options.ssl_client_priv_key + end + + -- proxy related settings + local proxy, proxy_uri, proxy_authorization, proxy_host, proxy_port, path_prefix + proxy = options.proxy_opts or self.proxy_opts + + if proxy then + if request_scheme == "https" then + proxy_uri = proxy.https_proxy + proxy_authorization = proxy.https_proxy_authorization + else + proxy_uri = proxy.http_proxy + proxy_authorization = proxy.http_proxy_authorization + -- When a proxy is used, the target URI must be in absolute-form + -- (RFC 7230, Section 5.3.2.). That is, it must be an absolute URI + -- to the remote resource with the scheme, host and an optional port + -- in place. + -- + -- Since _format_request() constructs the request line by concatenating + -- params.path and params.query together, we need to modify the path + -- to also include the scheme, host and port so that the final form + -- in conformant to RFC 7230. + path_prefix = "http://" .. request_host .. (request_port == 80 and "" or (":" .. request_port)) + end + if not proxy_uri then + proxy = nil + proxy_authorization = nil + path_prefix = nil + end + end + + if proxy and proxy.no_proxy then + -- Check if the no_proxy option matches this host. Implementation adapted + -- from lua-http library (https://github.com/daurnimator/lua-http) + if proxy.no_proxy == "*" then + -- all hosts are excluded + proxy = nil + + else + local host = request_host + local no_proxy_set = {} + -- wget allows domains in no_proxy list to be prefixed by "." + -- e.g. no_proxy=.mit.edu + for host_suffix in ngx_re_gmatch(proxy.no_proxy, "\\.?([^,]+)") do + no_proxy_set[host_suffix[1]] = true + end + + -- From curl docs: + -- matched as either a domain which contains the hostname, or the + -- hostname itself. For example local.com would match local.com, + -- local.com:80, and www.local.com, but not www.notlocal.com. + -- + -- Therefore, we keep stripping subdomains from the host, compare + -- them to the ones in the no_proxy list and continue until we find + -- a match or until there's only the TLD left + repeat + if no_proxy_set[host] then + proxy = nil + proxy_uri = nil + proxy_authorization = nil + break + end + + -- Strip the next level from the domain and check if that one + -- is on the list + host = ngx_re_sub(host, "^[^.]+\\.", "") + until not ngx_re_find(host, "\\.") + end + end + + if proxy then + local proxy_uri_t + proxy_uri_t, err = self:parse_uri(proxy_uri) + if not proxy_uri_t then + return nil, "uri parse error: " .. err + end + + local proxy_scheme = proxy_uri_t[1] + if proxy_scheme ~= "http" then + return nil, "protocol " .. tostring(proxy_scheme) .. + " not supported for proxy connections" + end + proxy_host = proxy_uri_t[2] + proxy_port = proxy_uri_t[3] + end + + local cert_hash + if ssl and ssl_client_cert and ssl_client_priv_key then + local cert_type = type(ssl_client_cert) + local key_type = type(ssl_client_priv_key) + + if cert_type ~= "cdata" then + return nil, "bad ssl_client_cert: cdata expected, got " .. cert_type + end + + if key_type ~= "cdata" then + return nil, "bad ssl_client_priv_key: cdata expected, got " .. key_type + end + + if not openssl_available then + return nil, "module `resty.openssl.*` not available, mTLS isn't supported without lua-resty-openssl" + end + + -- convert from `void*` to `OPENSSL_STACK*` + local cert_chain, err = lib_chain.dup(ffi_cast("OPENSSL_STACK*", ssl_client_cert)) + if not cert_chain then + return nil, "failed to dup the ssl_client_cert: " .. err + end + + if #cert_chain < 1 then + return nil, "no cert in ssl_client_cert" + end + + local cert, err = lib_x509.dup(cert_chain[1].ctx) + if not cert then + return nil, "failed to dup the x509: " .. err + end + + -- convert from `void*` to `EVP_PKEY*` + local key, err = lib_pkey.new(ffi_cast("EVP_PKEY*", ssl_client_priv_key)) + if not key then + return nil, "failed to new the pkey: " .. err + end + + -- should not free the cdata passed in + ffi_gc(key.ctx, nil) + + -- check the private key in order to make sure the caller is indeed the holder of the cert + ok, err = cert:check_private_key(key) + if not ok then + return nil, "the private key doesn't match the cert: " .. err + end + + cert_hash, err = cert:digest("sha256") + if not cert_hash then + return nil, "failed to calculate the digest of the cert: " .. err + end + + cert_hash = to_hex(cert_hash) -- convert to hex so that it's printable + end + + -- construct a poolname unique within proxy and ssl info + if not poolname then + poolname = (request_scheme or "") + .. ":" .. request_host + .. ":" .. tostring(request_port) + .. ":" .. tostring(ssl) + .. ":" .. (ssl_server_name or "") + .. ":" .. tostring(ssl_verify) + .. ":" .. (proxy_uri or "") + .. ":" .. (request_scheme == "https" and proxy_authorization or "") + .. ":" .. (cert_hash or "") + -- in the above we only add the 'proxy_authorization' as part of the poolname + -- when the request is https. Because in that case the CONNECT request (which + -- carries the authorization header) is part of the connect procedure, whereas + -- with a plain http request the authorization is part of the actual request. + end + + ngx_log(ngx_DEBUG, "poolname: ", poolname) + + -- do TCP level connection + local tcp_opts = { pool = poolname, pool_size = pool_size, backlog = backlog } + if proxy then + -- proxy based connection + ok, err = sock:connect(proxy_host, proxy_port, tcp_opts) + if not ok then + return nil, "failed to connect to: " .. (proxy_host or "") .. + ":" .. (proxy_port or "") .. + ": " .. err + end + + if ssl and sock:getreusedtimes() == 0 then + -- Make a CONNECT request to create a tunnel to the destination through + -- the proxy. The request-target and the Host header must be in the + -- authority-form of RFC 7230 Section 5.3.3. See also RFC 7231 Section + -- 4.3.6 for more details about the CONNECT request + local destination = request_host .. ":" .. request_port + local res + res, err = self:request({ + method = "CONNECT", + path = destination, + headers = { + ["Host"] = destination, + ["Proxy-Authorization"] = proxy_authorization, + } + }) + + if not res then + return nil, "failed to issue CONNECT to proxy: " .. err + end + + if res.status < 200 or res.status > 299 then + return nil, "failed to establish a tunnel through a proxy: " .. res.status + end + end + + elseif not request_port then + -- non-proxy, without port -> unix domain socket + ok, err = sock:connect(request_host, tcp_opts) + if not ok then + return nil, err + end + + else + -- non-proxy, regular network tcp + ok, err = sock:connect(request_host, request_port, tcp_opts) + if not ok then + return nil, err + end + end + + local ssl_session + -- Now do the ssl handshake + if ssl and sock:getreusedtimes() == 0 then + + -- Experimental mTLS support + if ssl_client_cert and ssl_client_priv_key then + if type(sock.setclientcert) ~= "function" then + return nil, "cannot use SSL client cert and key without mTLS support" + + else + ok, err = sock:setclientcert(ssl_client_cert, ssl_client_priv_key) + if not ok then + return nil, "could not set client certificate: " .. err + end + end + end + + ssl_session, err = sock:sslhandshake(ssl_reused_session, ssl_server_name, ssl_verify, ssl_send_status_req) + if not ssl_session then + self:close() + return nil, err + end + end + + self.host = request_host + self.port = request_port + self.keepalive = true + self.ssl = ssl + -- set only for http, https has already been handled + self.http_proxy_auth = request_scheme ~= "https" and proxy_authorization or nil + self.path_prefix = path_prefix + + return true, nil, ssl_session +end + +return connect diff --git a/docker/astronAgent/astronRPA/volumes/nginx/lua/resty/http_headers.lua b/docker/astronAgent/astronRPA/volumes/nginx/lua/resty/http_headers.lua new file mode 100644 index 0000000000000000000000000000000000000000..6394e619e2d54853c871512e01ef45b9e5064382 --- /dev/null +++ b/docker/astronAgent/astronRPA/volumes/nginx/lua/resty/http_headers.lua @@ -0,0 +1,44 @@ +local rawget, rawset, setmetatable = + rawget, rawset, setmetatable + +local str_lower = string.lower + +local _M = { + _VERSION = '0.17.2', +} + + +-- Returns an empty headers table with internalised case normalisation. +function _M.new() + local mt = { + normalised = {}, + } + + mt.__index = function(t, k) + return rawget(t, mt.normalised[str_lower(k)]) + end + + mt.__newindex = function(t, k, v) + local k_normalised = str_lower(k) + + -- First time seeing this header field? + if not mt.normalised[k_normalised] then + -- Create a lowercased entry in the metatable proxy, with the value + -- of the given field case + mt.normalised[k_normalised] = k + + -- Set the header using the given field case + rawset(t, k, v) + else + -- We're being updated just with a different field case. Use the + -- normalised metatable proxy to give us the original key case, and + -- perorm a rawset() to update the value. + rawset(t, mt.normalised[k_normalised], v) + end + end + + return setmetatable({}, mt) +end + + +return _M diff --git a/docker/astronAgent/casdoor/conf/init_data.json b/docker/astronAgent/casdoor/conf/init_data.json index 57ffbc55a256e901eb28e9ba6fe5cc45c2c2b391..36e02ef1ebb71972b97f70ca5a4affda2dea59da 100644 --- a/docker/astronAgent/casdoor/conf/init_data.json +++ b/docker/astronAgent/casdoor/conf/init_data.json @@ -1,5 +1,1190 @@ { + "organizations": [ + { + "owner": "admin", + "name": "example-org", + "createdTime": "2025-09-20T18:48:24+08:00", + "displayName": "示例组织", + "websiteUrl": "https://door.casdoor.com", + "logo": "", + "logoDark": "", + "favicon": "https://cdn.casbin.org/img/favicon.png", + "hasPrivilegeConsent": false, + "passwordType": "plain", + "passwordSalt": "", + "passwordOptions": [ + "AtLeast6" + ], + "passwordObfuscatorType": "Plain", + "passwordObfuscatorKey": "", + "passwordExpireDays": 0, + "countryCodes": [ + "CN" + ], + "defaultAvatar": "https://cdn.casbin.org/img/casbin.svg", + "defaultApplication": "example-app", + "userTypes": null, + "tags": [], + "languages": [ + "en", + "es", + "fr", + "de", + "zh", + "id", + "ja", + "ko", + "ru", + "vi", + "pt", + "it", + "ms", + "tr", + "ar", + "he", + "nl", + "pl", + "fi", + "sv", + "uk", + "kk", + "fa", + "cs", + "sk", + "az" + ], + "themeData": null, + "masterPassword": "", + "defaultPassword": "", + "masterVerificationCode": "", + "ipWhitelist": "", + "initScore": 0, + "enableSoftDeletion": false, + "isProfilePublic": true, + "useEmailAsUsername": false, + "enableTour": true, + "disableSignin": false, + "ipRestriction": "", + "navItems": null, + "widgetItems": null, + "mfaItems": null, + "mfaRememberInHours": 12, + "accountItems": [ + { + "name": "Organization", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "ID", + "visible": true, + "viewRule": "Public", + "modifyRule": "Immutable", + "regex": "" + }, + { + "name": "Name", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Display name", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Avatar", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "User type", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Password", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Email", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Phone", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Country code", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Country/Region", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Location", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Address", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Affiliation", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Title", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "ID card type", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "ID card", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "ID card info", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Homepage", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Bio", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Tag", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Language", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Gender", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Birthday", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Education", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Score", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Karma", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Ranking", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Signup application", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "API key", + "visible": false, + "viewRule": "", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Groups", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Roles", + "visible": true, + "viewRule": "Public", + "modifyRule": "Immutable", + "regex": "" + }, + { + "name": "Permissions", + "visible": true, + "viewRule": "Public", + "modifyRule": "Immutable", + "regex": "" + }, + { + "name": "3rd-party logins", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Properties", + "visible": false, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Is online", + "visible": true, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Is admin", + "visible": true, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Is forbidden", + "visible": true, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Is deleted", + "visible": true, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Multi-factor authentication", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "WebAuthn credentials", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Managed accounts", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "MFA accounts", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + } + ] + }, + { + "owner": "admin", + "name": "built-in", + "createdTime": "2025-09-20T10:47:17Z", + "displayName": "Built-in Organization", + "websiteUrl": "https://example.com", + "logo": "", + "logoDark": "", + "favicon": "https://cdn.casbin.org/img/casbin/favicon.ico", + "hasPrivilegeConsent": false, + "passwordType": "plain", + "passwordSalt": "", + "passwordOptions": [ + "AtLeast6" + ], + "passwordObfuscatorType": "", + "passwordObfuscatorKey": "", + "passwordExpireDays": 0, + "countryCodes": [ + "US", + "ES", + "FR", + "DE", + "GB", + "CN", + "JP", + "KR", + "VN", + "ID", + "SG", + "IN" + ], + "defaultAvatar": "https://cdn.casbin.org/img/casbin.svg", + "defaultApplication": "", + "userTypes": [], + "tags": [], + "languages": [ + "en", + "zh", + "es", + "fr", + "de", + "id", + "ja", + "ko", + "ru", + "vi", + "pt" + ], + "themeData": null, + "masterPassword": "", + "defaultPassword": "", + "masterVerificationCode": "", + "ipWhitelist": "", + "initScore": 2000, + "enableSoftDeletion": false, + "isProfilePublic": false, + "useEmailAsUsername": false, + "enableTour": true, + "disableSignin": false, + "ipRestriction": "", + "navItems": null, + "widgetItems": null, + "mfaItems": null, + "mfaRememberInHours": 0, + "accountItems": [ + { + "name": "Organization", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "ID", + "visible": true, + "viewRule": "Public", + "modifyRule": "Immutable", + "regex": "" + }, + { + "name": "Name", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Display name", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Avatar", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "User type", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Password", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Email", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Phone", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Country code", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Country/Region", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Location", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Affiliation", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Title", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Homepage", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Bio", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Tag", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Signup application", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Roles", + "visible": true, + "viewRule": "Public", + "modifyRule": "Immutable", + "regex": "" + }, + { + "name": "Permissions", + "visible": true, + "viewRule": "Public", + "modifyRule": "Immutable", + "regex": "" + }, + { + "name": "Groups", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "3rd-party logins", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Properties", + "visible": true, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Is admin", + "visible": true, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Is forbidden", + "visible": true, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Is deleted", + "visible": true, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Multi-factor authentication", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "WebAuthn credentials", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Managed accounts", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "MFA accounts", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + } + ] + } + ], "applications": [ + { + "owner": "admin", + "name": "example-app", + "createdTime": "2025-09-20T18:50:08+08:00", + "displayName": "示例应用", + "logo": "https://cdn.casbin.org/img/casdoor-logo_1185x256.png", + "order": 0, + "homepageUrl": "", + "description": "", + "organization": "example-org", + "cert": "cert-built-in", + "defaultGroup": "", + "headerHtml": "", + "enablePassword": true, + "enableSignUp": true, + "disableSignin": false, + "enableSigninSession": false, + "enableAutoSignin": false, + "enableCodeSignin": false, + "enableSamlCompress": false, + "enableSamlC14n10": false, + "enableSamlPostBinding": false, + "useEmailAsSamlNameId": false, + "enableWebAuthn": false, + "enableLinkWithEmail": false, + "orgChoiceMode": "", + "samlReplyUrl": "", + "providers": [ + { + "owner": "", + "name": "provider_captcha_default", + "canSignUp": false, + "canSignIn": false, + "canUnlink": false, + "countryCodes": null, + "prompted": false, + "signupGroup": "", + "rule": "", + "provider": null + } + ], + "signinMethods": [ + { + "name": "Password", + "displayName": "Password", + "rule": "All" + } + ], + "signupItems": [ + { + "name": "ID", + "visible": false, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "Random" + }, + { + "name": "Username", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Display name", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Password", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Confirm password", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Email", + "visible": false, + "required": false, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "No verification" + }, + { + "name": "Phone", + "visible": true, + "required": false, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "No verification" + }, + { + "name": "Agreement", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Signup button", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Providers", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": ".provider-img {\n width: 30px;\n margin: 5px;\n }\n .provider-big-img {\n margin-bottom: 10px;\n }\n ", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "small" + } + ], + "signinItems": [ + { + "name": "Back button", + "visible": true, + "label": "", + "customCss": ".back-button {\n top: 65px;\n left: 15px;\n position: absolute;\n}\n.back-inner-button{}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Languages", + "visible": true, + "label": "", + "customCss": ".login-languages {\n top: 55px;\n right: 5px;\n position: absolute;\n}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Logo", + "visible": true, + "label": "", + "customCss": ".login-logo-box {}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Signin methods", + "visible": true, + "label": "", + "customCss": ".signin-methods {}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Username", + "visible": true, + "label": "", + "customCss": ".login-username {}\n.login-username-input{}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Password", + "visible": true, + "label": "", + "customCss": ".login-password {}\n.login-password-input{}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Agreement", + "visible": true, + "label": "", + "customCss": ".login-agreement {}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Forgot password?", + "visible": true, + "label": "", + "customCss": ".login-forget-password {\n display: inline-flex;\n justify-content: space-between;\n width: 320px;\n margin-bottom: 25px;\n}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Login button", + "visible": true, + "label": "", + "customCss": ".login-button-box {\n margin-bottom: 5px;\n}\n.login-button {\n width: 100%;\n}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Signup link", + "visible": true, + "label": "", + "customCss": ".login-signup-link {\n margin-bottom: 24px;\n display: flex;\n justify-content: end;\n}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Providers", + "visible": true, + "label": "", + "customCss": ".provider-img {\n width: 30px;\n margin: 5px;\n}\n.provider-big-img {\n margin-bottom: 10px;\n}", + "placeholder": "", + "rule": "small", + "isCustom": false + } + ], + "grantTypes": [ + "authorization_code", + "password", + "client_credentials", + "token", + "id_token", + "refresh_token" + ], + "organizationObj": null, + "certPublicKey": "", + "tags": [], + "samlAttributes": null, + "isShared": false, + "ipRestriction": "", + "clientId": "e3ba6fec42cfe996121f", + "clientSecret": "0c18bf2a11ffbb756ec6ce47dae9e09bdd48e3dd", + "redirectUris": [ + "https://tauri.localhost/","http://localhost:1420/" + ], + "forcedRedirectOrigin": "", + "tokenFormat": "JWT", + "tokenSigningMethod": "", + "tokenFields": [], + "tokenAttributes": null, + "expireInHours": 168, + "refreshExpireInHours": 168, + "signupUrl": "", + "signinUrl": "", + "forgetUrl": "", + "affiliationUrl": "", + "ipWhitelist": "", + "termsOfUse": "", + "signupHtml": "", + "signinHtml": "", + "themeData": null, + "footerHtml": "", + "formCss": "", + "formCssMobile": "", + "formOffset": 2, + "formSideHtml": "", + "formBackgroundUrl": "", + "formBackgroundUrlMobile": "", + "failedSigninLimit": 5, + "failedSigninFrozenTime": 15 + }, + { + "owner": "admin", + "name": "app-built-in", + "createdTime": "2025-09-20T10:47:17Z", + "displayName": "Casdoor", + "logo": "https://cdn.casbin.org/img/casdoor-logo_1185x256.png", + "order": 0, + "homepageUrl": "https://casdoor.org", + "description": "", + "organization": "built-in", + "cert": "cert-built-in", + "defaultGroup": "", + "headerHtml": "", + "enablePassword": true, + "enableSignUp": true, + "disableSignin": false, + "enableSigninSession": false, + "enableAutoSignin": false, + "enableCodeSignin": false, + "enableSamlCompress": false, + "enableSamlC14n10": false, + "enableSamlPostBinding": false, + "useEmailAsSamlNameId": false, + "enableWebAuthn": false, + "enableLinkWithEmail": false, + "orgChoiceMode": "", + "samlReplyUrl": "", + "providers": [ + { + "owner": "", + "name": "provider_captcha_default", + "canSignUp": false, + "canSignIn": false, + "canUnlink": false, + "countryCodes": null, + "prompted": false, + "signupGroup": "", + "rule": "None", + "provider": null + } + ], + "signinMethods": [ + { + "name": "Password", + "displayName": "Password", + "rule": "All" + }, + { + "name": "Verification code", + "displayName": "Verification code", + "rule": "All" + }, + { + "name": "WebAuthn", + "displayName": "WebAuthn", + "rule": "None" + }, + { + "name": "Face ID", + "displayName": "Face ID", + "rule": "None" + } + ], + "signupItems": [ + { + "name": "ID", + "visible": false, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "Random" + }, + { + "name": "Username", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Display name", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Password", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Confirm password", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Email", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "Normal" + }, + { + "name": "Phone", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Agreement", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + } + ], + "signinItems": null, + "grantTypes": null, + "organizationObj": null, + "certPublicKey": "", + "tags": [], + "samlAttributes": null, + "isShared": false, + "ipRestriction": "", + "clientId": "1d1eb3c891fa8faa7d63", + "clientSecret": "4d623f9beb97dd8263bbf3147e194ad3b0b1c9e2", + "redirectUris": [], + "forcedRedirectOrigin": "", + "tokenFormat": "JWT", + "tokenSigningMethod": "", + "tokenFields": [], + "tokenAttributes": null, + "expireInHours": 168, + "refreshExpireInHours": 0, + "signupUrl": "", + "signinUrl": "", + "forgetUrl": "", + "affiliationUrl": "", + "ipWhitelist": "", + "termsOfUse": "", + "signupHtml": "", + "signinHtml": "", + "themeData": null, + "footerHtml": "", + "formCss": "", + "formCssMobile": "", + "formOffset": 2, + "formSideHtml": "", + "formBackgroundUrl": "", + "formBackgroundUrlMobile": "", + "failedSigninLimit": 0, + "failedSigninFrozenTime": 0 + }, { "owner": "admin", "name": "astron-agent-app", @@ -29,5 +1214,1624 @@ "tags": [], "formOffset": 2 } - ] + ], + "users": [ + { + "owner": "example-org", + "name": "example-user", + "createdTime": "2025-09-20T10:56:21Z", + "updatedTime": "2025-09-20T10:57:09Z", + "deletedTime": "", + "id": "3d7cca2b-8da9-41bf-b535-6c9f83d731db", + "externalId": "", + "type": "normal-user", + "password": "123456", + "passwordSalt": "", + "passwordType": "plain", + "displayName": "示例用户", + "firstName": "", + "lastName": "", + "avatar": "https://cdn.casbin.org/img/casbin.svg", + "avatarType": "", + "permanentAvatar": "", + "email": "", + "emailVerified": false, + "phone": "18888888888", + "countryCode": "CN", + "region": "", + "location": "", + "address": [], + "affiliation": "", + "title": "", + "idCardType": "", + "idCard": "", + "homepage": "", + "bio": "", + "tag": "", + "language": "", + "gender": "", + "birthday": "", + "education": "", + "score": 0, + "karma": 0, + "ranking": 1, + "balance": 0, + "currency": "", + "isDefaultAvatar": false, + "isOnline": false, + "isAdmin": false, + "isForbidden": false, + "isDeleted": false, + "signupApplication": "example-app", + "hash": "", + "preHash": "", + "accessKey": "", + "accessSecret": "", + "accessToken": "", + "createdIp": "", + "lastSigninTime": "", + "lastSigninIp": "", + "github": "", + "google": "", + "qq": "", + "wechat": "", + "facebook": "", + "dingtalk": "", + "weibo": "", + "gitee": "", + "linkedin": "", + "wecom": "", + "lark": "", + "gitlab": "", + "adfs": "", + "baidu": "", + "alipay": "", + "casdoor": "", + "infoflow": "", + "apple": "", + "azuread": "", + "azureadb2c": "", + "slack": "", + "steam": "", + "bilibili": "", + "okta": "", + "douyin": "", + "kwai": "", + "line": "", + "amazon": "", + "auth0": "", + "battlenet": "", + "bitbucket": "", + "box": "", + "cloudfoundry": "", + "dailymotion": "", + "deezer": "", + "digitalocean": "", + "discord": "", + "dropbox": "", + "eveonline": "", + "fitbit": "", + "gitea": "", + "heroku": "", + "influxcloud": "", + "instagram": "", + "intercom": "", + "kakao": "", + "lastfm": "", + "mailru": "", + "meetup": "", + "microsoftonline": "", + "naver": "", + "nextcloud": "", + "onedrive": "", + "oura": "", + "patreon": "", + "paypal": "", + "salesforce": "", + "shopify": "", + "soundcloud": "", + "spotify": "", + "strava": "", + "stripe": "", + "tiktok": "", + "tumblr": "", + "twitch": "", + "twitter": "", + "typetalk": "", + "uber": "", + "vk": "", + "wepay": "", + "xero": "", + "yahoo": "", + "yammer": "", + "yandex": "", + "zoom": "", + "metamask": "", + "web3onboard": "", + "custom": "", + "webauthnCredentials": null, + "preferredMfaType": "", + "recoveryCodes": null, + "totpSecret": "", + "mfaPhoneEnabled": false, + "mfaEmailEnabled": false, + "invitation": "", + "invitationCode": "", + "faceIds": null, + "ldap": "", + "properties": {}, + "roles": null, + "permissions": null, + "groups": [], + "lastChangePasswordTime": "", + "lastSigninWrongTime": "", + "signinWrongTimes": 0, + "managedAccounts": null, + "mfaAccounts": null, + "mfaItems": null, + "mfaRememberDeadline": "", + "needUpdatePassword": false, + "ipWhitelist": "" + }, + { + "owner": "built-in", + "name": "admin", + "createdTime": "2025-09-20T10:47:17Z", + "updatedTime": "", + "deletedTime": "", + "id": "1e3b4ee5-7164-47c4-a421-a2ff4938c765", + "externalId": "", + "type": "normal-user", + "password": "123", + "passwordSalt": "", + "passwordType": "plain", + "displayName": "Admin", + "firstName": "", + "lastName": "", + "avatar": "https://cdn.casbin.org/img/casbin.svg", + "avatarType": "", + "permanentAvatar": "", + "email": "admin@example.com", + "emailVerified": false, + "phone": "12345678910", + "countryCode": "US", + "region": "", + "location": "", + "address": [], + "affiliation": "Example Inc.", + "title": "", + "idCardType": "", + "idCard": "", + "homepage": "", + "bio": "", + "tag": "staff", + "language": "", + "gender": "", + "birthday": "", + "education": "", + "score": 2000, + "karma": 0, + "ranking": 1, + "balance": 0, + "currency": "", + "isDefaultAvatar": false, + "isOnline": false, + "isAdmin": true, + "isForbidden": false, + "isDeleted": false, + "signupApplication": "app-built-in", + "hash": "", + "preHash": "", + "accessKey": "", + "accessSecret": "", + "accessToken": "", + "createdIp": "127.0.0.1", + "lastSigninTime": "", + "lastSigninIp": "", + "github": "", + "google": "", + "qq": "", + "wechat": "", + "facebook": "", + "dingtalk": "", + "weibo": "", + "gitee": "", + "linkedin": "", + "wecom": "", + "lark": "", + "gitlab": "", + "adfs": "", + "baidu": "", + "alipay": "", + "casdoor": "", + "infoflow": "", + "apple": "", + "azuread": "", + "azureadb2c": "", + "slack": "", + "steam": "", + "bilibili": "", + "okta": "", + "douyin": "", + "kwai": "", + "line": "", + "amazon": "", + "auth0": "", + "battlenet": "", + "bitbucket": "", + "box": "", + "cloudfoundry": "", + "dailymotion": "", + "deezer": "", + "digitalocean": "", + "discord": "", + "dropbox": "", + "eveonline": "", + "fitbit": "", + "gitea": "", + "heroku": "", + "influxcloud": "", + "instagram": "", + "intercom": "", + "kakao": "", + "lastfm": "", + "mailru": "", + "meetup": "", + "microsoftonline": "", + "naver": "", + "nextcloud": "", + "onedrive": "", + "oura": "", + "patreon": "", + "paypal": "", + "salesforce": "", + "shopify": "", + "soundcloud": "", + "spotify": "", + "strava": "", + "stripe": "", + "tiktok": "", + "tumblr": "", + "twitch": "", + "twitter": "", + "typetalk": "", + "uber": "", + "vk": "", + "wepay": "", + "xero": "", + "yahoo": "", + "yammer": "", + "yandex": "", + "zoom": "", + "metamask": "", + "web3onboard": "", + "custom": "", + "webauthnCredentials": null, + "preferredMfaType": "", + "recoveryCodes": null, + "totpSecret": "", + "mfaPhoneEnabled": false, + "mfaEmailEnabled": false, + "invitation": "", + "invitationCode": "", + "faceIds": null, + "ldap": "", + "properties": {}, + "roles": null, + "permissions": null, + "groups": null, + "lastChangePasswordTime": "", + "lastSigninWrongTime": "", + "signinWrongTimes": 0, + "managedAccounts": null, + "mfaAccounts": null, + "mfaItems": null, + "mfaRememberDeadline": "", + "needUpdatePassword": false, + "ipWhitelist": "" + } + ], + "certs": [ + { + "owner": "admin", + "name": "cert-built-in", + "createdTime": "2025-09-20T10:47:17Z", + "displayName": "Built-in Cert", + "scope": "JWT", + "type": "x509", + "cryptoAlgorithm": "RS256", + "bitSize": 4096, + "expireInYears": 20, + "certificate": "-----BEGIN CERTIFICATE-----\nMIIE3TCCAsWgAwIBAgIDAeJAMA0GCSqGSIb3DQEBCwUAMCgxDjAMBgNVBAoTBWFk\nbWluMRYwFAYDVQQDEw1jZXJ0LWJ1aWx0LWluMB4XDTI1MDkyMDEwNDcxOFoXDTQ1\nMDkyMDEwNDcxOFowKDEOMAwGA1UEChMFYWRtaW4xFjAUBgNVBAMTDWNlcnQtYnVp\nbHQtaW4wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDL9L2vPZEXUP4z\nmbVhlgpQx35HzCvQGr+Hbi+ENf5rUadq2X8JVJ5Js3vsi/dMXoXuw2wScltgayEp\nOuyh775uXC/gOrKgfnwANE9VRU9jwBdpZcLeQBfZB2gVQZDYt2wZBSpCwp78I2AS\neWgpvBDXDTp8fV2bJBu7yaLPTdysXVCpdHEkEan7xCAY9yHl9psiqn8aVD4f9T+U\n/oHRIvyAVLpxgQ6w/Lsk2Zcw7lI4feRlF0PYQouoof91gnOIjkYEyFvF/imuL+Xg\nQuA6yMfJ04lfLt8lwu3jAwGw7VIA8LE2pQ6DmJ4pEbFBMU3H626HNel1dxEjW/j+\nTv47nkCPpXGI0w17fc54fbZ7VmtZ6LizxkBfhWf+j8Rm3hpMr6tJ6ISjUajyB17U\n1w9QWU9pOJa/cehOVczEehQLjhX5MZGAUovlmMNojKAtOO/tdcRsDMwOHJyXBqHa\noCykyJ00eIguTtmTTboAqdx3cpom8wNjRh5sUB+YkpsYTVVe/a5r0olfZHDos5bf\nknJXi9X+ppD7nvoCtwrki6AH5Dw9prsrql3sagUHgBKBVLG3EIhDIlkRTQDOO55C\n8OzuyVbDkIbcEX8BIFj8yoUAP/DcpazHHOGhjHRRcFvVHAGRtz8fH6qB9hX3N3a+\nTevIZoANOYLgN6ACWJ0bODLAO9pwWwIDAQABoxAwDjAMBgNVHRMBAf8EAjAAMA0G\nCSqGSIb3DQEBCwUAA4ICAQAT63JAwjc151XNWbMSr5ClNGd+bwEx+zDnQh/YD8V7\n8Wqj2E4r8B+wysDVu7YdOQkoIjtlFOLACg0469F7oC+kPi6N8vMFFZ+xXWk6qLed\nOFYsdUyH+l643GfMprFMA1qbJvqcOnymggeMA1rSJMu9PJ5g7WfoEg6UTKh7H9HV\nvHvgVzLweiZCS37FCC5+RDt/rOCzIrI2DfwDbf4CLKXft7mr3mnA3kVRuT+ufI9X\n+e6UqmM7EBFYeZAHi8/GXIQ8/j34ag5hiIISMhjuFYKEfMtqLYUCTH6X7NTGbGrv\nAs8YB2x5QnUj89N7IRv2hr1uJnaZOIx5feLRmuRmo35scLopAnNu0VT75TOS0Ifh\nyrouqlep4grk4DMFSWEMNodpkHHLr4pOVE8vCYphli75/beOkiilUpxGI6/osKKo\nSOC5CuC6hDarVBF3q6zpNEnqalQf9Vf2d4zeCKMfV2IuUOqKRaRFpVZfVJsbiYTi\nYF1VUCTFdfrIFsC5V9LknxvLyq8ubzpXHnIV6m/l95OxxCEDvI47l5RmwkblKk57\nH9IRmr6l66Ar2WRGQYAxpiOz3aF8IMg8f0+Vk91FNTsgNrSsk9uovQrrDDtm3KyO\nEzhOO4NA9WgaE1c6GzZD87GhrZukHWHE4KvTpkiQ3pGmTqUjIHvon+0lKtG8E5fz\nKg==\n-----END CERTIFICATE-----\n", + "privateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIJKQIBAAKCAgEAy/S9rz2RF1D+M5m1YZYKUMd+R8wr0Bq/h24vhDX+a1Gnatl/\nCVSeSbN77Iv3TF6F7sNsEnJbYGshKTrsoe++blwv4DqyoH58ADRPVUVPY8AXaWXC\n3kAX2QdoFUGQ2LdsGQUqQsKe/CNgEnloKbwQ1w06fH1dmyQbu8miz03crF1QqXRx\nJBGp+8QgGPch5fabIqp/GlQ+H/U/lP6B0SL8gFS6cYEOsPy7JNmXMO5SOH3kZRdD\n2EKLqKH/dYJziI5GBMhbxf4pri/l4ELgOsjHydOJXy7fJcLt4wMBsO1SAPCxNqUO\ng5ieKRGxQTFNx+tuhzXpdXcRI1v4/k7+O55Aj6VxiNMNe33OeH22e1ZrWei4s8ZA\nX4Vn/o/EZt4aTK+rSeiEo1Go8gde1NcPUFlPaTiWv3HoTlXMxHoUC44V+TGRgFKL\n5ZjDaIygLTjv7XXEbAzMDhyclwah2qAspMidNHiILk7Zk026AKncd3KaJvMDY0Ye\nbFAfmJKbGE1VXv2ua9KJX2Rw6LOW35JyV4vV/qaQ+576ArcK5IugB+Q8Paa7K6pd\n7GoFB4ASgVSxtxCIQyJZEU0AzjueQvDs7slWw5CG3BF/ASBY/MqFAD/w3KWsxxzh\noYx0UXBb1RwBkbc/Hx+qgfYV9zd2vk3ryGaADTmC4DegAlidGzgywDvacFsCAwEA\nAQKCAgEAtERUJ4BuLkKa+3afF2qrIWzB06nFC8GoiYY9H0kt3yMjq1AjdVbCNPgb\nzx6C7JAbJsa5TbCfzR/DBpMbNaIWGasHcdPPsAU7il6xw/dnzQ2qY7DaxN+3dE6U\nkz0JTlMIizDCgpFMPiTyNEH0a/bal4kMqZ2Qz5/hl2AHs9zo77vmoG/X1H58VJer\nmwVLg9sskT5K6zWMV2jH0uQET5nxvWemBs5/8rTeoBpmBIyQRXgYF7WxdIKUt+6/\nQNiVTxwZDP8eBmi35EpXjpjtYWe3Fk8O+v8Nom2hHuW4Z+3KbiRPLbJDmtKY8Em/\n9pQiYFJZtc5T00vy7OLMt9GP6ZfdDMXHqGT/VFJuYNQhRWgaf9JE5zZuQ3O/D1BH\nAbY0+a825DcOn2XqP3KlHOR1CJyFhphZDowxg2pjhQ548+30eQ9/IoTvgrEnReRW\n3/USVvcUA4lgmzKv50BLiy9wK55FVglafdRm1fq3ykQwAZ/ok4ah2U+ZA98Hh8/V\n4xZ/KSBlNxSfBEPKlPkSBBrwqUwZtrwcHUg0qiRrJGvGxqKPUb0kOQmQjX2VNPoU\nPYzHO9G83RFeJU5KjMj9+apXV2qSL1m8wFJ/aHraUoaOhQ7AzETY0H8r0EbBunq3\nQ8s3Foeb3/p9DOxZxODaDKYDKHM43h1Oro+JjXy+21KSBBjAQrkCggEBAOZzNUlB\nayl/c6ynVlaYR2UGPdbymbAu8dB2Yj/OFjKQgWl2pKVpjUvva7A8p0smU+oC3fVQ\n9qBT6834N8jUqKUCxkHnVw1UDhXPJofqOkaLwf4cLL3X1PbPShaZbEM45YZqmU/c\npihL/myVcXFxntzQZ9NxzJU1wu4uwII0jd1ciFNssulxobgN0JDLM3jJ+Vf1yFUC\nJgCscZcRWBb0HW1IxHVic3GPEzg1hwgyt9V+e/xdKuy4+LQuPPsVBiy5lsVBtwXY\nN5Ve2k9dp0etnoQE+xjdcDwJVNgD46C4nw8e177u20cDyevILbxCRlSJ/ptQXgVu\nc3UZ9o9Y51N9HfUCggEBAOKRj7vGLhUf0Tv7+qroktTaj6jFUQr+JFQKuOTAHo1C\nghyIAtDjDPl3Be+DWPrvXSswEjOqI/haTjxUmTQgJEmuQEfebE7n0fOf25jcCFwb\nIEFgzvLJSvEiZX7y8nPFffP5TSzS/gxiqNZVJ0im3aAYUK48DXY+6Sg+xhOAPpzY\nysLifc6P2WlGt3OntuMYYgCqGwmlnRNVADdlqt5EH/mRRuxjqGQqXovozlQ8UBTL\nDX4fDLjkcqdG22mOD0qscvsG36LTjpcERposjQ6Qa6QFkGoNd5qYTILW3oq36NsJ\nevucMPSK6HWEbCkrC9Z6Q+PSuILHRNWJSThkAuzKkw8CggEAb6BEomxWvS4oWOxh\njOaMRqokUDcJLOdAaKq/YoqwA+QtW2mFzT34nFynvCFVI7i4EvU6kHacUAL2iLmA\nQ/6Ghg92+ztU1nbtr7C8yD8z5TITUMRTA85FMRwtlg7Q+yrXOyntg1qs/X36CpzE\n65+OxQUKFcjcwTXea0MoKqnMQfptaoOPkjZhkGbYrRpQn2SuK+Y5GLxGrjLZfsR+\n9/ddPa9uwjFjHBGizKpY8yamF3sCEbcLcMkUZyqyjSic6hMnrfrr7Z/TJL5iXulN\nexHlY6uJ+XxhviMC/vO7UgG7wjY9aRYIDzkNmPFI/hTYPmDtfEwMjvL2aDWgUcVN\noApN9QKCAQEAyhT21I7BD4pff1cSj1n9jOicdfX4gQuIr4UYwL8zAN+vWW9ew52g\nNumYW7cVqEvTF/A6a+Z3Ss6RNXJna3y3oRhQsUmL5R0TwG522XJ36l8vd+C29Qnh\nVA5P5Nkgs24VF4Tm9vICMl3VJcax0TU0O9U0MRPTFgKqx4Cl/0LFlfQvdX+6ooDf\nc+zlN70BfLCEyP7wOryCy3lnRgHiU3kD4/9V+QYybZT022l8jtl0u/cYQ8PB/y+T\nq+uhTBavQPVrYMcStRJo/f2MU3slHTZnK9biphT49uScaZ7ow2WhxaxBCyaW66by\nC89fAaEpX9WRtCSA+fRuSt+2dRuPGFDetQKCAQBNxBbtOrw79tpq7NaSWlylTR+K\nQJeUSol1NpktS17dLesFc6c4vVc90tOrQvmK9MoOdYpk7/ZMpIpXtgtoegEnN34r\nbfyb+O4UeOi44Y/cKr1Av3bZmp2lRQtTXZJkRlRI5kowVAHOP70WWytcfIYW+zbZ\nOSRiQOT2UFaIQjdZml9jvD/Zhr8TuLPZoaRuhWVLID0LZrix9ivYD028uHoiONl3\nbmzNhqTlcGC/skh5hn6ohEyizvHLIrpbUPK66xOWjcheFi+wKfGpKOZxt325y64D\nhQkmJquirnONmiUNuKWIUxOkbC/spnrAJ72dStfEo2V59hG5jitTlmoaXAo+\n-----END RSA PRIVATE KEY-----\n" + } + ], + "providers": [ + { + "owner": "admin", + "name": "provider_captcha_default", + "createdTime": "2025-09-20T10:47:17Z", + "displayName": "Captcha Default", + "category": "Captcha", + "type": "Default", + "subType": "", + "method": "", + "clientId": "", + "clientSecret": "", + "clientId2": "", + "clientSecret2": "", + "cert": "", + "customAuthUrl": "", + "customTokenUrl": "", + "customUserInfoUrl": "", + "customLogo": "", + "scopes": "", + "userMapping": null, + "httpHeaders": null, + "host": "", + "port": 0, + "disableSsl": false, + "title": "", + "content": "", + "receiver": "", + "regionId": "", + "signName": "", + "templateCode": "", + "appId": "", + "endpoint": "", + "intranetEndpoint": "", + "domain": "", + "bucket": "", + "pathPrefix": "", + "metadata": "", + "idP": "", + "issuerUrl": "", + "enableSignAuthnRequest": false, + "emailRegex": "", + "providerUrl": "" + } + ], + "ldaps": [ + { + "id": "ldap-built-in", + "owner": "built-in", + "createdTime": "2025-09-20T10:47:18Z", + "serverName": "BuildIn LDAP Server", + "host": "example.com", + "port": 389, + "enableSsl": false, + "allowSelfSignedCert": false, + "username": "cn=buildin,dc=example,dc=com", + "password": "123", + "baseDn": "ou=BuildIn,dc=example,dc=com", + "filter": "", + "filterFields": null, + "defaultGroup": "", + "passwordType": "", + "autoSync": 0, + "lastSync": "" + } + ], + "models": [ + { + "owner": "built-in", + "name": "api-model-built-in", + "createdTime": "2025-09-20T10:47:18Z", + "displayName": "API Model", + "description": "", + "modelText": "[request_definition]\nr = subOwner, subName, method, urlPath, objOwner, objName\n\n[policy_definition]\np = subOwner, subName, method, urlPath, objOwner, objName\n\n[role_definition]\ng = _, _\n\n[policy_effect]\ne = some(where (p.eft == allow))\n\n[matchers]\nm = (r.subOwner == p.subOwner || p.subOwner == \"*\") \u0026\u0026 \\\n (r.subName == p.subName || p.subName == \"*\" || r.subName != \"anonymous\" \u0026\u0026 p.subName == \"!anonymous\") \u0026\u0026 \\\n (r.method == p.method || p.method == \"*\") \u0026\u0026 \\\n (r.urlPath == p.urlPath || p.urlPath == \"*\") \u0026\u0026 \\\n (r.objOwner == p.objOwner || p.objOwner == \"*\") \u0026\u0026 \\\n (r.objName == p.objName || p.objName == \"*\") || \\\n (r.subOwner == r.objOwner \u0026\u0026 r.subName == r.objName)" + }, + { + "owner": "built-in", + "name": "user-model-built-in", + "createdTime": "2025-09-20T10:47:18Z", + "displayName": "Built-in Model", + "description": "", + "modelText": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _\n\n[policy_effect]\ne = some(where (p.eft == allow))\n\n[matchers]\nm = g(r.sub, p.sub) \u0026\u0026 r.obj == p.obj \u0026\u0026 r.act == p.act" + } + ], + "permissions": [ + { + "owner": "built-in", + "name": "permission-built-in", + "createdTime": "2025-09-20T10:47:17Z", + "displayName": "Built-in Permission", + "description": "Built-in Permission", + "users": [ + "built-in/*" + ], + "groups": [], + "roles": [], + "domains": [], + "model": "user-model-built-in", + "adapter": "", + "resourceType": "Application", + "resources": [ + "app-built-in" + ], + "actions": [ + "Read", + "Write", + "Admin" + ], + "effect": "Allow", + "isEnabled": true, + "submitter": "admin", + "approver": "admin", + "approveTime": "2025-09-20T10:47:17Z", + "state": "Approved" + } + ], + "payments": [], + "products": [], + "resources": [], + "roles": [ + { + "owner": "example-org", + "name": "example-role", + "createdTime": "2025-09-20T18:58:05+08:00", + "displayName": "示例角色", + "description": "", + "users": [ + "example-org/example-user" + ], + "groups": [], + "roles": [], + "domains": [], + "isEnabled": true + }, + { + "owner": "built-in", + "name": "role_m06bnm", + "createdTime": "2025-09-20T18:57:13+08:00", + "displayName": "New Role - m06bnm", + "description": "", + "users": [], + "groups": [], + "roles": [], + "domains": [], + "isEnabled": true + } + ], + "syncers": [], + "tokens": [ + { + "owner": "admin", + "name": "3511665e-fe71-4497-8a96-a2f298e3751d", + "createdTime": "2025-09-20T10:59:43Z", + "application": "app-built-in", + "organization": "built-in", + "user": "admin", + "code": "7f586f871be50a1b2671", + "accessToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImNlcnQtYnVpbHQtaW4iLCJ0eXAiOiJKV1QifQ.eyJvd25lciI6ImJ1aWx0LWluIiwibmFtZSI6ImFkbWluIiwiY3JlYXRlZFRpbWUiOiIyMDI1LTA5LTIwVDEwOjQ3OjE3WiIsInVwZGF0ZWRUaW1lIjoiIiwiZGVsZXRlZFRpbWUiOiIiLCJpZCI6IjFlM2I0ZWU1LTcxNjQtNDdjNC1hNDIxLWEyZmY0OTM4Yzc2NSIsInR5cGUiOiJub3JtYWwtdXNlciIsInBhc3N3b3JkIjoiIiwicGFzc3dvcmRTYWx0IjoiIiwicGFzc3dvcmRUeXBlIjoicGxhaW4iLCJkaXNwbGF5TmFtZSI6IkFkbWluIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4ub3JnL2ltZy9jYXNiaW4uc3ZnIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6IiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxMjM0NTY3ODkxMCIsImNvdW50cnlDb2RlIjoiVVMiLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IkV4YW1wbGUgSW5jLiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjoyMDAwLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjp0cnVlLCJpc0ZvcmJpZGRlbiI6ZmFsc2UsImlzRGVsZXRlZCI6ZmFsc2UsInNpZ251cEFwcGxpY2F0aW9uIjoiYXBwLWJ1aWx0LWluIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIxMjcuMC4wLjEiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoiYWNjZXNzLXRva2VuIiwidGFnIjoic3RhZmYiLCJzY29wZSI6InByb2ZpbGUiLCJhenAiOiIxZDFlYjNjODkxZmE4ZmFhN2Q2MyIsImlzcyI6Imh0dHA6Ly8xNzIuMzAuMzQuMTg0OjgwMDQiLCJzdWIiOiIxZTNiNGVlNS03MTY0LTQ3YzQtYTQyMS1hMmZmNDkzOGM3NjUiLCJhdWQiOlsiMWQxZWIzYzg5MWZhOGZhYTdkNjMiXSwiZXhwIjoxNzU4OTcwNzgzLCJuYmYiOjE3NTgzNjU5ODMsImlhdCI6MTc1ODM2NTk4MywianRpIjoiYWRtaW4vMzUxMTY2NWUtZmU3MS00NDk3LThhOTYtYTJmMjk4ZTM3NTFkIn0.TeqMA2waDtY2CQYNEkMdOdNHzXBpxdk203qMnu_6EbVgR4dEdEmEqaJ4wn-oiLvdTgoMfZ_Fb4De4iyp8jRNYdTMylo82RhcF4jsU_C8sLzeE6tENPcVQ3xJq7oOFtLCWa2V0lmE3SuypJtI2Vki5AEOds9en2Y1RCCryug6LgVo_94MnmCWlQW3pYZG5cmrKVGHBlyIK0Nw01IBBxfkPOga1s50QZaCR3Cva8SjaoY1Cx-AtU5vKzHRjp63bfrhP9JXfeP2xrL0ZyZ6LBHsCsA_1FyojAndZCNahCpAZH0_s6I0nJan0NLkBZhR89TE-Ys5SygvgkofSsyNJ7jhLh21oTdvpheUFDOqNtjBE36Et1EUFsm3jc88fRUsgzArR4pg_6YPybSMJeUrTtgpngBi-yKTs3jOo3hUszMixJrE1kXyVqMeesyrAt-HJWLBh_wx8L5BfwsgZgCRwULvbMRCH33Jfn3hG9jxu9DoLM9OvBm7HqPWXhioGG_4RII0PE9QBmN2cIPfJokf6f_FgO8O-kvwH5LUhW5HpiNJar6oOdn7aamkpuI7BBEn6YxF7c-qr1scVGBum46wQRSJ4Hl_pMwGZ1uyB76zXSaM2nqRO4MX3g7vaySq1FrL68JpYizW8ejDnuSqovVhyDwgJ_iEVbP5z7aDicOemrgoN-I", + "refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJvd25lciI6ImJ1aWx0LWluIiwibmFtZSI6ImFkbWluIiwiY3JlYXRlZFRpbWUiOiIyMDI1LTA5LTIwVDEwOjQ3OjE3WiIsInVwZGF0ZWRUaW1lIjoiIiwiZGVsZXRlZFRpbWUiOiIiLCJpZCI6IjFlM2I0ZWU1LTcxNjQtNDdjNC1hNDIxLWEyZmY0OTM4Yzc2NSIsInR5cGUiOiJub3JtYWwtdXNlciIsInBhc3N3b3JkIjoiIiwicGFzc3dvcmRTYWx0IjoiIiwicGFzc3dvcmRUeXBlIjoicGxhaW4iLCJkaXNwbGF5TmFtZSI6IkFkbWluIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4ub3JnL2ltZy9jYXNiaW4uc3ZnIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6IiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxMjM0NTY3ODkxMCIsImNvdW50cnlDb2RlIjoiVVMiLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IkV4YW1wbGUgSW5jLiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjoyMDAwLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjp0cnVlLCJpc0ZvcmJpZGRlbiI6ZmFsc2UsImlzRGVsZXRlZCI6ZmFsc2UsInNpZ251cEFwcGxpY2F0aW9uIjoiYXBwLWJ1aWx0LWluIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIxMjcuMC4wLjEiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoicmVmcmVzaC10b2tlbiIsInRhZyI6InN0YWZmIiwic2NvcGUiOiJwcm9maWxlIiwiYXpwIjoiMWQxZWIzYzg5MWZhOGZhYTdkNjMiLCJpc3MiOiJodHRwOi8vMTcyLjMwLjM0LjE4NDo4MDA0Iiwic3ViIjoiMWUzYjRlZTUtNzE2NC00N2M0LWE0MjEtYTJmZjQ5MzhjNzY1IiwiYXVkIjpbIjFkMWViM2M4OTFmYThmYWE3ZDYzIl0sImV4cCI6MTc1ODk3MDc4MywibmJmIjoxNzU4MzY1OTgzLCJpYXQiOjE3NTgzNjU5ODMsImp0aSI6ImFkbWluLzM1MTE2NjVlLWZlNzEtNDQ5Ny04YTk2LWEyZjI5OGUzNzUxZCJ9.vTiXef-KdyuwQdMEdReDdw5x4DDtSPRCLp5iDNlKaUTY5zWzUixGXU3GlYyNWqtjB8tl1saENUsvfD8k7womxdxJLnbpBu_DgQePF3woEeTaGrs27vIncbdi8ywUb_I8IEuYhjavi3hvaN5rXqouVr09sLZrbu6E65RBw4LM6GEQcUkwxUqd-qIhtV2p49ip9p2SIsvhe4BxVkbjg2EhbaS9Alf4uBeXl_vgjG9vEKj4vr3mol4yyVuwnr-rYYPjPL2QFsJfrUQCxZI9xpDeKgfoKNpmarPHcwxWK5wKcLCSCfc3Nhvnr_iQWr-lW0ZhkgUCbfATljfYSy_Vp6Ro_sSu9mw3Bke35wKt28nOMBQ2f1bx9Inhoi4ocZvV9AShtS56WXgHl5Ts7oM0HG3Z2LcYh-lCEPqTDjG-LW1R9xxaBFRJeV14g_YlUD_uTECjT94xaQs0eqUJHXebE3QJzHt2-rFagZV2iG-QDZDmij3f8VjLcG2zYG1EXfMR5H76xOu7Xyk5YnV5WQYECu_njTSbb-AEdt8syaqzM5LIvrN4Mp0dzbB6xfwXVZrlCF56zemcR17zdcspgSMa7RWphIBWgKPAm65GgAtGAdQEak81IHiF5dZ5xUyCjzrjS-z_RE_Vrf7ra1NUd0xJtJwUMf4AiIO0qI5JhFaTfjT4KlY", + "accessTokenHash": "ea2da0b06f8554f3ea1f3496e54e15cd87f7b5a53b31caecb8685e996ccf0390", + "refreshTokenHash": "a6943e013ca1031c6851c3220062b3591e94e99f1e98e1400ee7354b45cb475e", + "expiresIn": 604800, + "scope": "profile", + "tokenType": "Bearer", + "codeChallenge": "", + "codeIsUsed": true, + "codeExpireIn": 0 + }, + { + "owner": "admin", + "name": "96e45056-947a-4d29-9b59-46e7b2d25889", + "createdTime": "2025-09-20T10:56:34Z", + "application": "app-built-in", + "organization": "built-in", + "user": "admin", + "code": "a32cf35f5ca08f50732e", + "accessToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImNlcnQtYnVpbHQtaW4iLCJ0eXAiOiJKV1QifQ.eyJvd25lciI6ImJ1aWx0LWluIiwibmFtZSI6ImFkbWluIiwiY3JlYXRlZFRpbWUiOiIyMDI1LTA5LTIwVDEwOjQ3OjE3WiIsInVwZGF0ZWRUaW1lIjoiIiwiZGVsZXRlZFRpbWUiOiIiLCJpZCI6IjFlM2I0ZWU1LTcxNjQtNDdjNC1hNDIxLWEyZmY0OTM4Yzc2NSIsInR5cGUiOiJub3JtYWwtdXNlciIsInBhc3N3b3JkIjoiIiwicGFzc3dvcmRTYWx0IjoiIiwicGFzc3dvcmRUeXBlIjoicGxhaW4iLCJkaXNwbGF5TmFtZSI6IkFkbWluIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4ub3JnL2ltZy9jYXNiaW4uc3ZnIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6IiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxMjM0NTY3ODkxMCIsImNvdW50cnlDb2RlIjoiVVMiLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IkV4YW1wbGUgSW5jLiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjoyMDAwLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjp0cnVlLCJpc0ZvcmJpZGRlbiI6ZmFsc2UsImlzRGVsZXRlZCI6ZmFsc2UsInNpZ251cEFwcGxpY2F0aW9uIjoiYXBwLWJ1aWx0LWluIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIxMjcuMC4wLjEiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoiYWNjZXNzLXRva2VuIiwidGFnIjoic3RhZmYiLCJzY29wZSI6InByb2ZpbGUiLCJhenAiOiIxZDFlYjNjODkxZmE4ZmFhN2Q2MyIsImlzcyI6Imh0dHA6Ly8xNzIuMzAuMzQuMTg0OjgwMDQiLCJzdWIiOiIxZTNiNGVlNS03MTY0LTQ3YzQtYTQyMS1hMmZmNDkzOGM3NjUiLCJhdWQiOlsiMWQxZWIzYzg5MWZhOGZhYTdkNjMiXSwiZXhwIjoxNzU4OTcwNTk0LCJuYmYiOjE3NTgzNjU3OTQsImlhdCI6MTc1ODM2NTc5NCwianRpIjoiYWRtaW4vOTZlNDUwNTYtOTQ3YS00ZDI5LTliNTktNDZlN2IyZDI1ODg5In0.WzQyw21sLPwwhCZp6v7PlPM_Muztxl-XFwKtYdg96Fp0mxWzXB3oPfGECFfcqXjNi6n8C42M32deKKUERimOxESI9LehdDwsweyvZN_wyeJgkxmIhN1gQd59TjIglJ134IFYA2AoIxCC76M78ged9hEW_IzoOF2lQh12DISCLY7RuzYpkuY0DTe4QFcRocAp_ZRMTe6wQPN8zPDqhGvJBs173o1CFSdta7TzE9UyFgrfdhITSv2rNlPqi7hbWvOlazDDjY8Qzw40xi7_v2wnO33hbiX_WLMLlJpOTzWnPFWcw9-nYd4rCL3Vxo0CVteNwP3ZuK2HtN8errnM6vXFAng0ZgdtyIQ3wdI1-65cyG6PJGBBq02d6Hgfg1KktnsTtA0tklO2t9YM3ph-EDAMDj35gUyU3sXFfHpVmtB9qKwx6WmcvA6hJvo8Gc79_-SoLE92a_GW_sRojqJJ5rLmb9d6mrU6UqKVTsa1mfV28CnLMkQq7kyxpjpRD41yVh-vdXv4qquHxTIjPtgw6akS3sCjGbTszO5YvvOzQCcHN8brBKnDX0MYvKu7i8-d0roVF0TYLaCDW8EKm1AQlaP7ts6Pi3INeyf6xaXhJfNqQSeqDkmAWNDUUO3okTu8uq4br48inn7GK4e8Dc2QpZScerPlNjKTliOsKZzK1uNCpIA", + "refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJvd25lciI6ImJ1aWx0LWluIiwibmFtZSI6ImFkbWluIiwiY3JlYXRlZFRpbWUiOiIyMDI1LTA5LTIwVDEwOjQ3OjE3WiIsInVwZGF0ZWRUaW1lIjoiIiwiZGVsZXRlZFRpbWUiOiIiLCJpZCI6IjFlM2I0ZWU1LTcxNjQtNDdjNC1hNDIxLWEyZmY0OTM4Yzc2NSIsInR5cGUiOiJub3JtYWwtdXNlciIsInBhc3N3b3JkIjoiIiwicGFzc3dvcmRTYWx0IjoiIiwicGFzc3dvcmRUeXBlIjoicGxhaW4iLCJkaXNwbGF5TmFtZSI6IkFkbWluIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4ub3JnL2ltZy9jYXNiaW4uc3ZnIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6IiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxMjM0NTY3ODkxMCIsImNvdW50cnlDb2RlIjoiVVMiLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IkV4YW1wbGUgSW5jLiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjoyMDAwLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjp0cnVlLCJpc0ZvcmJpZGRlbiI6ZmFsc2UsImlzRGVsZXRlZCI6ZmFsc2UsInNpZ251cEFwcGxpY2F0aW9uIjoiYXBwLWJ1aWx0LWluIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIxMjcuMC4wLjEiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoicmVmcmVzaC10b2tlbiIsInRhZyI6InN0YWZmIiwic2NvcGUiOiJwcm9maWxlIiwiYXpwIjoiMWQxZWIzYzg5MWZhOGZhYTdkNjMiLCJpc3MiOiJodHRwOi8vMTcyLjMwLjM0LjE4NDo4MDA0Iiwic3ViIjoiMWUzYjRlZTUtNzE2NC00N2M0LWE0MjEtYTJmZjQ5MzhjNzY1IiwiYXVkIjpbIjFkMWViM2M4OTFmYThmYWE3ZDYzIl0sImV4cCI6MTc1ODk3MDU5NCwibmJmIjoxNzU4MzY1Nzk0LCJpYXQiOjE3NTgzNjU3OTQsImp0aSI6ImFkbWluLzk2ZTQ1MDU2LTk0N2EtNGQyOS05YjU5LTQ2ZTdiMmQyNTg4OSJ9.FxxMAsCarLLg6uDuP67z5zqTvgEufohViNlpM9z9127XStlOShcXRR3C4Z-OwDRP65QmqqidWY-Sn2VkaxWnpKB_Du-KLBHDKz2XRKv20Qg9E8Q25rcyiBl2RnRa3pFfnekaOw9fj21S0LAkUEuqqsbotDeOv_B9seMRptAGcuhdTY0pMnurRh6b4-tt0fhH1CxlI1LZX5fFS7EWPACqZ2OCYVujU43jicusnXPpPwq2mKiKBGDx-sBXyVIpBuocLJrJDIClV6S0yqMtfbkwM5n7q8GDg-Md9_wsQ9ZT6MmRHzEOP2LI3B8UNZ4EHkzclVRQSaQWlh4QBXmYpoHJWLH5-inNQ0XON4zGmgdsEY-PKY6sYa2Qkf6tXCY7J_l8lUMLtvU_PUkamrZYNyB29JsCTSBHUpk2CuZ2kVyhSZ2v2oAr6v80kywJrEesuP1ErYR3BXwXRUiDZ4qds5I8BolrNGS0Ew3aMyPVmcJ8FxoDcwViDzcy-aMnaUPnpa7yV1BgLShKp_KD0byd28cns5ARbEi2XZwA7pCsE59QHI655OQNGCIM9hofMK0PIl4aJGyNVOVRZeNc-JvrwNdjR_bGYVJYo5e2XygRoedtlCg5hPpUzr9V82eIqmY8noU1yN0vneH-h24GLeDcb0OILaGvYBuMn8l0cslfDMxeK7Y", + "accessTokenHash": "b731f1895b7fd0397844fb3926495c7791f8cd4670e10661b7d07c67d684ca51", + "refreshTokenHash": "fe4612153bba0a17aecefd1ca69da23dd2e30fcb55f91f16fbc052d4d12739fa", + "expiresIn": 604800, + "scope": "profile", + "tokenType": "Bearer", + "codeChallenge": "", + "codeIsUsed": true, + "codeExpireIn": 0 + }, + { + "owner": "admin", + "name": "c8fea633-4187-49d6-b94c-e43306f5a32e", + "createdTime": "2025-09-20T10:56:24Z", + "application": "example-app", + "organization": "example-org", + "user": "example-user", + "code": "032fd4699c85d5444a80", + "accessToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImNlcnQtYnVpbHQtaW4iLCJ0eXAiOiJKV1QifQ.eyJvd25lciI6ImV4YW1wbGUtb3JnIiwibmFtZSI6ImV4YW1wbGUtdXNlciIsImNyZWF0ZWRUaW1lIjoiMjAyNS0wOS0yMFQxMDo1NjoyMVoiLCJ1cGRhdGVkVGltZSI6IiIsImRlbGV0ZWRUaW1lIjoiIiwiaWQiOiIzZDdjY2EyYi04ZGE5LTQxYmYtYjUzNS02YzlmODNkNzMxZGIiLCJ0eXBlIjoibm9ybWFsLXVzZXIiLCJwYXNzd29yZCI6IiIsInBhc3N3b3JkU2FsdCI6IiIsInBhc3N3b3JkVHlwZSI6InBsYWluIiwiZGlzcGxheU5hbWUiOiLnpLrkvovnlKjmiLciLCJmaXJzdE5hbWUiOiIiLCJsYXN0TmFtZSI6IiIsImF2YXRhciI6Imh0dHBzOi8vY2RuLmNhc2Jpbi5vcmcvaW1nL2Nhc2Jpbi5zdmciLCJhdmF0YXJUeXBlIjoiIiwicGVybWFuZW50QXZhdGFyIjoiIiwiZW1haWwiOiIiLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxODg4ODg4ODg4OCIsImNvdW50cnlDb2RlIjoiQ04iLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjowLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjpmYWxzZSwiaXNGb3JiaWRkZW4iOmZhbHNlLCJpc0RlbGV0ZWQiOmZhbHNlLCJzaWdudXBBcHBsaWNhdGlvbiI6ImV4YW1wbGUtYXBwIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoiYWNjZXNzLXRva2VuIiwidGFnIjoiIiwic2NvcGUiOiJwcm9maWxlIiwiYXpwIjoiZTNiYTZmZWM0MmNmZTk5NjEyMWYiLCJpc3MiOiJodHRwOi8vMTcyLjMwLjM0LjE4NDo4MDA0Iiwic3ViIjoiM2Q3Y2NhMmItOGRhOS00MWJmLWI1MzUtNmM5ZjgzZDczMWRiIiwiYXVkIjpbImUzYmE2ZmVjNDJjZmU5OTYxMjFmIl0sImV4cCI6MTc1ODk3MDU4NCwibmJmIjoxNzU4MzY1Nzg0LCJpYXQiOjE3NTgzNjU3ODQsImp0aSI6ImFkbWluL2M4ZmVhNjMzLTQxODctNDlkNi1iOTRjLWU0MzMwNmY1YTMyZSJ9.buJ10cMxbnIS6LRrAjMkJrtOw-V0NJWJ2ySfk-uzWLTxA1SOXwA1DGa8wsn5k0WUyCy6RSN3d3Kl75hz2qwKZdABc4E9tiqx7J_obXxGjAZwZozmWrzBLMBCXjIHk89qc7b6AEbndNbSR0_MDRWunNNwqGvY6H4q3rSAA0Cu-sKLW1xUIpvRLVq3pF2ddWd3_4t30O4uDR7q3PBzmGeCKfRxiCEB3TYcq89rGfS9frKXl7vN9m9wSM6Q6Pqx1IFkALoUl1Z45GIHSn9nzRTuPr5dbeD2jOI9Y-3tHndRrKioyKGZcBgPhzEFmFY6oBWbzoK1TQEGJMk667RfVxew9aE-hXA07yxL7el1p6ZIG_RoUw9MYC0NzjYtiDWg8qamDX2Om7NRs6-e11hPbq3-kvyO9sFdu9aFzpPE-2vcpUfyI0jgg9QRpPjYJ00_WbtTW1caIfAu1RlWK7M56GFylKXtQkLDlz7R1d5pY9z6kMmoBOu-eiLdKfA1QWhGvDp6g3m3HBPCVd7J0lAGnQFFzTaO5adTpTlfN7PHnd1U4hhfSlU525s7-dRIiKjRLeKgehmAAlwlG_M7_huapbGpAxg_t2kDmOsGf9vxbbiHt9x-vYtnyT9rF6XRttAzRfddl3kEsg8vZpG1K9IV5b0mGmYMB2UAdC-YFlVD6FSAjrQ", + "refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJvd25lciI6ImV4YW1wbGUtb3JnIiwibmFtZSI6ImV4YW1wbGUtdXNlciIsImNyZWF0ZWRUaW1lIjoiMjAyNS0wOS0yMFQxMDo1NjoyMVoiLCJ1cGRhdGVkVGltZSI6IiIsImRlbGV0ZWRUaW1lIjoiIiwiaWQiOiIzZDdjY2EyYi04ZGE5LTQxYmYtYjUzNS02YzlmODNkNzMxZGIiLCJ0eXBlIjoibm9ybWFsLXVzZXIiLCJwYXNzd29yZCI6IiIsInBhc3N3b3JkU2FsdCI6IiIsInBhc3N3b3JkVHlwZSI6InBsYWluIiwiZGlzcGxheU5hbWUiOiLnpLrkvovnlKjmiLciLCJmaXJzdE5hbWUiOiIiLCJsYXN0TmFtZSI6IiIsImF2YXRhciI6Imh0dHBzOi8vY2RuLmNhc2Jpbi5vcmcvaW1nL2Nhc2Jpbi5zdmciLCJhdmF0YXJUeXBlIjoiIiwicGVybWFuZW50QXZhdGFyIjoiIiwiZW1haWwiOiIiLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxODg4ODg4ODg4OCIsImNvdW50cnlDb2RlIjoiQ04iLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjowLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjpmYWxzZSwiaXNGb3JiaWRkZW4iOmZhbHNlLCJpc0RlbGV0ZWQiOmZhbHNlLCJzaWdudXBBcHBsaWNhdGlvbiI6ImV4YW1wbGUtYXBwIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoicmVmcmVzaC10b2tlbiIsInRhZyI6IiIsInNjb3BlIjoicHJvZmlsZSIsImF6cCI6ImUzYmE2ZmVjNDJjZmU5OTYxMjFmIiwiaXNzIjoiaHR0cDovLzE3Mi4zMC4zNC4xODQ6ODAwNCIsInN1YiI6IjNkN2NjYTJiLThkYTktNDFiZi1iNTM1LTZjOWY4M2Q3MzFkYiIsImF1ZCI6WyJlM2JhNmZlYzQyY2ZlOTk2MTIxZiJdLCJleHAiOjE3NTg5NzA1ODQsIm5iZiI6MTc1ODM2NTc4NCwiaWF0IjoxNzU4MzY1Nzg0LCJqdGkiOiJhZG1pbi9jOGZlYTYzMy00MTg3LTQ5ZDYtYjk0Yy1lNDMzMDZmNWEzMmUifQ.ncEansC9KmS4KRzM7J-8X1GWxOZPa6paHyTa71o1-kYA47IxZlnta5V8HPorNDL-uiKy6JaxIa9s9qd8SgBfqNcf1LWjOnsjScJuvbnDthS4db0RTPgqN_roaBAf4O_vSFxhvDAFy796zNXpbRbo3HfVIC7la_K5Y-3Qg4PaviX2oI5Rs9jQ1ao4iWUsADDMkQHTNS5LSlgQee_tAk_DbtJ7tB2Fw6z8xr23BM7FksfxnYLH9HFYxv7NxLkNeeskEGkTVpMgQaQzNs19bVDzfG0O5zcHjxjQIx76Q1GotTD2V-x59_VilM0Avr39exhPRc8v3y6Jp5j0TtMd2LvTMWrGkrINW25mBijbuGB1xfMy7LsyPR8lerFt--xG_kelRK4HL76XaZF9pz73FU6IYCv9QpYothE_zVYOEkrmkaNltpfFckoCPMwY5dIN8_sco3P88X607XervKFVcs3ArCA8sL3mHjX--xZ_FK2A_5Jmi_oriSytU-uwQPbIbMATr5CPKOpwuIrkCugjOIi1HyojzSYcmSdxmM9MiOW5Qx92nTBVd1g_b6Px5bZzENXey2mFtDVLy2P2Eh8ihaZXY1IymTXKbJfn5rgEg5PjkdA_7dyrX-bBTg8xwX3vQH6y8_j_69vDHd57rivUcy_ZbQCz6QQCgVkVallpZZuk7U4", + "accessTokenHash": "5d07861e82306dcbcb9b5dbb7ad4789c19ea0c0208613400af30f1e3bd7fb481", + "refreshTokenHash": "f4c32cfb6450ca7ad9209efe58b3c26dae45a708c6820edd022df31659255850", + "expiresIn": 604800, + "scope": "profile", + "tokenType": "Bearer", + "codeChallenge": "", + "codeIsUsed": true, + "codeExpireIn": 0 + }, + { + "owner": "admin", + "name": "b3bc9cc8-ebe9-4be5-9f1b-439120a263d7", + "createdTime": "2025-09-20T10:48:20Z", + "application": "app-built-in", + "organization": "built-in", + "user": "admin", + "code": "3d4550d03ef798879df7", + "accessToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImNlcnQtYnVpbHQtaW4iLCJ0eXAiOiJKV1QifQ.eyJvd25lciI6ImJ1aWx0LWluIiwibmFtZSI6ImFkbWluIiwiY3JlYXRlZFRpbWUiOiIyMDI1LTA5LTIwVDEwOjQ3OjE3WiIsInVwZGF0ZWRUaW1lIjoiIiwiZGVsZXRlZFRpbWUiOiIiLCJpZCI6IjFlM2I0ZWU1LTcxNjQtNDdjNC1hNDIxLWEyZmY0OTM4Yzc2NSIsInR5cGUiOiJub3JtYWwtdXNlciIsInBhc3N3b3JkIjoiIiwicGFzc3dvcmRTYWx0IjoiIiwicGFzc3dvcmRUeXBlIjoicGxhaW4iLCJkaXNwbGF5TmFtZSI6IkFkbWluIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4ub3JnL2ltZy9jYXNiaW4uc3ZnIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6IiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxMjM0NTY3ODkxMCIsImNvdW50cnlDb2RlIjoiVVMiLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IkV4YW1wbGUgSW5jLiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjoyMDAwLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjp0cnVlLCJpc0ZvcmJpZGRlbiI6ZmFsc2UsImlzRGVsZXRlZCI6ZmFsc2UsInNpZ251cEFwcGxpY2F0aW9uIjoiYXBwLWJ1aWx0LWluIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIxMjcuMC4wLjEiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoiYWNjZXNzLXRva2VuIiwidGFnIjoic3RhZmYiLCJzY29wZSI6InByb2ZpbGUiLCJhenAiOiIxZDFlYjNjODkxZmE4ZmFhN2Q2MyIsImlzcyI6Imh0dHA6Ly8xNzIuMzAuMzQuMTg0OjgwMDQiLCJzdWIiOiIxZTNiNGVlNS03MTY0LTQ3YzQtYTQyMS1hMmZmNDkzOGM3NjUiLCJhdWQiOlsiMWQxZWIzYzg5MWZhOGZhYTdkNjMiXSwiZXhwIjoxNzU4OTcwMTAwLCJuYmYiOjE3NTgzNjUzMDAsImlhdCI6MTc1ODM2NTMwMCwianRpIjoiYWRtaW4vYjNiYzljYzgtZWJlOS00YmU1LTlmMWItNDM5MTIwYTI2M2Q3In0.GD4vk_rKUZ_bgNcgombRXVfoHNQE0KKifFZ0jvlGN7Se_OeJOkLdhJmPnR9LYgAr4hjZnqW90IL-ADJYcWswSS0bqk-D6so5srbDjxWNTa5EIxVOfG9JLBvGJl7spjvwLj84OIQNrtEOdL-4iHGcnK5bxMLoqvYApWWMZjcA99_tlibV4EBk3ajFMnGQAzrl-GhXvsglK0mk6DRWPJuzvHwRu3PvAUBegtBr5guT2WUC1VCS_FSxiwpdHcKAcqe-zArLRH7w84gs9IiR6-5Mqvx2QDO1c4yYH9DqTDplGoqK6Ln4KiIjO5MHu78zG_Mv4ywY-t0-qolZS0EnQ5JiJarZANbsI9SGIj7z_M5HhDYOYtcPvDl5DTq-gFOwyq0F7YJ2VcT9_pPKVm71nZAAkR9D0UocGCu_AHQAdvBK_3gwUYkeotITTGPj4M3U-HLoZwyy54lPjscPpLxaS_HMgeCe_GZSErOvGLV_s9cLJL3IJ5gXo5gc84DQHID-UkmLTAoj7wRwmr64STtGCKjsellJI0Jf62g4TDhOVYerd8l1K5oa520RB-gQ_PkV0nyyPIpVYpzCbByBDPxvjFmVLFgKE1NnYAeoAE-1AJbqH3E2sh9hps9oiYMWBCnym_1eL515_spRRJlxJlGCEETyhTUAYh_RrrMXjEit77P1GIE", + "refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJvd25lciI6ImJ1aWx0LWluIiwibmFtZSI6ImFkbWluIiwiY3JlYXRlZFRpbWUiOiIyMDI1LTA5LTIwVDEwOjQ3OjE3WiIsInVwZGF0ZWRUaW1lIjoiIiwiZGVsZXRlZFRpbWUiOiIiLCJpZCI6IjFlM2I0ZWU1LTcxNjQtNDdjNC1hNDIxLWEyZmY0OTM4Yzc2NSIsInR5cGUiOiJub3JtYWwtdXNlciIsInBhc3N3b3JkIjoiIiwicGFzc3dvcmRTYWx0IjoiIiwicGFzc3dvcmRUeXBlIjoicGxhaW4iLCJkaXNwbGF5TmFtZSI6IkFkbWluIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4ub3JnL2ltZy9jYXNiaW4uc3ZnIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6IiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxMjM0NTY3ODkxMCIsImNvdW50cnlDb2RlIjoiVVMiLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IkV4YW1wbGUgSW5jLiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjoyMDAwLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjp0cnVlLCJpc0ZvcmJpZGRlbiI6ZmFsc2UsImlzRGVsZXRlZCI6ZmFsc2UsInNpZ251cEFwcGxpY2F0aW9uIjoiYXBwLWJ1aWx0LWluIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIxMjcuMC4wLjEiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoicmVmcmVzaC10b2tlbiIsInRhZyI6InN0YWZmIiwic2NvcGUiOiJwcm9maWxlIiwiYXpwIjoiMWQxZWIzYzg5MWZhOGZhYTdkNjMiLCJpc3MiOiJodHRwOi8vMTcyLjMwLjM0LjE4NDo4MDA0Iiwic3ViIjoiMWUzYjRlZTUtNzE2NC00N2M0LWE0MjEtYTJmZjQ5MzhjNzY1IiwiYXVkIjpbIjFkMWViM2M4OTFmYThmYWE3ZDYzIl0sImV4cCI6MTc1ODk3MDEwMCwibmJmIjoxNzU4MzY1MzAwLCJpYXQiOjE3NTgzNjUzMDAsImp0aSI6ImFkbWluL2IzYmM5Y2M4LWViZTktNGJlNS05ZjFiLTQzOTEyMGEyNjNkNyJ9.NJmBGdkB_B8g6ETE-w3s_X68rmy0xQ3V6u6117nZzkMlyhGrQLWNvzBnsS-IpqDpF-AlZs8_5RXbqqE8UjBQQF4Bzx4iVX9uQU5aq-3V2-pfSj_NJC8vUCMWT4m8PW397ca0YoPj9O5CbW_zLhakwHrYCFl5KiWbUeCymiJXi1ga3Bb9F0HfcGs2bQzLaDf3b9QyKcnymMpPAIMKGJtT57PUvSiVkSKFbunG3tXlczGzRG98lKamZ5NLS1pJMCeYt3Q2_IfHk0VsfOz--0SLbEzf1k-NtPMVMBWc95BSAoLwbCzCQAaI8Yt5dkVqVkSVu3xlpHOGYJoQHONxiiPfu9apy1gGlbctFASbOUUlnSliuQa_dBgRfQhPOy44Jbe_sL-jPYjLqdNU8R4eOsoKrjJTx55uSREDw_jdZItrhz_c2a62JKJLTW3GauYUiFNTCx351wRtorrNAa7yQhsP6iKPNLYKQpgtiwRMcMl5uafYqfYCx5WjUmPnh_Dh2YfTG6xZRI9bon-HOTiX3LGqox4lsCKE7xw8fORmFfiJoQHZMT1oZQxhUYOnNaDol2yU1ItKBdDU2OYXJO8CTWx2Pf-3RkhCAJ1GPeGmWb-5fBcTwdjZpUEAcripw3KuAUHtBcj6bh-QJBuMN6Mq_oRMKmj0a2TNaxjcBxOynxrvLB8", + "accessTokenHash": "e8ca10541c424511e14bcb78df856404c90c8214eecb028b6f7a2d397bc17959", + "refreshTokenHash": "3169b450f72be004ea22b63ef669e242fc7eaac1366a1b66bca3f3d15be5e7ab", + "expiresIn": 604800, + "scope": "profile", + "tokenType": "Bearer", + "codeChallenge": "", + "codeIsUsed": true, + "codeExpireIn": 0 + }, + { + "owner": "admin", + "name": "bf581cf2-8eeb-41c0-aee2-a9a395725af5", + "createdTime": "2025-09-20T10:47:51Z", + "application": "app-built-in", + "organization": "built-in", + "user": "admin", + "code": "41f84c4861e1d0024daf", + "accessToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImNlcnQtYnVpbHQtaW4iLCJ0eXAiOiJKV1QifQ.eyJvd25lciI6ImJ1aWx0LWluIiwibmFtZSI6ImFkbWluIiwiY3JlYXRlZFRpbWUiOiIyMDI1LTA5LTIwVDEwOjQ3OjE3WiIsInVwZGF0ZWRUaW1lIjoiIiwiZGVsZXRlZFRpbWUiOiIiLCJpZCI6IjFlM2I0ZWU1LTcxNjQtNDdjNC1hNDIxLWEyZmY0OTM4Yzc2NSIsInR5cGUiOiJub3JtYWwtdXNlciIsInBhc3N3b3JkIjoiIiwicGFzc3dvcmRTYWx0IjoiIiwicGFzc3dvcmRUeXBlIjoicGxhaW4iLCJkaXNwbGF5TmFtZSI6IkFkbWluIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4ub3JnL2ltZy9jYXNiaW4uc3ZnIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6IiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxMjM0NTY3ODkxMCIsImNvdW50cnlDb2RlIjoiVVMiLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IkV4YW1wbGUgSW5jLiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjoyMDAwLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjp0cnVlLCJpc0ZvcmJpZGRlbiI6ZmFsc2UsImlzRGVsZXRlZCI6ZmFsc2UsInNpZ251cEFwcGxpY2F0aW9uIjoiYXBwLWJ1aWx0LWluIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIxMjcuMC4wLjEiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoiYWNjZXNzLXRva2VuIiwidGFnIjoic3RhZmYiLCJzY29wZSI6InByb2ZpbGUiLCJhenAiOiIxZDFlYjNjODkxZmE4ZmFhN2Q2MyIsImlzcyI6Imh0dHA6Ly8xNzIuMzAuMzQuMTg0OjgwMDQiLCJzdWIiOiIxZTNiNGVlNS03MTY0LTQ3YzQtYTQyMS1hMmZmNDkzOGM3NjUiLCJhdWQiOlsiMWQxZWIzYzg5MWZhOGZhYTdkNjMiXSwiZXhwIjoxNzU4OTcwMDcxLCJuYmYiOjE3NTgzNjUyNzEsImlhdCI6MTc1ODM2NTI3MSwianRpIjoiYWRtaW4vYmY1ODFjZjItOGVlYi00MWMwLWFlZTItYTlhMzk1NzI1YWY1In0.ysggMjMtH9BhmwQt87ds-9zCRNZqYLVcUPZuLU0XSBSOyz2pBWfcFHAwb_e5D2VGZx5AAQCOkOdQNASi6DbHMcA3eidejl4e6LsxxoEHQiumpLMcAFuyxLLlgnSrWbsBHAGZr5nvCnlUycX0Ioyt3Z-JRRrHnxg_7fr6ZRG-1-xyau8YeLlVt4j46Gc57dtoDQtv6R6_XFSfIrxBzQr6TITTtC_YVcKA3N_SvwlAuaulldEGWs_oBt4aYd_xyY8uZT-AsTLrf2WmvcDK4tN1gt7MAhPiyAZnsEoZA40T4495cAjaAXb0bPrON6v326A_irjqIayLiZvz3I9TYIId7tZrZG_0h17S9ebr4uK2bFGKAh5uRgrBI_x6rptctYs7IuxrwKRaoXklP530t1Lb7-aZRjKkG6Xx0C9XBGgOJmwx0nnZ0hxJsJ74J_8jJA9GepiItLzUvJNYQupBLQyVQLsdkCF7chiJtcZRNEIP8CtudEUcFT8y6fti_5XmIukCw_ftI5sAS8c7g-cm9Pwn9-6lvHwUjX3mvfccodnGsY2U7-6lj3u5LcTxcrvQ5Yc30-x-whaD9vzuMQ1Rf4UUCU_xFIq2nWyPzME6-XqieLY5TaxKMBqfHtG4fDNGeaYTFvx6to1ZD-v6LMUNJW-lGbZ4T9Ug2OpxV4mzL0lkHDY", + "refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJvd25lciI6ImJ1aWx0LWluIiwibmFtZSI6ImFkbWluIiwiY3JlYXRlZFRpbWUiOiIyMDI1LTA5LTIwVDEwOjQ3OjE3WiIsInVwZGF0ZWRUaW1lIjoiIiwiZGVsZXRlZFRpbWUiOiIiLCJpZCI6IjFlM2I0ZWU1LTcxNjQtNDdjNC1hNDIxLWEyZmY0OTM4Yzc2NSIsInR5cGUiOiJub3JtYWwtdXNlciIsInBhc3N3b3JkIjoiIiwicGFzc3dvcmRTYWx0IjoiIiwicGFzc3dvcmRUeXBlIjoicGxhaW4iLCJkaXNwbGF5TmFtZSI6IkFkbWluIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4ub3JnL2ltZy9jYXNiaW4uc3ZnIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6IiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxMjM0NTY3ODkxMCIsImNvdW50cnlDb2RlIjoiVVMiLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IkV4YW1wbGUgSW5jLiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjoyMDAwLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjp0cnVlLCJpc0ZvcmJpZGRlbiI6ZmFsc2UsImlzRGVsZXRlZCI6ZmFsc2UsInNpZ251cEFwcGxpY2F0aW9uIjoiYXBwLWJ1aWx0LWluIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIxMjcuMC4wLjEiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoicmVmcmVzaC10b2tlbiIsInRhZyI6InN0YWZmIiwic2NvcGUiOiJwcm9maWxlIiwiYXpwIjoiMWQxZWIzYzg5MWZhOGZhYTdkNjMiLCJpc3MiOiJodHRwOi8vMTcyLjMwLjM0LjE4NDo4MDA0Iiwic3ViIjoiMWUzYjRlZTUtNzE2NC00N2M0LWE0MjEtYTJmZjQ5MzhjNzY1IiwiYXVkIjpbIjFkMWViM2M4OTFmYThmYWE3ZDYzIl0sImV4cCI6MTc1ODk3MDA3MSwibmJmIjoxNzU4MzY1MjcxLCJpYXQiOjE3NTgzNjUyNzEsImp0aSI6ImFkbWluL2JmNTgxY2YyLThlZWItNDFjMC1hZWUyLWE5YTM5NTcyNWFmNSJ9.FwFmS1F0j9OoVguQiPghg4JsrwM7z_RI2o6hiBBxbL0OTG1uCtOtoHjlB7e8naoGZrfs8GoC7Q_GWjkVBv_uViWmMoOr9-LLjJb96UdhwcDW1jaeTx-ZoFqOr3xuoY9B44TKiXyP69IEI7fCn6_xDPSRlJNLXSE7UtIL3p_eEEYcI8GNhhSYwpQzSYbQLiFmU-du9Ic7kTscALQb6MRwF6duyqOtsjLuNnqX7fbauH3wwUqbP57PN0usniuIgpW5XPySBtm_688WCOqLipptSrQ12NZejTA2H8P3FZvZUj5VS7snN-1bQdX06B4rYNIU4bLZQd5Q-TfZEWX-JIYobhv8nyqBVcjUDYxl57cFzKVKPiXibrfp0Z5qHiBDZgRAvylRkFUsGgI1GCSXNBqJjVQw1eyhTXn3dlQpvMMZ7zqIWFDILtIV_9pFHH04XbHT7ogprKzXgHoxznFKnytM4BrloH-XNRGr9Ka6Mk-uVyVgMq3hS5Yk2wjQVnWbN8oQx4GwuxqMd3UqfY-2Ba4OxJsvWuW2PikW284q-QmcmphX75nuLlaP104WbBG7S1A9_WYdI37IPGAA7wLwBoLt2y1sx6pYRUsrqj9NG5CCWtgnMAWkkFXWAwA3_ipgcfEWDB7VzlGiqvsPFy54VAHJ1oZUvnmE2go5Dx7RIM1VHGk", + "accessTokenHash": "f2e809e71a22b29909f9f1c6e37133ee9a4d38c56f6646cfc9b671aad8ffadc7", + "refreshTokenHash": "5dea79cefe422c3e696e4f7245703b6c1e160cc1631787b5dddb206c35c2024b", + "expiresIn": 604800, + "scope": "profile", + "tokenType": "Bearer", + "codeChallenge": "", + "codeIsUsed": true, + "codeExpireIn": 0 + } + ], + "webhooks": [], + "groups": [], + "adapters": [ + { + "owner": "built-in", + "name": "api-adapter-built-in", + "createdTime": "2025-09-20T10:47:18Z", + "table": "casbin_api_rule", + "useSameDb": true, + "type": "", + "databaseType": "", + "host": "", + "port": 0, + "user": "", + "password": "", + "database": "" + }, + { + "owner": "built-in", + "name": "user-adapter-built-in", + "createdTime": "2025-09-20T10:47:18Z", + "table": "casbin_user_rule", + "useSameDb": true, + "type": "", + "databaseType": "", + "host": "", + "port": 0, + "user": "", + "password": "", + "database": "" + } + ], + "enforcers": [ + { + "owner": "built-in", + "name": "api-enforcer-built-in", + "createdTime": "2025-09-20T10:47:18Z", + "updatedTime": "2025-09-20 10:47:18", + "displayName": "API Enforcer", + "description": "", + "model": "built-in/api-model-built-in", + "adapter": "built-in/api-adapter-built-in", + "modelCfg": null + }, + { + "owner": "built-in", + "name": "user-enforcer-built-in", + "createdTime": "2025-09-20T10:47:18Z", + "updatedTime": "2025-09-20 10:47:18", + "displayName": "User Enforcer", + "description": "", + "model": "built-in/user-model-built-in", + "adapter": "built-in/user-adapter-built-in", + "modelCfg": null + } + ], + "plans": [], + "pricings": [], + "invitations": [], + "records": [ + { + "id": 26, + "owner": "built-in", + "name": "2284aa5d-ad34-402a-a73b-d97a4819409b", + "createdTime": "2025-09-20T10:59:43Z", + "organization": "built-in", + "clientIp": "10.10.125.231", + "user": "admin", + "method": "POST", + "requestUri": "/api/login", + "action": "login", + "language": "zh", + "object": "{\"application\":\"app-built-in\",\"organization\":\"built-in\",\"username\":\"admin\",\"password\":\"***\",\"autoSignin\":true,\"language\":\"\",\"signinMethod\":\"Password\",\"type\":\"login\"}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 25, + "owner": "built-in", + "name": "420a7908-d3fd-4630-aa30-f9afa20260d2", + "createdTime": "2025-09-20T10:58:45Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-role?id=example-org/example-role", + "action": "update-role", + "language": "zh", + "object": "{\"owner\":\"example-org\",\"name\":\"example-role\",\"createdTime\":\"2025-09-20T18:58:05+08:00\",\"displayName\":\"示例角色\",\"description\":\"\",\"users\":[\"example-org/example-user\"],\"groups\":[],\"roles\":[],\"domains\":[],\"isEnabled\":true}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 24, + "owner": "built-in", + "name": "97faa108-d69f-449c-a2fa-c76e90a5fbd5", + "createdTime": "2025-09-20T10:58:41Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-role?id=example-org/example-role", + "action": "update-role", + "language": "zh", + "object": "{\"owner\":\"example-org\",\"name\":\"example-role\",\"createdTime\":\"2025-09-20T18:58:05+08:00\",\"displayName\":\"示例角色\",\"description\":\"\",\"users\":[\"example-org/example-user\"],\"groups\":[],\"roles\":[],\"domains\":[],\"isEnabled\":true}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 23, + "owner": "built-in", + "name": "c54b07c2-b470-40d7-a542-3cf234b10e75", + "createdTime": "2025-09-20T10:58:33Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-role?id=built-in/example-role", + "action": "update-role", + "language": "zh", + "object": "{\"owner\":\"example-org\",\"name\":\"example-role\",\"createdTime\":\"2025-09-20T18:58:05+08:00\",\"displayName\":\"示例角色\",\"description\":\"\",\"users\":[],\"groups\":[],\"roles\":[],\"domains\":[],\"isEnabled\":true}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 22, + "owner": "built-in", + "name": "e51bbeba-bdf3-4ef4-9130-b3c29007e5f2", + "createdTime": "2025-09-20T10:58:31Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-role?id=built-in/role_s52ltl", + "action": "update-role", + "language": "zh", + "object": "{\"owner\":\"example-org\",\"name\":\"example-role\",\"createdTime\":\"2025-09-20T18:58:05+08:00\",\"displayName\":\"示例角色\",\"description\":\"\",\"users\":[],\"groups\":[],\"roles\":[],\"domains\":[],\"isEnabled\":true}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 21, + "owner": "built-in", + "name": "76c504fe-ef57-47e2-9b38-f37bc9254fdb", + "createdTime": "2025-09-20T10:58:05Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/add-role", + "action": "add-role", + "language": "zh", + "object": "{\"owner\":\"built-in\",\"name\":\"role_s52ltl\",\"createdTime\":\"2025-09-20T18:58:05+08:00\",\"displayName\":\"New Role - s52ltl\",\"users\":[],\"groups\":[],\"roles\":[],\"domains\":[],\"isEnabled\":true}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 20, + "owner": "built-in", + "name": "d8f347d3-880c-4991-8094-b61c24aaeefd", + "createdTime": "2025-09-20T10:57:13Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/add-role", + "action": "add-role", + "language": "zh", + "object": "{\"owner\":\"built-in\",\"name\":\"role_m06bnm\",\"createdTime\":\"2025-09-20T18:57:13+08:00\",\"displayName\":\"New Role - m06bnm\",\"users\":[],\"groups\":[],\"roles\":[],\"domains\":[],\"isEnabled\":true}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 19, + "owner": "built-in", + "name": "00355afa-dbab-48a5-a3b1-fd6e96e834f6", + "createdTime": "2025-09-20T10:57:09Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-user?id=example-org/example-user", + "action": "update-user", + "language": "zh", + "object": "{\"owner\":\"example-org\",\"name\":\"example-user\",\"createdTime\":\"2025-09-20T10:56:21Z\",\"updatedTime\":\"\",\"deletedTime\":\"\",\"id\":\"3d7cca2b-8da9-41bf-b535-6c9f83d731db\",\"externalId\":\"\",\"type\":\"normal-user\",\"password\":\"***\",\"passwordSalt\":\"\",\"passwordType\":\"plain\",\"displayName\":\"示例用户\",\"firstName\":\"\",\"lastName\":\"\",\"avatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"avatarType\":\"\",\"permanentAvatar\":\"\",\"email\":\"\",\"emailVerified\":false,\"phone\":\"18888888888\",\"countryCode\":\"CN\",\"region\":\"\",\"location\":\"\",\"address\":[],\"affiliation\":\"\",\"title\":\"\",\"idCardType\":\"\",\"idCard\":\"\",\"homepage\":\"\",\"bio\":\"\",\"tag\":\"\",\"language\":\"\",\"gender\":\"\",\"birthday\":\"\",\"education\":\"\",\"score\":0,\"karma\":0,\"ranking\":1,\"balance\":0,\"currency\":\"\",\"isDefaultAvatar\":false,\"isOnline\":false,\"isAdmin\":false,\"isForbidden\":false,\"isDeleted\":false,\"signupApplication\":\"example-app\",\"hash\":\"\",\"preHash\":\"\",\"accessKey\":\"\",\"accessSecret\":\"\",\"accessToken\":\"\",\"createdIp\":\"\",\"lastSigninTime\":\"\",\"lastSigninIp\":\"\",\"github\":\"\",\"google\":\"\",\"qq\":\"\",\"wechat\":\"\",\"facebook\":\"\",\"dingtalk\":\"\",\"weibo\":\"\",\"gitee\":\"\",\"linkedin\":\"\",\"wecom\":\"\",\"lark\":\"\",\"gitlab\":\"\",\"adfs\":\"\",\"baidu\":\"\",\"alipay\":\"\",\"casdoor\":\"\",\"infoflow\":\"\",\"apple\":\"\",\"azuread\":\"\",\"azureadb2c\":\"\",\"slack\":\"\",\"steam\":\"\",\"bilibili\":\"\",\"okta\":\"\",\"douyin\":\"\",\"kwai\":\"\",\"line\":\"\",\"amazon\":\"\",\"auth0\":\"\",\"battlenet\":\"\",\"bitbucket\":\"\",\"box\":\"\",\"cloudfoundry\":\"\",\"dailymotion\":\"\",\"deezer\":\"\",\"digitalocean\":\"\",\"discord\":\"\",\"dropbox\":\"\",\"eveonline\":\"\",\"fitbit\":\"\",\"gitea\":\"\",\"heroku\":\"\",\"influxcloud\":\"\",\"instagram\":\"\",\"intercom\":\"\",\"kakao\":\"\",\"lastfm\":\"\",\"mailru\":\"\",\"meetup\":\"\",\"microsoftonline\":\"\",\"naver\":\"\",\"nextcloud\":\"\",\"onedrive\":\"\",\"oura\":\"\",\"patreon\":\"\",\"paypal\":\"\",\"salesforce\":\"\",\"shopify\":\"\",\"soundcloud\":\"\",\"spotify\":\"\",\"strava\":\"\",\"stripe\":\"\",\"tiktok\":\"\",\"tumblr\":\"\",\"twitch\":\"\",\"twitter\":\"\",\"typetalk\":\"\",\"uber\":\"\",\"vk\":\"\",\"wepay\":\"\",\"xero\":\"\",\"yahoo\":\"\",\"yammer\":\"\",\"yandex\":\"\",\"zoom\":\"\",\"metamask\":\"\",\"web3onboard\":\"\",\"custom\":\"\",\"webauthnCredentials\":null,\"preferredMfaType\":\"\",\"recoveryCodes\":null,\"totpSecret\":\"\",\"mfaPhoneEnabled\":false,\"mfaEmailEnabled\":false,\"multiFactorAuths\":[{\"enabled\":false,\"isPreferred\":false,\"mfaType\":\"sms\",\"mfaRememberInHours\":0},{\"enabled\":false,\"isPreferred\":false,\"mfaType\":\"email\",\"mfaRememberInHours\":0},{\"enabled\":false,\"isPreferred\":false,\"mfaType\":\"app\",\"mfaRememberInHours\":0}],\"invitation\":\"\",\"invitationCode\":\"\",\"faceIds\":null,\"ldap\":\"\",\"properties\":{},\"roles\":[],\"permissions\":[],\"groups\":[],\"lastChangePasswordTime\":\"\",\"lastSigninWrongTime\":\"\",\"signinWrongTimes\":0,\"managedAccounts\":null,\"mfaAccounts\":null,\"mfaItems\":null,\"mfaRememberDeadline\":\"\",\"needUpdatePassword\":false,\"ipWhitelist\":\"\"}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 18, + "owner": "built-in", + "name": "5a427026-bfbf-48fc-8a1e-ae8e4e573e0e", + "createdTime": "2025-09-20T10:56:34Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/login", + "action": "login", + "language": "zh", + "object": "{\"application\":\"app-built-in\",\"organization\":\"built-in\",\"username\":\"admin\",\"password\":\"***\",\"autoSignin\":true,\"language\":\"\",\"signinMethod\":\"Password\",\"type\":\"login\"}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 17, + "owner": "example-org", + "name": "7f808e0b-2a32-4b18-9cd1-97e732113c1c", + "createdTime": "2025-09-20T10:56:27Z", + "organization": "example-org", + "clientIp": "10.10.122.195", + "user": "example-user", + "method": "POST", + "requestUri": "/api/logout", + "action": "logout", + "language": "zh", + "object": "", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 16, + "owner": "example-org", + "name": "4bc172fd-f388-4423-8314-c7f9b6f6a433", + "createdTime": "2025-09-20T10:56:21Z", + "organization": "example-org", + "clientIp": "10.10.122.195", + "user": "example-user", + "method": "POST", + "requestUri": "/api/signup", + "action": "new-user", + "language": "zh", + "object": "{\"owner\":\"example-org\",\"name\":\"example-user\",\"createdTime\":\"2025-09-20T10:56:21Z\",\"updatedTime\":\"\",\"deletedTime\":\"\",\"id\":\"3d7cca2b-8da9-41bf-b535-6c9f83d731db\",\"externalId\":\"\",\"type\":\"normal-user\",\"password\":\"***\",\"passwordSalt\":\"\",\"passwordType\":\"plain\",\"displayName\":\"示例用户\",\"firstName\":\"\",\"lastName\":\"\",\"avatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"avatarType\":\"\",\"permanentAvatar\":\"\",\"email\":\"\",\"emailVerified\":false,\"phone\":\"18888888888\",\"countryCode\":\"CN\",\"region\":\"\",\"location\":\"\",\"address\":[],\"affiliation\":\"\",\"title\":\"\",\"idCardType\":\"\",\"idCard\":\"\",\"homepage\":\"\",\"bio\":\"\",\"tag\":\"\",\"language\":\"\",\"gender\":\"\",\"birthday\":\"\",\"education\":\"\",\"score\":0,\"karma\":0,\"ranking\":1,\"balance\":0,\"currency\":\"\",\"isDefaultAvatar\":false,\"isOnline\":false,\"isAdmin\":false,\"isForbidden\":false,\"isDeleted\":false,\"signupApplication\":\"example-app\",\"hash\":\"\",\"preHash\":\"\",\"accessKey\":\"\",\"accessSecret\":\"\",\"accessToken\":\"\",\"createdIp\":\"\",\"lastSigninTime\":\"\",\"lastSigninIp\":\"\",\"github\":\"\",\"google\":\"\",\"qq\":\"\",\"wechat\":\"\",\"facebook\":\"\",\"dingtalk\":\"\",\"weibo\":\"\",\"gitee\":\"\",\"linkedin\":\"\",\"wecom\":\"\",\"lark\":\"\",\"gitlab\":\"\",\"adfs\":\"\",\"baidu\":\"\",\"alipay\":\"\",\"casdoor\":\"\",\"infoflow\":\"\",\"apple\":\"\",\"azuread\":\"\",\"azureadb2c\":\"\",\"slack\":\"\",\"steam\":\"\",\"bilibili\":\"\",\"okta\":\"\",\"douyin\":\"\",\"kwai\":\"\",\"line\":\"\",\"amazon\":\"\",\"auth0\":\"\",\"battlenet\":\"\",\"bitbucket\":\"\",\"box\":\"\",\"cloudfoundry\":\"\",\"dailymotion\":\"\",\"deezer\":\"\",\"digitalocean\":\"\",\"discord\":\"\",\"dropbox\":\"\",\"eveonline\":\"\",\"fitbit\":\"\",\"gitea\":\"\",\"heroku\":\"\",\"influxcloud\":\"\",\"instagram\":\"\",\"intercom\":\"\",\"kakao\":\"\",\"lastfm\":\"\",\"mailru\":\"\",\"meetup\":\"\",\"microsoftonline\":\"\",\"naver\":\"\",\"nextcloud\":\"\",\"onedrive\":\"\",\"oura\":\"\",\"patreon\":\"\",\"paypal\":\"\",\"salesforce\":\"\",\"shopify\":\"\",\"soundcloud\":\"\",\"spotify\":\"\",\"strava\":\"\",\"stripe\":\"\",\"tiktok\":\"\",\"tumblr\":\"\",\"twitch\":\"\",\"twitter\":\"\",\"typetalk\":\"\",\"uber\":\"\",\"vk\":\"\",\"wepay\":\"\",\"xero\":\"\",\"yahoo\":\"\",\"yammer\":\"\",\"yandex\":\"\",\"zoom\":\"\",\"metamask\":\"\",\"web3onboard\":\"\",\"custom\":\"\",\"webauthnCredentials\":null,\"preferredMfaType\":\"\",\"recoveryCodes\":null,\"totpSecret\":\"\",\"mfaPhoneEnabled\":false,\"mfaEmailEnabled\":false,\"invitation\":\"\",\"invitationCode\":\"\",\"faceIds\":null,\"ldap\":\"\",\"properties\":{},\"roles\":null,\"permissions\":null,\"groups\":null,\"lastChangePasswordTime\":\"\",\"lastSigninWrongTime\":\"\",\"signinWrongTimes\":0,\"managedAccounts\":null,\"mfaAccounts\":null,\"mfaItems\":null,\"mfaRememberDeadline\":\"\",\"needUpdatePassword\":false,\"ipWhitelist\":\"\"}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 0, + "isTriggered": true + }, + { + "id": 15, + "owner": "example-org", + "name": "4bc172fd-f388-4423-8314-c7f9b6f6a433", + "createdTime": "2025-09-20T10:56:21Z", + "organization": "example-org", + "clientIp": "10.10.122.195", + "user": "example-user", + "method": "POST", + "requestUri": "/api/signup", + "action": "signup", + "language": "zh", + "object": "{\"application\":\"example-app\",\"organization\":\"example-org\",\"username\":\"example-user\",\"name\":\"示例用户\",\"password\":\"***\",\"confirm\":\"123456\",\"countryCode\":\"CN\",\"phone\":\"18888888888\",\"agreement\":true,\"plan\":null,\"pricing\":null}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 14, + "owner": "", + "name": "745e0e6a-5194-4d79-a3cd-90551104fd3c", + "createdTime": "2025-09-20T10:55:17Z", + "organization": "", + "clientIp": "10.10.122.195", + "user": "", + "method": "POST", + "requestUri": "/api/login", + "action": "login", + "language": "zh", + "object": "{\"application\":\"example-app\",\"organization\":\"example-org\",\"username\":\"admin\",\"password\":\"***\",\"autoSignin\":true,\"language\":\"\",\"signinMethod\":\"Password\",\"type\":\"login\"}", + "response": "{status:\"error\", msg:\"用户: example-org/admin不存在\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 13, + "owner": "built-in", + "name": "cb140d8a-27a4-4a60-8185-e60db48ddbfb", + "createdTime": "2025-09-20T10:54:57Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/logout", + "action": "logout", + "language": "zh", + "object": "", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 12, + "owner": "built-in", + "name": "deb63bd0-cfb4-4ddb-80da-0878359aeee9", + "createdTime": "2025-09-20T10:54:42Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/add-user", + "action": "add-user", + "language": "zh", + "object": "{\"owner\":\"built-in\",\"name\":\"user_wght4c\",\"createdTime\":\"2025-09-20T18:54:42+08:00\",\"type\":\"normal-user\",\"password\":\"***\",\"passwordSalt\":\"\",\"displayName\":\"New User - wght4c\",\"avatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"email\":\"wght4c@example.com\",\"phone\":\"30037413383\",\"countryCode\":\"US\",\"address\":[],\"groups\":[],\"affiliation\":\"Example Inc.\",\"tag\":\"staff\",\"region\":\"\",\"isAdmin\":true,\"IsForbidden\":false,\"score\":2000,\"isDeleted\":false,\"properties\":{},\"signupApplication\":\"\"}", + "response": "{status:\"error\", msg:\"目前,向'built-in'组织添加新用户的功能已禁用。请注意:'built-in'组织中的所有用户均为Casdoor的全局管理员。请参阅文档:https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself。如果您仍希望为built-in组织创建用户,请转到该组织的设置页面并启用“特权同意”选项。\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 11, + "owner": "built-in", + "name": "e56c3765-842f-4d9e-adda-9a526d99aed9", + "createdTime": "2025-09-20T10:54:37Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/add-user", + "action": "add-user", + "language": "zh", + "object": "{\"owner\":\"built-in\",\"name\":\"user_1ub2fs\",\"createdTime\":\"2025-09-20T18:54:37+08:00\",\"type\":\"normal-user\",\"password\":\"***\",\"passwordSalt\":\"\",\"displayName\":\"New User - 1ub2fs\",\"avatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"email\":\"1ub2fs@example.com\",\"phone\":\"23130608354\",\"countryCode\":\"US\",\"address\":[],\"groups\":[],\"affiliation\":\"Example Inc.\",\"tag\":\"staff\",\"region\":\"\",\"isAdmin\":true,\"IsForbidden\":false,\"score\":2000,\"isDeleted\":false,\"properties\":{},\"signupApplication\":\"\"}", + "response": "{status:\"error\", msg:\"目前,向'built-in'组织添加新用户的功能已禁用。请注意:'built-in'组织中的所有用户均为Casdoor的全局管理员。请参阅文档:https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself。如果您仍希望为built-in组织创建用户,请转到该组织的设置页面并启用“特权同意”选项。\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 10, + "owner": "built-in", + "name": "9bcd72a5-d4dc-47ab-b300-d7b984507762", + "createdTime": "2025-09-20T10:54:29Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-organization?id=admin/example-org", + "action": "update-organization", + "language": "zh", + "object": "{\"owner\":\"admin\",\"name\":\"example-org\",\"createdTime\":\"2025-09-20T18:48:24+08:00\",\"displayName\":\"示例组织\",\"websiteUrl\":\"https://door.casdoor.com\",\"logo\":\"\",\"logoDark\":\"\",\"favicon\":\"https://cdn.casbin.org/img/favicon.png\",\"hasPrivilegeConsent\":false,\"passwordType\":\"plain\",\"passwordSalt\":\"\",\"passwordOptions\":[\"AtLeast6\"],\"passwordObfuscatorType\":\"Plain\",\"passwordObfuscatorKey\":\"\",\"passwordExpireDays\":0,\"countryCodes\":[\"CN\"],\"defaultAvatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"defaultApplication\":\"example-app\",\"userTypes\":null,\"tags\":[],\"languages\":[\"en\",\"es\",\"fr\",\"de\",\"zh\",\"id\",\"ja\",\"ko\",\"ru\",\"vi\",\"pt\",\"it\",\"ms\",\"tr\",\"ar\",\"he\",\"nl\",\"pl\",\"fi\",\"sv\",\"uk\",\"kk\",\"fa\",\"cs\",\"sk\",\"az\"],\"themeData\":null,\"masterPassword\":\"\",\"defaultPassword\":\"\",\"masterVerificationCode\":\"\",\"ipWhitelist\":\"\",\"initScore\":0,\"enableSoftDeletion\":false,\"isProfilePublic\":true,\"useEmailAsUsername\":false,\"enableTour\":true,\"disableSignin\":false,\"ipRestriction\":\"\",\"navItems\":null,\"widgetItems\":null,\"mfaItems\":null,\"mfaRememberInHours\":12,\"accountItems\":[{\"name\":\"Organization\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"ID\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Display name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Avatar\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"User type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Password\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Email\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Phone\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Country code\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Country/Region\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Location\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Address\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Affiliation\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Title\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"ID card type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"ID card\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"ID card info\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Homepage\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Bio\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Tag\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Language\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Gender\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Birthday\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Education\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Score\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Karma\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Ranking\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Signup application\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"API key\",\"visible\":false,\"viewRule\":\"\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Groups\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Roles\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Permissions\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"3rd-party logins\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Properties\",\"visible\":false,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is online\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is admin\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is forbidden\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is deleted\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Multi-factor authentication\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"WebAuthn credentials\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Managed accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"MFA accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"}],\"enableDarkLogo\":false}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 9, + "owner": "built-in", + "name": "17e560c6-e5a8-4f16-8f0b-8b86b39dcab9", + "createdTime": "2025-09-20T10:54:20Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-application?id=admin/example-app", + "action": "update-application", + "language": "zh", + "object": "{\"owner\":\"admin\",\"name\":\"example-app\",\"createdTime\":\"2025-09-20T18:50:08+08:00\",\"displayName\":\"示例应用\",\"logo\":\"https://cdn.casbin.org/img/casdoor-logo_1185x256.png\",\"order\":0,\"homepageUrl\":\"\",\"description\":\"\",\"organization\":\"example-org\",\"cert\":\"cert-built-in\",\"defaultGroup\":\"\",\"headerHtml\":\"\",\"enablePassword\":true,\"enableSignUp\":true,\"disableSignin\":false,\"enableSigninSession\":false,\"enableAutoSignin\":false,\"enableCodeSignin\":false,\"enableSamlCompress\":false,\"enableSamlC14n10\":false,\"enableSamlPostBinding\":false,\"useEmailAsSamlNameId\":false,\"enableWebAuthn\":false,\"enableLinkWithEmail\":false,\"orgChoiceMode\":\"\",\"samlReplyUrl\":\"\",\"providers\":[{\"owner\":\"\",\"name\":\"provider_captcha_default\",\"canSignUp\":false,\"canSignIn\":false,\"canUnlink\":false,\"countryCodes\":null,\"prompted\":false,\"signupGroup\":\"\",\"rule\":\"\",\"provider\":{\"owner\":\"admin\",\"name\":\"provider_captcha_default\",\"createdTime\":\"2025-09-20T10:47:17Z\",\"displayName\":\"Captcha Default\",\"category\":\"Captcha\",\"type\":\"Default\",\"subType\":\"\",\"method\":\"\",\"clientId\":\"\",\"clientSecret\":\"\",\"clientId2\":\"\",\"clientSecret2\":\"\",\"cert\":\"\",\"customAuthUrl\":\"\",\"customTokenUrl\":\"\",\"customUserInfoUrl\":\"\",\"customLogo\":\"\",\"scopes\":\"\",\"userMapping\":null,\"httpHeaders\":null,\"host\":\"\",\"port\":0,\"disableSsl\":false,\"title\":\"\",\"content\":\"\",\"receiver\":\"\",\"regionId\":\"\",\"signName\":\"\",\"templateCode\":\"\",\"appId\":\"\",\"endpoint\":\"\",\"intranetEndpoint\":\"\",\"domain\":\"\",\"bucket\":\"\",\"pathPrefix\":\"\",\"metadata\":\"\",\"idP\":\"\",\"issuerUrl\":\"\",\"enableSignAuthnRequest\":false,\"emailRegex\":\"\",\"providerUrl\":\"\"}}],\"signinMethods\":[{\"name\":\"Password\",\"displayName\":\"Password\",\"rule\":\"All\"}],\"signupItems\":[{\"name\":\"ID\",\"visible\":false,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"Random\"},{\"name\":\"Username\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Display name\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Password\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Confirm password\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Email\",\"visible\":false,\"required\":false,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"No verification\"},{\"name\":\"Phone\",\"visible\":true,\"required\":false,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"No verification\"},{\"name\":\"Agreement\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Signup button\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Providers\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n }\\n .provider-big-img {\\n margin-bottom: 10px;\\n }\\n \",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"small\"}],\"signinItems\":[{\"name\":\"Back button\",\"visible\":true,\"label\":\"\",\"customCss\":\".back-button {\\n top: 65px;\\n left: 15px;\\n position: absolute;\\n}\\n.back-inner-button{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Languages\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-languages {\\n top: 55px;\\n right: 5px;\\n position: absolute;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Logo\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-logo-box {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Signin methods\",\"visible\":true,\"label\":\"\",\"customCss\":\".signin-methods {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Username\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-username {}\\n.login-username-input{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Password\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-password {}\\n.login-password-input{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Agreement\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-agreement {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Forgot password?\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-forget-password {\\n display: inline-flex;\\n justify-content: space-between;\\n width: 320px;\\n margin-bottom: 25px;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Login button\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-button-box {\\n margin-bottom: 5px;\\n}\\n.login-button {\\n width: 100%;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Signup link\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-signup-link {\\n margin-bottom: 24px;\\n display: flex;\\n justify-content: end;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Providers\",\"visible\":true,\"label\":\"\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n}\\n.provider-big-img {\\n margin-bottom: 10px;\\n}\",\"placeholder\":\"\",\"rule\":\"small\",\"isCustom\":false}],\"grantTypes\":[\"authorization_code\",\"password\",\"client_credentials\",\"token\",\"id_token\",\"refresh_token\"],\"organizationObj\":{\"owner\":\"admin\",\"name\":\"built-in\",\"createdTime\":\"2025-09-20T10:47:17Z\",\"displayName\":\"Built-in Organization\",\"websiteUrl\":\"https://example.com\",\"logo\":\"\",\"logoDark\":\"\",\"favicon\":\"https://cdn.casbin.org/img/casbin/favicon.ico\",\"hasPrivilegeConsent\":false,\"passwordType\":\"plain\",\"passwordSalt\":\"\",\"passwordOptions\":[\"AtLeast6\"],\"passwordObfuscatorType\":\"\",\"passwordObfuscatorKey\":\"\",\"passwordExpireDays\":0,\"countryCodes\":[\"US\",\"ES\",\"FR\",\"DE\",\"GB\",\"CN\",\"JP\",\"KR\",\"VN\",\"ID\",\"SG\",\"IN\"],\"defaultAvatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"defaultApplication\":\"\",\"userTypes\":[],\"tags\":[],\"languages\":[\"en\",\"zh\",\"es\",\"fr\",\"de\",\"id\",\"ja\",\"ko\",\"ru\",\"vi\",\"pt\"],\"themeData\":null,\"masterPassword\":\"\",\"defaultPassword\":\"\",\"masterVerificationCode\":\"\",\"ipWhitelist\":\"\",\"initScore\":2000,\"enableSoftDeletion\":false,\"isProfilePublic\":false,\"useEmailAsUsername\":false,\"enableTour\":true,\"disableSignin\":false,\"ipRestriction\":\"\",\"navItems\":null,\"widgetItems\":null,\"mfaItems\":null,\"mfaRememberInHours\":0,\"accountItems\":[{\"name\":\"Organization\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"ID\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Display name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Avatar\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"User type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Password\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Email\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Phone\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Country code\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Country/Region\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Location\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Affiliation\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Title\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Homepage\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Bio\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Tag\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Signup application\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Roles\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Permissions\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Groups\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"3rd-party logins\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Properties\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is admin\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is forbidden\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is deleted\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Multi-factor authentication\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"WebAuthn credentials\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Managed accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"MFA accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"}]},\"certPublicKey\":\"\",\"tags\":[],\"samlAttributes\":null,\"isShared\":false,\"ipRestriction\":\"\",\"clientId\":\"e3ba6fec42cfe996121f\",\"clientSecret\":\"0c18bf2a11ffbb756ec6ce47dae9e09bdd48e3dd\",\"redirectUris\":[\"http://localhost:9000/callback\"],\"forcedRedirectOrigin\":\"\",\"tokenFormat\":\"JWT\",\"tokenSigningMethod\":\"\",\"tokenFields\":[],\"expireInHours\":168,\"refreshExpireInHours\":168,\"signupUrl\":\"\",\"signinUrl\":\"\",\"forgetUrl\":\"\",\"affiliationUrl\":\"\",\"ipWhitelist\":\"\",\"termsOfUse\":\"\",\"signupHtml\":\"\",\"signinHtml\":\"\",\"themeData\":null,\"footerHtml\":\"\",\"formCss\":\"\",\"formCssMobile\":\"\",\"formOffset\":2,\"formSideHtml\":\"\",\"formBackgroundUrl\":\"\",\"formBackgroundUrlMobile\":\"\",\"failedSigninLimit\":5,\"failedSigninFrozenTime\":15}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 8, + "owner": "built-in", + "name": "c3c1335b-785b-4a27-b12a-96bc649a78fb", + "createdTime": "2025-09-20T10:54:20Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-application?id=admin/example-app", + "action": "update-application", + "language": "zh", + "object": "{\"owner\":\"admin\",\"name\":\"example-app\",\"createdTime\":\"2025-09-20T18:50:08+08:00\",\"displayName\":\"示例应用\",\"logo\":\"https://cdn.casbin.org/img/casdoor-logo_1185x256.png\",\"order\":0,\"homepageUrl\":\"\",\"description\":\"\",\"organization\":\"example-org\",\"cert\":\"cert-built-in\",\"defaultGroup\":\"\",\"headerHtml\":\"\",\"enablePassword\":true,\"enableSignUp\":true,\"disableSignin\":false,\"enableSigninSession\":false,\"enableAutoSignin\":false,\"enableCodeSignin\":false,\"enableSamlCompress\":false,\"enableSamlC14n10\":false,\"enableSamlPostBinding\":false,\"useEmailAsSamlNameId\":false,\"enableWebAuthn\":false,\"enableLinkWithEmail\":false,\"orgChoiceMode\":\"\",\"samlReplyUrl\":\"\",\"providers\":[{\"owner\":\"\",\"name\":\"provider_captcha_default\",\"canSignUp\":false,\"canSignIn\":false,\"canUnlink\":false,\"countryCodes\":null,\"prompted\":false,\"signupGroup\":\"\",\"rule\":\"\",\"provider\":{\"owner\":\"admin\",\"name\":\"provider_captcha_default\",\"createdTime\":\"2025-09-20T10:47:17Z\",\"displayName\":\"Captcha Default\",\"category\":\"Captcha\",\"type\":\"Default\",\"subType\":\"\",\"method\":\"\",\"clientId\":\"\",\"clientSecret\":\"\",\"clientId2\":\"\",\"clientSecret2\":\"\",\"cert\":\"\",\"customAuthUrl\":\"\",\"customTokenUrl\":\"\",\"customUserInfoUrl\":\"\",\"customLogo\":\"\",\"scopes\":\"\",\"userMapping\":null,\"httpHeaders\":null,\"host\":\"\",\"port\":0,\"disableSsl\":false,\"title\":\"\",\"content\":\"\",\"receiver\":\"\",\"regionId\":\"\",\"signName\":\"\",\"templateCode\":\"\",\"appId\":\"\",\"endpoint\":\"\",\"intranetEndpoint\":\"\",\"domain\":\"\",\"bucket\":\"\",\"pathPrefix\":\"\",\"metadata\":\"\",\"idP\":\"\",\"issuerUrl\":\"\",\"enableSignAuthnRequest\":false,\"emailRegex\":\"\",\"providerUrl\":\"\"}}],\"signinMethods\":[{\"name\":\"Password\",\"displayName\":\"Password\",\"rule\":\"All\"}],\"signupItems\":[{\"name\":\"ID\",\"visible\":false,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"Random\"},{\"name\":\"Username\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Display name\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Password\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Confirm password\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Email\",\"visible\":false,\"required\":false,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"No verification\"},{\"name\":\"Phone\",\"visible\":true,\"required\":false,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"No verification\"},{\"name\":\"Agreement\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Signup button\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Providers\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n }\\n .provider-big-img {\\n margin-bottom: 10px;\\n }\\n \",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"small\"}],\"signinItems\":[{\"name\":\"Back button\",\"visible\":true,\"label\":\"\",\"customCss\":\".back-button {\\n top: 65px;\\n left: 15px;\\n position: absolute;\\n}\\n.back-inner-button{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Languages\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-languages {\\n top: 55px;\\n right: 5px;\\n position: absolute;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Logo\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-logo-box {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Signin methods\",\"visible\":true,\"label\":\"\",\"customCss\":\".signin-methods {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Username\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-username {}\\n.login-username-input{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Password\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-password {}\\n.login-password-input{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Agreement\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-agreement {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Forgot password?\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-forget-password {\\n display: inline-flex;\\n justify-content: space-between;\\n width: 320px;\\n margin-bottom: 25px;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Login button\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-button-box {\\n margin-bottom: 5px;\\n}\\n.login-button {\\n width: 100%;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Signup link\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-signup-link {\\n margin-bottom: 24px;\\n display: flex;\\n justify-content: end;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Providers\",\"visible\":true,\"label\":\"\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n}\\n.provider-big-img {\\n margin-bottom: 10px;\\n}\",\"placeholder\":\"\",\"rule\":\"small\",\"isCustom\":false}],\"grantTypes\":[\"authorization_code\",\"password\",\"client_credentials\",\"token\",\"id_token\",\"refresh_token\"],\"organizationObj\":{\"owner\":\"admin\",\"name\":\"built-in\",\"createdTime\":\"2025-09-20T10:47:17Z\",\"displayName\":\"Built-in Organization\",\"websiteUrl\":\"https://example.com\",\"logo\":\"\",\"logoDark\":\"\",\"favicon\":\"https://cdn.casbin.org/img/casbin/favicon.ico\",\"hasPrivilegeConsent\":false,\"passwordType\":\"plain\",\"passwordSalt\":\"\",\"passwordOptions\":[\"AtLeast6\"],\"passwordObfuscatorType\":\"\",\"passwordObfuscatorKey\":\"\",\"passwordExpireDays\":0,\"countryCodes\":[\"US\",\"ES\",\"FR\",\"DE\",\"GB\",\"CN\",\"JP\",\"KR\",\"VN\",\"ID\",\"SG\",\"IN\"],\"defaultAvatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"defaultApplication\":\"\",\"userTypes\":[],\"tags\":[],\"languages\":[\"en\",\"zh\",\"es\",\"fr\",\"de\",\"id\",\"ja\",\"ko\",\"ru\",\"vi\",\"pt\"],\"themeData\":null,\"masterPassword\":\"\",\"defaultPassword\":\"\",\"masterVerificationCode\":\"\",\"ipWhitelist\":\"\",\"initScore\":2000,\"enableSoftDeletion\":false,\"isProfilePublic\":false,\"useEmailAsUsername\":false,\"enableTour\":true,\"disableSignin\":false,\"ipRestriction\":\"\",\"navItems\":null,\"widgetItems\":null,\"mfaItems\":null,\"mfaRememberInHours\":0,\"accountItems\":[{\"name\":\"Organization\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"ID\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Display name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Avatar\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"User type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Password\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Email\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Phone\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Country code\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Country/Region\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Location\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Affiliation\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Title\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Homepage\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Bio\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Tag\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Signup application\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Roles\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Permissions\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Groups\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"3rd-party logins\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Properties\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is admin\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is forbidden\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is deleted\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Multi-factor authentication\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"WebAuthn credentials\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Managed accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"MFA accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"}]},\"certPublicKey\":\"\",\"tags\":[],\"samlAttributes\":null,\"isShared\":false,\"ipRestriction\":\"\",\"clientId\":\"e3ba6fec42cfe996121f\",\"clientSecret\":\"0c18bf2a11ffbb756ec6ce47dae9e09bdd48e3dd\",\"redirectUris\":[\"http://localhost:9000/callback\"],\"forcedRedirectOrigin\":\"\",\"tokenFormat\":\"JWT\",\"tokenSigningMethod\":\"\",\"tokenFields\":[],\"expireInHours\":168,\"refreshExpireInHours\":168,\"signupUrl\":\"\",\"signinUrl\":\"\",\"forgetUrl\":\"\",\"affiliationUrl\":\"\",\"ipWhitelist\":\"\",\"termsOfUse\":\"\",\"signupHtml\":\"\",\"signinHtml\":\"\",\"themeData\":null,\"footerHtml\":\"\",\"formCss\":\"\",\"formCssMobile\":\"\",\"formOffset\":2,\"formSideHtml\":\"\",\"formBackgroundUrl\":\"\",\"formBackgroundUrlMobile\":\"\",\"failedSigninLimit\":5,\"failedSigninFrozenTime\":15}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 7, + "owner": "built-in", + "name": "c617f6f6-d4a3-4f77-a111-49c775b9a01d", + "createdTime": "2025-09-20T10:54:11Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-application?id=admin/example-app", + "action": "update-application", + "language": "zh", + "object": "{\"owner\":\"admin\",\"name\":\"example-app\",\"createdTime\":\"2025-09-20T18:50:08+08:00\",\"displayName\":\"示例应用\",\"logo\":\"https://cdn.casbin.org/img/casdoor-logo_1185x256.png\",\"order\":0,\"homepageUrl\":\"\",\"description\":\"\",\"organization\":\"built-in\",\"cert\":\"cert-built-in\",\"defaultGroup\":\"\",\"headerHtml\":\"\",\"enablePassword\":true,\"enableSignUp\":true,\"disableSignin\":false,\"enableSigninSession\":false,\"enableAutoSignin\":false,\"enableCodeSignin\":false,\"enableSamlCompress\":false,\"enableSamlC14n10\":false,\"enableSamlPostBinding\":false,\"useEmailAsSamlNameId\":false,\"enableWebAuthn\":false,\"enableLinkWithEmail\":false,\"orgChoiceMode\":\"\",\"samlReplyUrl\":\"\",\"providers\":[{\"owner\":\"\",\"name\":\"provider_captcha_default\",\"canSignUp\":false,\"canSignIn\":false,\"canUnlink\":false,\"countryCodes\":null,\"prompted\":false,\"signupGroup\":\"\",\"rule\":\"\",\"provider\":{\"owner\":\"admin\",\"name\":\"provider_captcha_default\",\"createdTime\":\"2025-09-20T10:47:17Z\",\"displayName\":\"Captcha Default\",\"category\":\"Captcha\",\"type\":\"Default\",\"subType\":\"\",\"method\":\"\",\"clientId\":\"\",\"clientSecret\":\"\",\"clientId2\":\"\",\"clientSecret2\":\"\",\"cert\":\"\",\"customAuthUrl\":\"\",\"customTokenUrl\":\"\",\"customUserInfoUrl\":\"\",\"customLogo\":\"\",\"scopes\":\"\",\"userMapping\":null,\"httpHeaders\":null,\"host\":\"\",\"port\":0,\"disableSsl\":false,\"title\":\"\",\"content\":\"\",\"receiver\":\"\",\"regionId\":\"\",\"signName\":\"\",\"templateCode\":\"\",\"appId\":\"\",\"endpoint\":\"\",\"intranetEndpoint\":\"\",\"domain\":\"\",\"bucket\":\"\",\"pathPrefix\":\"\",\"metadata\":\"\",\"idP\":\"\",\"issuerUrl\":\"\",\"enableSignAuthnRequest\":false,\"emailRegex\":\"\",\"providerUrl\":\"\"}}],\"signinMethods\":[{\"name\":\"Password\",\"displayName\":\"Password\",\"rule\":\"All\"}],\"signupItems\":[{\"name\":\"ID\",\"visible\":false,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"Random\"},{\"name\":\"Username\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Display name\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Password\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Confirm password\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Email\",\"visible\":false,\"required\":false,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"No verification\"},{\"name\":\"Phone\",\"visible\":true,\"required\":false,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"No verification\"},{\"name\":\"Agreement\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Signup button\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Providers\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n }\\n .provider-big-img {\\n margin-bottom: 10px;\\n }\\n \",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"small\"}],\"signinItems\":[{\"name\":\"Back button\",\"visible\":true,\"label\":\"\",\"customCss\":\".back-button {\\n top: 65px;\\n left: 15px;\\n position: absolute;\\n}\\n.back-inner-button{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Languages\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-languages {\\n top: 55px;\\n right: 5px;\\n position: absolute;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Logo\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-logo-box {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Signin methods\",\"visible\":true,\"label\":\"\",\"customCss\":\".signin-methods {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Username\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-username {}\\n.login-username-input{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Password\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-password {}\\n.login-password-input{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Agreement\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-agreement {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Forgot password?\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-forget-password {\\n display: inline-flex;\\n justify-content: space-between;\\n width: 320px;\\n margin-bottom: 25px;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Login button\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-button-box {\\n margin-bottom: 5px;\\n}\\n.login-button {\\n width: 100%;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Signup link\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-signup-link {\\n margin-bottom: 24px;\\n display: flex;\\n justify-content: end;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Providers\",\"visible\":true,\"label\":\"\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n}\\n.provider-big-img {\\n margin-bottom: 10px;\\n}\",\"placeholder\":\"\",\"rule\":\"small\",\"isCustom\":false}],\"grantTypes\":[\"authorization_code\",\"password\",\"client_credentials\",\"token\",\"id_token\",\"refresh_token\"],\"organizationObj\":{\"owner\":\"admin\",\"name\":\"built-in\",\"createdTime\":\"2025-09-20T10:47:17Z\",\"displayName\":\"Built-in Organization\",\"websiteUrl\":\"https://example.com\",\"logo\":\"\",\"logoDark\":\"\",\"favicon\":\"https://cdn.casbin.org/img/casbin/favicon.ico\",\"hasPrivilegeConsent\":false,\"passwordType\":\"plain\",\"passwordSalt\":\"\",\"passwordOptions\":[\"AtLeast6\"],\"passwordObfuscatorType\":\"\",\"passwordObfuscatorKey\":\"\",\"passwordExpireDays\":0,\"countryCodes\":[\"US\",\"ES\",\"FR\",\"DE\",\"GB\",\"CN\",\"JP\",\"KR\",\"VN\",\"ID\",\"SG\",\"IN\"],\"defaultAvatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"defaultApplication\":\"\",\"userTypes\":[],\"tags\":[],\"languages\":[\"en\",\"zh\",\"es\",\"fr\",\"de\",\"id\",\"ja\",\"ko\",\"ru\",\"vi\",\"pt\"],\"themeData\":null,\"masterPassword\":\"\",\"defaultPassword\":\"\",\"masterVerificationCode\":\"\",\"ipWhitelist\":\"\",\"initScore\":2000,\"enableSoftDeletion\":false,\"isProfilePublic\":false,\"useEmailAsUsername\":false,\"enableTour\":true,\"disableSignin\":false,\"ipRestriction\":\"\",\"navItems\":null,\"widgetItems\":null,\"mfaItems\":null,\"mfaRememberInHours\":0,\"accountItems\":[{\"name\":\"Organization\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"ID\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Display name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Avatar\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"User type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Password\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Email\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Phone\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Country code\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Country/Region\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Location\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Affiliation\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Title\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Homepage\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Bio\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Tag\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Signup application\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Roles\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Permissions\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Groups\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"3rd-party logins\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Properties\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is admin\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is forbidden\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is deleted\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Multi-factor authentication\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"WebAuthn credentials\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Managed accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"MFA accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"}]},\"certPublicKey\":\"\",\"tags\":[],\"samlAttributes\":null,\"isShared\":false,\"ipRestriction\":\"\",\"clientId\":\"e3ba6fec42cfe996121f\",\"clientSecret\":\"0c18bf2a11ffbb756ec6ce47dae9e09bdd48e3dd\",\"redirectUris\":[\"http://localhost:9000/callback\"],\"forcedRedirectOrigin\":\"\",\"tokenFormat\":\"JWT\",\"tokenSigningMethod\":\"\",\"tokenFields\":[],\"expireInHours\":168,\"refreshExpireInHours\":168,\"signupUrl\":\"\",\"signinUrl\":\"\",\"forgetUrl\":\"\",\"affiliationUrl\":\"\",\"ipWhitelist\":\"\",\"termsOfUse\":\"\",\"signupHtml\":\"\",\"signinHtml\":\"\",\"themeData\":null,\"footerHtml\":\"\",\"formCss\":\"\",\"formCssMobile\":\"\",\"formOffset\":2,\"formSideHtml\":\"\",\"formBackgroundUrl\":\"\",\"formBackgroundUrlMobile\":\"\",\"failedSigninLimit\":5,\"failedSigninFrozenTime\":15}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 6, + "owner": "built-in", + "name": "612a4272-23f0-4289-b7de-e75e0567050d", + "createdTime": "2025-09-20T10:53:39Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-application?id=admin/application_1o1gji", + "action": "update-application", + "language": "zh", + "object": "{\"owner\":\"admin\",\"name\":\"example-app\",\"createdTime\":\"2025-09-20T18:50:08+08:00\",\"displayName\":\"示例应用\",\"logo\":\"https://cdn.casbin.org/img/casdoor-logo_1185x256.png\",\"order\":0,\"homepageUrl\":\"\",\"description\":\"\",\"organization\":\"built-in\",\"cert\":\"cert-built-in\",\"defaultGroup\":\"\",\"headerHtml\":\"\",\"enablePassword\":true,\"enableSignUp\":true,\"disableSignin\":false,\"enableSigninSession\":false,\"enableAutoSignin\":false,\"enableCodeSignin\":false,\"enableSamlCompress\":false,\"enableSamlC14n10\":false,\"enableSamlPostBinding\":false,\"useEmailAsSamlNameId\":false,\"enableWebAuthn\":false,\"enableLinkWithEmail\":false,\"orgChoiceMode\":\"\",\"samlReplyUrl\":\"\",\"providers\":[{\"owner\":\"\",\"name\":\"provider_captcha_default\",\"canSignUp\":false,\"canSignIn\":false,\"canUnlink\":false,\"countryCodes\":null,\"prompted\":false,\"signupGroup\":\"\",\"rule\":\"\",\"provider\":{\"owner\":\"admin\",\"name\":\"provider_captcha_default\",\"createdTime\":\"2025-09-20T10:47:17Z\",\"displayName\":\"Captcha Default\",\"category\":\"Captcha\",\"type\":\"Default\",\"subType\":\"\",\"method\":\"\",\"clientId\":\"\",\"clientSecret\":\"\",\"clientId2\":\"\",\"clientSecret2\":\"\",\"cert\":\"\",\"customAuthUrl\":\"\",\"customTokenUrl\":\"\",\"customUserInfoUrl\":\"\",\"customLogo\":\"\",\"scopes\":\"\",\"userMapping\":null,\"httpHeaders\":null,\"host\":\"\",\"port\":0,\"disableSsl\":false,\"title\":\"\",\"content\":\"\",\"receiver\":\"\",\"regionId\":\"\",\"signName\":\"\",\"templateCode\":\"\",\"appId\":\"\",\"endpoint\":\"\",\"intranetEndpoint\":\"\",\"domain\":\"\",\"bucket\":\"\",\"pathPrefix\":\"\",\"metadata\":\"\",\"idP\":\"\",\"issuerUrl\":\"\",\"enableSignAuthnRequest\":false,\"emailRegex\":\"\",\"providerUrl\":\"\"}}],\"signinMethods\":[{\"name\":\"Password\",\"displayName\":\"Password\",\"rule\":\"All\"}],\"signupItems\":[{\"name\":\"ID\",\"visible\":false,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"Random\"},{\"name\":\"Username\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Display name\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Password\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Confirm password\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Email\",\"visible\":false,\"required\":false,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"No verification\"},{\"name\":\"Phone\",\"visible\":true,\"required\":false,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"No verification\"},{\"name\":\"Agreement\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Signup button\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Providers\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n }\\n .provider-big-img {\\n margin-bottom: 10px;\\n }\\n \",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"small\"}],\"signinItems\":[{\"name\":\"Back button\",\"visible\":true,\"label\":\"\",\"customCss\":\".back-button {\\n top: 65px;\\n left: 15px;\\n position: absolute;\\n}\\n.back-inner-button{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Languages\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-languages {\\n top: 55px;\\n right: 5px;\\n position: absolute;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Logo\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-logo-box {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Signin methods\",\"visible\":true,\"label\":\"\",\"customCss\":\".signin-methods {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Username\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-username {}\\n.login-username-input{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Password\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-password {}\\n.login-password-input{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Agreement\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-agreement {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Forgot password?\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-forget-password {\\n display: inline-flex;\\n justify-content: space-between;\\n width: 320px;\\n margin-bottom: 25px;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Login button\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-button-box {\\n margin-bottom: 5px;\\n}\\n.login-button {\\n width: 100%;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Signup link\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-signup-link {\\n margin-bottom: 24px;\\n display: flex;\\n justify-content: end;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Providers\",\"visible\":true,\"label\":\"\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n}\\n.provider-big-img {\\n margin-bottom: 10px;\\n}\",\"placeholder\":\"\",\"rule\":\"small\",\"isCustom\":false}],\"grantTypes\":[\"authorization_code\",\"password\",\"client_credentials\",\"token\",\"id_token\",\"refresh_token\"],\"organizationObj\":{\"owner\":\"admin\",\"name\":\"built-in\",\"createdTime\":\"2025-09-20T10:47:17Z\",\"displayName\":\"Built-in Organization\",\"websiteUrl\":\"https://example.com\",\"logo\":\"\",\"logoDark\":\"\",\"favicon\":\"https://cdn.casbin.org/img/casbin/favicon.ico\",\"hasPrivilegeConsent\":false,\"passwordType\":\"plain\",\"passwordSalt\":\"\",\"passwordOptions\":[\"AtLeast6\"],\"passwordObfuscatorType\":\"\",\"passwordObfuscatorKey\":\"\",\"passwordExpireDays\":0,\"countryCodes\":[\"US\",\"ES\",\"FR\",\"DE\",\"GB\",\"CN\",\"JP\",\"KR\",\"VN\",\"ID\",\"SG\",\"IN\"],\"defaultAvatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"defaultApplication\":\"\",\"userTypes\":[],\"tags\":[],\"languages\":[\"en\",\"zh\",\"es\",\"fr\",\"de\",\"id\",\"ja\",\"ko\",\"ru\",\"vi\",\"pt\"],\"themeData\":null,\"masterPassword\":\"\",\"defaultPassword\":\"\",\"masterVerificationCode\":\"\",\"ipWhitelist\":\"\",\"initScore\":2000,\"enableSoftDeletion\":false,\"isProfilePublic\":false,\"useEmailAsUsername\":false,\"enableTour\":true,\"disableSignin\":false,\"ipRestriction\":\"\",\"navItems\":null,\"widgetItems\":null,\"mfaItems\":null,\"mfaRememberInHours\":0,\"accountItems\":[{\"name\":\"Organization\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"ID\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Display name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Avatar\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"User type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Password\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Email\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Phone\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Country code\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Country/Region\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Location\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Affiliation\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Title\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Homepage\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Bio\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Tag\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Signup application\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Roles\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Permissions\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Groups\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"3rd-party logins\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Properties\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is admin\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is forbidden\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is deleted\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Multi-factor authentication\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"WebAuthn credentials\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Managed accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"MFA accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"}]},\"certPublicKey\":\"\",\"tags\":[],\"samlAttributes\":null,\"isShared\":false,\"ipRestriction\":\"\",\"clientId\":\"e3ba6fec42cfe996121f\",\"clientSecret\":\"0c18bf2a11ffbb756ec6ce47dae9e09bdd48e3dd\",\"redirectUris\":[\"http://localhost:9000/callback\"],\"forcedRedirectOrigin\":\"\",\"tokenFormat\":\"JWT\",\"tokenSigningMethod\":\"\",\"tokenFields\":[],\"expireInHours\":168,\"refreshExpireInHours\":168,\"signupUrl\":\"\",\"signinUrl\":\"\",\"forgetUrl\":\"\",\"affiliationUrl\":\"\",\"ipWhitelist\":\"\",\"termsOfUse\":\"\",\"signupHtml\":\"\",\"signinHtml\":\"\",\"themeData\":null,\"footerHtml\":\"\",\"formCss\":\"\",\"formCssMobile\":\"\",\"formOffset\":2,\"formSideHtml\":\"\",\"formBackgroundUrl\":\"\",\"formBackgroundUrlMobile\":\"\",\"failedSigninLimit\":5,\"failedSigninFrozenTime\":15}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 5, + "owner": "built-in", + "name": "aa5b7413-d9fb-4fee-9565-1a39712643da", + "createdTime": "2025-09-20T10:50:09Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/add-application", + "action": "add-application", + "language": "zh", + "object": "{\"owner\":\"admin\",\"name\":\"application_1o1gji\",\"organization\":\"built-in\",\"createdTime\":\"2025-09-20T18:50:08+08:00\",\"displayName\":\"New Application - 1o1gji\",\"logo\":\"https://cdn.casbin.org/img/casdoor-logo_1185x256.png\",\"enablePassword\":true,\"enableSignUp\":true,\"disableSignin\":false,\"enableSigninSession\":false,\"enableCodeSignin\":false,\"enableSamlCompress\":false,\"providers\":[{\"name\":\"provider_captcha_default\",\"canSignUp\":false,\"canSignIn\":false,\"canUnlink\":false,\"prompted\":false,\"signupGroup\":\"\",\"rule\":\"\"}],\"SigninMethods\":[{\"name\":\"Password\",\"displayName\":\"Password\",\"rule\":\"All\"},{\"name\":\"Verification code\",\"displayName\":\"Verification code\",\"rule\":\"All\"},{\"name\":\"WebAuthn\",\"displayName\":\"WebAuthn\",\"rule\":\"None\"},{\"name\":\"Face ID\",\"displayName\":\"Face ID\",\"rule\":\"None\"}],\"signupItems\":[{\"name\":\"ID\",\"visible\":false,\"required\":true,\"rule\":\"Random\"},{\"name\":\"Username\",\"visible\":true,\"required\":true,\"rule\":\"None\"},{\"name\":\"Display name\",\"visible\":true,\"required\":true,\"rule\":\"None\"},{\"name\":\"Password\",\"visible\":true,\"required\":true,\"rule\":\"None\"},{\"name\":\"Confirm password\",\"visible\":true,\"required\":true,\"rule\":\"None\"},{\"name\":\"Email\",\"visible\":true,\"required\":true,\"rule\":\"Normal\"},{\"name\":\"Phone\",\"visible\":true,\"required\":true,\"rule\":\"None\"},{\"name\":\"Agreement\",\"visible\":true,\"required\":true,\"rule\":\"None\"},{\"name\":\"Signup button\",\"visible\":true,\"required\":true,\"rule\":\"None\"},{\"name\":\"Providers\",\"visible\":true,\"required\":true,\"rule\":\"None\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n }\\n .provider-big-img {\\n margin-bottom: 10px;\\n }\\n \"}],\"grantTypes\":[\"authorization_code\",\"password\",\"client_credentials\",\"token\",\"id_token\",\"refresh_token\"],\"cert\":\"cert-built-in\",\"redirectUris\":[\"http://localhost:9000/callback\"],\"tokenFormat\":\"JWT\",\"tokenFields\":[],\"expireInHours\":168,\"refreshExpireInHours\":168,\"formOffset\":2}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 4, + "owner": "built-in", + "name": "fb9b52f4-cee5-4c76-b577-0fa18d5e2162", + "createdTime": "2025-09-20T10:50:04Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-organization?id=admin/organization_qe0w97", + "action": "update-organization", + "language": "zh", + "object": "{\"owner\":\"admin\",\"name\":\"example-org\",\"createdTime\":\"2025-09-20T18:48:24+08:00\",\"displayName\":\"示例组织\",\"websiteUrl\":\"https://door.casdoor.com\",\"logo\":\"\",\"logoDark\":\"\",\"favicon\":\"https://cdn.casbin.org/img/favicon.png\",\"hasPrivilegeConsent\":false,\"passwordType\":\"plain\",\"passwordSalt\":\"\",\"passwordOptions\":[\"AtLeast6\"],\"passwordObfuscatorType\":\"Plain\",\"passwordObfuscatorKey\":\"\",\"passwordExpireDays\":0,\"countryCodes\":[\"CN\"],\"defaultAvatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"defaultApplication\":\"\",\"userTypes\":null,\"tags\":[],\"languages\":[\"en\",\"es\",\"fr\",\"de\",\"zh\",\"id\",\"ja\",\"ko\",\"ru\",\"vi\",\"pt\",\"it\",\"ms\",\"tr\",\"ar\",\"he\",\"nl\",\"pl\",\"fi\",\"sv\",\"uk\",\"kk\",\"fa\",\"cs\",\"sk\",\"az\"],\"themeData\":null,\"masterPassword\":\"\",\"defaultPassword\":\"\",\"masterVerificationCode\":\"\",\"ipWhitelist\":\"\",\"initScore\":0,\"enableSoftDeletion\":false,\"isProfilePublic\":true,\"useEmailAsUsername\":false,\"enableTour\":true,\"disableSignin\":false,\"ipRestriction\":\"\",\"navItems\":null,\"widgetItems\":null,\"mfaItems\":null,\"mfaRememberInHours\":12,\"accountItems\":[{\"name\":\"Organization\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"ID\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Display name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Avatar\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"User type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Password\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Email\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Phone\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Country code\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Country/Region\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Location\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Address\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Affiliation\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Title\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"ID card type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"ID card\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"ID card info\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Homepage\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Bio\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Tag\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Language\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Gender\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Birthday\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Education\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Score\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Karma\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Ranking\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Signup application\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"API key\",\"visible\":false,\"viewRule\":\"\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Groups\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Roles\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Permissions\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"3rd-party logins\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Properties\",\"visible\":false,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is online\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is admin\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is forbidden\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is deleted\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Multi-factor authentication\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"WebAuthn credentials\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Managed accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"MFA accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"}],\"enableDarkLogo\":false}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 3, + "owner": "built-in", + "name": "b0de7ab6-eda7-4d2d-8221-5ac506b21d3e", + "createdTime": "2025-09-20T10:48:24Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/add-organization", + "action": "add-organization", + "language": "zh", + "object": "{\"owner\":\"admin\",\"name\":\"organization_qe0w97\",\"createdTime\":\"2025-09-20T18:48:24+08:00\",\"displayName\":\"New Organization - qe0w97\",\"websiteUrl\":\"https://door.casdoor.com\",\"favicon\":\"https://cdn.casbin.org/img/favicon.png\",\"passwordType\":\"plain\",\"PasswordSalt\":\"\",\"passwordOptions\":[\"AtLeast6\"],\"passwordObfuscatorType\":\"Plain\",\"passwordObfuscatorKey\":\"\",\"passwordExpireDays\":0,\"countryCodes\":[\"US\"],\"defaultAvatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"defaultApplication\":\"\",\"tags\":[],\"languages\":[\"en\",\"es\",\"fr\",\"de\",\"zh\",\"id\",\"ja\",\"ko\",\"ru\",\"vi\",\"pt\",\"it\",\"ms\",\"tr\",\"ar\",\"he\",\"nl\",\"pl\",\"fi\",\"sv\",\"uk\",\"kk\",\"fa\",\"cs\",\"sk\",\"az\"],\"masterPassword\":\"\",\"defaultPassword\":\"\",\"enableSoftDeletion\":false,\"isProfilePublic\":true,\"enableTour\":true,\"disableSignin\":false,\"mfaRememberInHours\":12,\"accountItems\":[{\"name\":\"Organization\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"ID\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\"},{\"name\":\"Name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Display name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Avatar\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"User type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Password\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\"},{\"name\":\"Email\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Phone\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Country code\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Country/Region\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Location\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Address\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Affiliation\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Title\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"ID card type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"ID card\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"ID card info\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Homepage\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Bio\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Tag\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Language\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Gender\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Birthday\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Education\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Score\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Karma\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Ranking\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Signup application\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"API key\",\"label\":\"API 密钥\",\"modifyRule\":\"Self\"},{\"name\":\"Groups\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Roles\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\"},{\"name\":\"Permissions\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\"},{\"name\":\"3rd-party logins\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\"},{\"name\":\"Properties\",\"visible\":false,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\"},{\"name\":\"Is online\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\"},{\"name\":\"Is admin\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\"},{\"name\":\"Is forbidden\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\"},{\"name\":\"Is deleted\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\"},{\"Name\":\"Multi-factor authentication\",\"Visible\":true,\"ViewRule\":\"Self\",\"ModifyRule\":\"Self\"},{\"Name\":\"WebAuthn credentials\",\"Visible\":true,\"ViewRule\":\"Self\",\"ModifyRule\":\"Self\"},{\"Name\":\"Managed accounts\",\"Visible\":true,\"ViewRule\":\"Self\",\"ModifyRule\":\"Self\"},{\"Name\":\"MFA accounts\",\"Visible\":true,\"ViewRule\":\"Self\",\"ModifyRule\":\"Self\"}]}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 2, + "owner": "built-in", + "name": "81b8cee1-efe6-4522-a915-11fc0dc77ff2", + "createdTime": "2025-09-20T10:48:20Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/login", + "action": "login", + "language": "zh", + "object": "{\"application\":\"app-built-in\",\"organization\":\"built-in\",\"username\":\"admin\",\"password\":\"***\",\"autoSignin\":true,\"language\":\"\",\"signinMethod\":\"Password\",\"type\":\"login\"}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 1, + "owner": "built-in", + "name": "3041e2e0-2ff5-43cc-8fad-7d424ebc2e07", + "createdTime": "2025-09-20T10:47:51Z", + "organization": "built-in", + "clientIp": "10.10.125.231", + "user": "admin", + "method": "POST", + "requestUri": "/api/login", + "action": "login", + "language": "zh", + "object": "{\"application\":\"app-built-in\",\"organization\":\"built-in\",\"username\":\"admin\",\"autoSignin\":true,\"password\":\"***\",\"language\":\"\",\"signinMethod\":\"Password\",\"type\":\"login\"}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + } + ], + "sessions": [ + { + "owner": "built-in", + "name": "admin", + "application": "app-built-in", + "createdTime": "2025-09-20T10:47:51Z", + "sessionId": [ + "12692e708d7f7348e75ba800df9606d2", + "d60a540308bd43cfae3b88e83c50abd2", + "ae85d04cfecb47522ceeec61a166fcc8" + ] + } + ], + "subscriptions": [], + "transactions": [], + "enforcerPolicies": { + "built-in/api-enforcer-built-in": [ + [ + "built-in", + "*", + "*", + "*", + "*", + "*" + ], + [ + "app", + "*", + "*", + "*", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/signup", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-email-and-phone", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/login", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-app-login", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/logout", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/logout", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/callback", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/device-auth", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-account", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/userinfo", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/user", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/health", + "*", + "*" + ], + [ + "*", + "*", + "*", + "/api/webhook", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-qrcode", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-webhook-event", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-captcha-status", + "*", + "*" + ], + [ + "*", + "*", + "*", + "/api/login/oauth", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-application", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-organization-applications", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-user", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-user-application", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-resources", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-records", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-product", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/buy-product", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-payment", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/update-payment", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/invoice-payment", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/notify-payment", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/unlink", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/set-password", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/send-verification-code", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-captcha", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/verify-captcha", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/verify-code", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/reset-email-or-phone", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/upload-resource", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/.well-known/openid-configuration", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/.well-known/webfinger", + "*", + "*" + ], + [ + "*", + "*", + "*", + "/.well-known/jwks", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-saml-login", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/acs", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/saml/metadata", + "*", + "*" + ], + [ + "*", + "*", + "*", + "/api/saml/redirect", + "*", + "*" + ], + [ + "*", + "*", + "*", + "/cas", + "*", + "*" + ], + [ + "*", + "*", + "*", + "/scim", + "*", + "*" + ], + [ + "*", + "*", + "*", + "/api/webauthn", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-release", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-default-application", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-prometheus-info", + "*", + "*" + ], + [ + "*", + "*", + "*", + "/api/metrics", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-pricing", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-plan", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-subscription", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-provider", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-organization-names", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-all-objects", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-all-actions", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-all-roles", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/run-casbin-command", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/refresh-engines", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-invitation-info", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/faceid-signin-begin", + "*", + "*" + ] + ], + "built-in/user-enforcer-built-in": null + } } \ No newline at end of file diff --git a/docker/astronAgent/casdoor/conf/init_data.json.template b/docker/astronAgent/casdoor/conf/init_data.json.template new file mode 100644 index 0000000000000000000000000000000000000000..930feead088757698f110cd88e2b382fe5d20360 --- /dev/null +++ b/docker/astronAgent/casdoor/conf/init_data.json.template @@ -0,0 +1,2838 @@ +{ + "organizations": [ + { + "owner": "admin", + "name": "example-org", + "createdTime": "2025-09-20T18:48:24+08:00", + "displayName": "示例组织", + "websiteUrl": "https://door.casdoor.com", + "logo": "", + "logoDark": "", + "favicon": "https://cdn.casbin.org/img/favicon.png", + "hasPrivilegeConsent": false, + "passwordType": "plain", + "passwordSalt": "", + "passwordOptions": [ + "AtLeast6" + ], + "passwordObfuscatorType": "Plain", + "passwordObfuscatorKey": "", + "passwordExpireDays": 0, + "countryCodes": [ + "CN" + ], + "defaultAvatar": "https://cdn.casbin.org/img/casbin.svg", + "defaultApplication": "example-app", + "userTypes": null, + "tags": [], + "languages": [ + "en", + "es", + "fr", + "de", + "zh", + "id", + "ja", + "ko", + "ru", + "vi", + "pt", + "it", + "ms", + "tr", + "ar", + "he", + "nl", + "pl", + "fi", + "sv", + "uk", + "kk", + "fa", + "cs", + "sk", + "az" + ], + "themeData": null, + "masterPassword": "", + "defaultPassword": "", + "masterVerificationCode": "", + "ipWhitelist": "", + "initScore": 0, + "enableSoftDeletion": false, + "isProfilePublic": true, + "useEmailAsUsername": false, + "enableTour": true, + "disableSignin": false, + "ipRestriction": "", + "navItems": null, + "widgetItems": null, + "mfaItems": null, + "mfaRememberInHours": 12, + "accountItems": [ + { + "name": "Organization", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "ID", + "visible": true, + "viewRule": "Public", + "modifyRule": "Immutable", + "regex": "" + }, + { + "name": "Name", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Display name", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Avatar", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "User type", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Password", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Email", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Phone", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Country code", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Country/Region", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Location", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Address", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Affiliation", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Title", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "ID card type", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "ID card", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "ID card info", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Homepage", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Bio", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Tag", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Language", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Gender", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Birthday", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Education", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Score", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Karma", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Ranking", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Signup application", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "API key", + "visible": false, + "viewRule": "", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Groups", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Roles", + "visible": true, + "viewRule": "Public", + "modifyRule": "Immutable", + "regex": "" + }, + { + "name": "Permissions", + "visible": true, + "viewRule": "Public", + "modifyRule": "Immutable", + "regex": "" + }, + { + "name": "3rd-party logins", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Properties", + "visible": false, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Is online", + "visible": true, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Is admin", + "visible": true, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Is forbidden", + "visible": true, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Is deleted", + "visible": true, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Multi-factor authentication", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "WebAuthn credentials", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Managed accounts", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "MFA accounts", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + } + ] + }, + { + "owner": "admin", + "name": "built-in", + "createdTime": "2025-09-20T10:47:17Z", + "displayName": "Built-in Organization", + "websiteUrl": "https://example.com", + "logo": "", + "logoDark": "", + "favicon": "https://cdn.casbin.org/img/casbin/favicon.ico", + "hasPrivilegeConsent": false, + "passwordType": "plain", + "passwordSalt": "", + "passwordOptions": [ + "AtLeast6" + ], + "passwordObfuscatorType": "", + "passwordObfuscatorKey": "", + "passwordExpireDays": 0, + "countryCodes": [ + "US", + "ES", + "FR", + "DE", + "GB", + "CN", + "JP", + "KR", + "VN", + "ID", + "SG", + "IN" + ], + "defaultAvatar": "https://cdn.casbin.org/img/casbin.svg", + "defaultApplication": "", + "userTypes": [], + "tags": [], + "languages": [ + "en", + "zh", + "es", + "fr", + "de", + "id", + "ja", + "ko", + "ru", + "vi", + "pt" + ], + "themeData": null, + "masterPassword": "", + "defaultPassword": "", + "masterVerificationCode": "", + "ipWhitelist": "", + "initScore": 2000, + "enableSoftDeletion": false, + "isProfilePublic": false, + "useEmailAsUsername": false, + "enableTour": true, + "disableSignin": false, + "ipRestriction": "", + "navItems": null, + "widgetItems": null, + "mfaItems": null, + "mfaRememberInHours": 0, + "accountItems": [ + { + "name": "Organization", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "ID", + "visible": true, + "viewRule": "Public", + "modifyRule": "Immutable", + "regex": "" + }, + { + "name": "Name", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Display name", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Avatar", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "User type", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Password", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Email", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Phone", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Country code", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Country/Region", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Location", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Affiliation", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Title", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Homepage", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Bio", + "visible": true, + "viewRule": "Public", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Tag", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Signup application", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Roles", + "visible": true, + "viewRule": "Public", + "modifyRule": "Immutable", + "regex": "" + }, + { + "name": "Permissions", + "visible": true, + "viewRule": "Public", + "modifyRule": "Immutable", + "regex": "" + }, + { + "name": "Groups", + "visible": true, + "viewRule": "Public", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "3rd-party logins", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Properties", + "visible": true, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Is admin", + "visible": true, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Is forbidden", + "visible": true, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Is deleted", + "visible": true, + "viewRule": "Admin", + "modifyRule": "Admin", + "regex": "" + }, + { + "name": "Multi-factor authentication", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "WebAuthn credentials", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "Managed accounts", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + }, + { + "name": "MFA accounts", + "visible": true, + "viewRule": "Self", + "modifyRule": "Self", + "regex": "" + } + ] + } + ], + "applications": [ + { + "owner": "admin", + "name": "example-app", + "createdTime": "2025-09-20T18:50:08+08:00", + "displayName": "示例应用", + "logo": "https://cdn.casbin.org/img/casdoor-logo_1185x256.png", + "order": 0, + "homepageUrl": "", + "description": "", + "organization": "example-org", + "cert": "cert-built-in", + "defaultGroup": "", + "headerHtml": "", + "enablePassword": true, + "enableSignUp": true, + "disableSignin": false, + "enableSigninSession": false, + "enableAutoSignin": false, + "enableCodeSignin": false, + "enableSamlCompress": false, + "enableSamlC14n10": false, + "enableSamlPostBinding": false, + "useEmailAsSamlNameId": false, + "enableWebAuthn": false, + "enableLinkWithEmail": false, + "orgChoiceMode": "", + "samlReplyUrl": "", + "providers": [ + { + "owner": "", + "name": "provider_captcha_default", + "canSignUp": false, + "canSignIn": false, + "canUnlink": false, + "countryCodes": null, + "prompted": false, + "signupGroup": "", + "rule": "", + "provider": null + } + ], + "signinMethods": [ + { + "name": "Password", + "displayName": "Password", + "rule": "All" + } + ], + "signupItems": [ + { + "name": "ID", + "visible": false, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "Random" + }, + { + "name": "Username", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Display name", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Password", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Confirm password", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Email", + "visible": false, + "required": false, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "No verification" + }, + { + "name": "Phone", + "visible": true, + "required": false, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "No verification" + }, + { + "name": "Agreement", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Signup button", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Providers", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": ".provider-img {\n width: 30px;\n margin: 5px;\n }\n .provider-big-img {\n margin-bottom: 10px;\n }\n ", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "small" + } + ], + "signinItems": [ + { + "name": "Back button", + "visible": true, + "label": "", + "customCss": ".back-button {\n top: 65px;\n left: 15px;\n position: absolute;\n}\n.back-inner-button{}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Languages", + "visible": true, + "label": "", + "customCss": ".login-languages {\n top: 55px;\n right: 5px;\n position: absolute;\n}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Logo", + "visible": true, + "label": "", + "customCss": ".login-logo-box {}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Signin methods", + "visible": true, + "label": "", + "customCss": ".signin-methods {}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Username", + "visible": true, + "label": "", + "customCss": ".login-username {}\n.login-username-input{}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Password", + "visible": true, + "label": "", + "customCss": ".login-password {}\n.login-password-input{}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Agreement", + "visible": true, + "label": "", + "customCss": ".login-agreement {}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Forgot password?", + "visible": true, + "label": "", + "customCss": ".login-forget-password {\n display: inline-flex;\n justify-content: space-between;\n width: 320px;\n margin-bottom: 25px;\n}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Login button", + "visible": true, + "label": "", + "customCss": ".login-button-box {\n margin-bottom: 5px;\n}\n.login-button {\n width: 100%;\n}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Signup link", + "visible": true, + "label": "", + "customCss": ".login-signup-link {\n margin-bottom: 24px;\n display: flex;\n justify-content: end;\n}", + "placeholder": "", + "rule": "None", + "isCustom": false + }, + { + "name": "Providers", + "visible": true, + "label": "", + "customCss": ".provider-img {\n width: 30px;\n margin: 5px;\n}\n.provider-big-img {\n margin-bottom: 10px;\n}", + "placeholder": "", + "rule": "small", + "isCustom": false + } + ], + "grantTypes": [ + "authorization_code", + "password", + "client_credentials", + "token", + "id_token", + "refresh_token" + ], + "organizationObj": null, + "certPublicKey": "", + "tags": [], + "samlAttributes": null, + "isShared": false, + "ipRestriction": "", + "clientId": "e3ba6fec42cfe996121f", + "clientSecret": "0c18bf2a11ffbb756ec6ce47dae9e09bdd48e3dd", + "redirectUris": [ + "https://tauri.localhost/","http://localhost:1420/" + ], + "forcedRedirectOrigin": "", + "tokenFormat": "JWT", + "tokenSigningMethod": "", + "tokenFields": [], + "tokenAttributes": null, + "expireInHours": 168, + "refreshExpireInHours": 168, + "signupUrl": "", + "signinUrl": "", + "forgetUrl": "", + "affiliationUrl": "", + "ipWhitelist": "", + "termsOfUse": "", + "signupHtml": "", + "signinHtml": "", + "themeData": null, + "footerHtml": "", + "formCss": "", + "formCssMobile": "", + "formOffset": 2, + "formSideHtml": "", + "formBackgroundUrl": "", + "formBackgroundUrlMobile": "", + "failedSigninLimit": 5, + "failedSigninFrozenTime": 15 + }, + { + "owner": "admin", + "name": "app-built-in", + "createdTime": "2025-09-20T10:47:17Z", + "displayName": "Casdoor", + "logo": "https://cdn.casbin.org/img/casdoor-logo_1185x256.png", + "order": 0, + "homepageUrl": "https://casdoor.org", + "description": "", + "organization": "built-in", + "cert": "cert-built-in", + "defaultGroup": "", + "headerHtml": "", + "enablePassword": true, + "enableSignUp": true, + "disableSignin": false, + "enableSigninSession": false, + "enableAutoSignin": false, + "enableCodeSignin": false, + "enableSamlCompress": false, + "enableSamlC14n10": false, + "enableSamlPostBinding": false, + "useEmailAsSamlNameId": false, + "enableWebAuthn": false, + "enableLinkWithEmail": false, + "orgChoiceMode": "", + "samlReplyUrl": "", + "providers": [ + { + "owner": "", + "name": "provider_captcha_default", + "canSignUp": false, + "canSignIn": false, + "canUnlink": false, + "countryCodes": null, + "prompted": false, + "signupGroup": "", + "rule": "None", + "provider": null + } + ], + "signinMethods": [ + { + "name": "Password", + "displayName": "Password", + "rule": "All" + }, + { + "name": "Verification code", + "displayName": "Verification code", + "rule": "All" + }, + { + "name": "WebAuthn", + "displayName": "WebAuthn", + "rule": "None" + }, + { + "name": "Face ID", + "displayName": "Face ID", + "rule": "None" + } + ], + "signupItems": [ + { + "name": "ID", + "visible": false, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "Random" + }, + { + "name": "Username", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Display name", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Password", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Confirm password", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Email", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "Normal" + }, + { + "name": "Phone", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + }, + { + "name": "Agreement", + "visible": true, + "required": true, + "prompted": false, + "type": "", + "customCss": "", + "label": "", + "placeholder": "", + "options": null, + "regex": "", + "rule": "None" + } + ], + "signinItems": null, + "grantTypes": null, + "organizationObj": null, + "certPublicKey": "", + "tags": [], + "samlAttributes": null, + "isShared": false, + "ipRestriction": "", + "clientId": "1d1eb3c891fa8faa7d63", + "clientSecret": "4d623f9beb97dd8263bbf3147e194ad3b0b1c9e2", + "redirectUris": [], + "forcedRedirectOrigin": "", + "tokenFormat": "JWT", + "tokenSigningMethod": "", + "tokenFields": [], + "tokenAttributes": null, + "expireInHours": 168, + "refreshExpireInHours": 0, + "signupUrl": "", + "signinUrl": "", + "forgetUrl": "", + "affiliationUrl": "", + "ipWhitelist": "", + "termsOfUse": "", + "signupHtml": "", + "signinHtml": "", + "themeData": null, + "footerHtml": "", + "formCss": "", + "formCssMobile": "", + "formOffset": 2, + "formSideHtml": "", + "formBackgroundUrl": "", + "formBackgroundUrlMobile": "", + "failedSigninLimit": 0, + "failedSigninFrozenTime": 0 + }, + { + "owner": "admin", + "name": "astron-agent-app", + "displayName": "Astron Agent Application", + "logo": "https://raw.githubusercontent.com/iflytek/astron-agent/bf285fd637e0920f38fbfd293f22e950b7534484/docs/logo.svg", + "organization": "built-in", + "cert": "cert-built-in", + "enablePassword": true, + "enableSignUp": true, + "clientId": "astron-agent-client", + "redirectUris": [ + "${CONSOLE_DOMAIN}/callback", + "${HOST_BASE_ADDRESS}/callback" + ], + "tokenFormat": "JWT", + "tokenFields": [], + "expireInHours": 168, + "refreshExpireInHours": 168, + "grantTypes": ["authorization_code","refresh_token"], + "signinMethods": [ + {"name": "Password", "displayName": "Password", "rule": "All"} + ], + "signupItems": [ + {"name": "Username", "visible": true, "required": true, "prompted": false, "rule": "None"}, + {"name": "Password", "visible": true, "required": true, "prompted": false, "rule": "None"}, + {"name": "Email", "visible": true, "required": true, "prompted": false, "rule": "None"} + ], + "tags": [], + "formOffset": 2 + } + ], + "users": [ + { + "owner": "example-org", + "name": "example-user", + "createdTime": "2025-09-20T10:56:21Z", + "updatedTime": "2025-09-20T10:57:09Z", + "deletedTime": "", + "id": "3d7cca2b-8da9-41bf-b535-6c9f83d731db", + "externalId": "", + "type": "normal-user", + "password": "123456", + "passwordSalt": "", + "passwordType": "plain", + "displayName": "示例用户", + "firstName": "", + "lastName": "", + "avatar": "https://cdn.casbin.org/img/casbin.svg", + "avatarType": "", + "permanentAvatar": "", + "email": "", + "emailVerified": false, + "phone": "18888888888", + "countryCode": "CN", + "region": "", + "location": "", + "address": [], + "affiliation": "", + "title": "", + "idCardType": "", + "idCard": "", + "homepage": "", + "bio": "", + "tag": "", + "language": "", + "gender": "", + "birthday": "", + "education": "", + "score": 0, + "karma": 0, + "ranking": 1, + "balance": 0, + "currency": "", + "isDefaultAvatar": false, + "isOnline": false, + "isAdmin": false, + "isForbidden": false, + "isDeleted": false, + "signupApplication": "example-app", + "hash": "", + "preHash": "", + "accessKey": "", + "accessSecret": "", + "accessToken": "", + "createdIp": "", + "lastSigninTime": "", + "lastSigninIp": "", + "github": "", + "google": "", + "qq": "", + "wechat": "", + "facebook": "", + "dingtalk": "", + "weibo": "", + "gitee": "", + "linkedin": "", + "wecom": "", + "lark": "", + "gitlab": "", + "adfs": "", + "baidu": "", + "alipay": "", + "casdoor": "", + "infoflow": "", + "apple": "", + "azuread": "", + "azureadb2c": "", + "slack": "", + "steam": "", + "bilibili": "", + "okta": "", + "douyin": "", + "kwai": "", + "line": "", + "amazon": "", + "auth0": "", + "battlenet": "", + "bitbucket": "", + "box": "", + "cloudfoundry": "", + "dailymotion": "", + "deezer": "", + "digitalocean": "", + "discord": "", + "dropbox": "", + "eveonline": "", + "fitbit": "", + "gitea": "", + "heroku": "", + "influxcloud": "", + "instagram": "", + "intercom": "", + "kakao": "", + "lastfm": "", + "mailru": "", + "meetup": "", + "microsoftonline": "", + "naver": "", + "nextcloud": "", + "onedrive": "", + "oura": "", + "patreon": "", + "paypal": "", + "salesforce": "", + "shopify": "", + "soundcloud": "", + "spotify": "", + "strava": "", + "stripe": "", + "tiktok": "", + "tumblr": "", + "twitch": "", + "twitter": "", + "typetalk": "", + "uber": "", + "vk": "", + "wepay": "", + "xero": "", + "yahoo": "", + "yammer": "", + "yandex": "", + "zoom": "", + "metamask": "", + "web3onboard": "", + "custom": "", + "webauthnCredentials": null, + "preferredMfaType": "", + "recoveryCodes": null, + "totpSecret": "", + "mfaPhoneEnabled": false, + "mfaEmailEnabled": false, + "invitation": "", + "invitationCode": "", + "faceIds": null, + "ldap": "", + "properties": {}, + "roles": null, + "permissions": null, + "groups": [], + "lastChangePasswordTime": "", + "lastSigninWrongTime": "", + "signinWrongTimes": 0, + "managedAccounts": null, + "mfaAccounts": null, + "mfaItems": null, + "mfaRememberDeadline": "", + "needUpdatePassword": false, + "ipWhitelist": "" + }, + { + "owner": "built-in", + "name": "admin", + "createdTime": "2025-09-20T10:47:17Z", + "updatedTime": "", + "deletedTime": "", + "id": "1e3b4ee5-7164-47c4-a421-a2ff4938c765", + "externalId": "", + "type": "normal-user", + "password": "123", + "passwordSalt": "", + "passwordType": "plain", + "displayName": "Admin", + "firstName": "", + "lastName": "", + "avatar": "https://cdn.casbin.org/img/casbin.svg", + "avatarType": "", + "permanentAvatar": "", + "email": "admin@example.com", + "emailVerified": false, + "phone": "12345678910", + "countryCode": "US", + "region": "", + "location": "", + "address": [], + "affiliation": "Example Inc.", + "title": "", + "idCardType": "", + "idCard": "", + "homepage": "", + "bio": "", + "tag": "staff", + "language": "", + "gender": "", + "birthday": "", + "education": "", + "score": 2000, + "karma": 0, + "ranking": 1, + "balance": 0, + "currency": "", + "isDefaultAvatar": false, + "isOnline": false, + "isAdmin": true, + "isForbidden": false, + "isDeleted": false, + "signupApplication": "app-built-in", + "hash": "", + "preHash": "", + "accessKey": "", + "accessSecret": "", + "accessToken": "", + "createdIp": "127.0.0.1", + "lastSigninTime": "", + "lastSigninIp": "", + "github": "", + "google": "", + "qq": "", + "wechat": "", + "facebook": "", + "dingtalk": "", + "weibo": "", + "gitee": "", + "linkedin": "", + "wecom": "", + "lark": "", + "gitlab": "", + "adfs": "", + "baidu": "", + "alipay": "", + "casdoor": "", + "infoflow": "", + "apple": "", + "azuread": "", + "azureadb2c": "", + "slack": "", + "steam": "", + "bilibili": "", + "okta": "", + "douyin": "", + "kwai": "", + "line": "", + "amazon": "", + "auth0": "", + "battlenet": "", + "bitbucket": "", + "box": "", + "cloudfoundry": "", + "dailymotion": "", + "deezer": "", + "digitalocean": "", + "discord": "", + "dropbox": "", + "eveonline": "", + "fitbit": "", + "gitea": "", + "heroku": "", + "influxcloud": "", + "instagram": "", + "intercom": "", + "kakao": "", + "lastfm": "", + "mailru": "", + "meetup": "", + "microsoftonline": "", + "naver": "", + "nextcloud": "", + "onedrive": "", + "oura": "", + "patreon": "", + "paypal": "", + "salesforce": "", + "shopify": "", + "soundcloud": "", + "spotify": "", + "strava": "", + "stripe": "", + "tiktok": "", + "tumblr": "", + "twitch": "", + "twitter": "", + "typetalk": "", + "uber": "", + "vk": "", + "wepay": "", + "xero": "", + "yahoo": "", + "yammer": "", + "yandex": "", + "zoom": "", + "metamask": "", + "web3onboard": "", + "custom": "", + "webauthnCredentials": null, + "preferredMfaType": "", + "recoveryCodes": null, + "totpSecret": "", + "mfaPhoneEnabled": false, + "mfaEmailEnabled": false, + "invitation": "", + "invitationCode": "", + "faceIds": null, + "ldap": "", + "properties": {}, + "roles": null, + "permissions": null, + "groups": null, + "lastChangePasswordTime": "", + "lastSigninWrongTime": "", + "signinWrongTimes": 0, + "managedAccounts": null, + "mfaAccounts": null, + "mfaItems": null, + "mfaRememberDeadline": "", + "needUpdatePassword": false, + "ipWhitelist": "" + } + ], + "certs": [ + { + "owner": "admin", + "name": "cert-built-in", + "createdTime": "2025-09-20T10:47:17Z", + "displayName": "Built-in Cert", + "scope": "JWT", + "type": "x509", + "cryptoAlgorithm": "RS256", + "bitSize": 4096, + "expireInYears": 20, + "certificate": "-----BEGIN CERTIFICATE-----\nMIIE3TCCAsWgAwIBAgIDAeJAMA0GCSqGSIb3DQEBCwUAMCgxDjAMBgNVBAoTBWFk\nbWluMRYwFAYDVQQDEw1jZXJ0LWJ1aWx0LWluMB4XDTI1MDkyMDEwNDcxOFoXDTQ1\nMDkyMDEwNDcxOFowKDEOMAwGA1UEChMFYWRtaW4xFjAUBgNVBAMTDWNlcnQtYnVp\nbHQtaW4wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDL9L2vPZEXUP4z\nmbVhlgpQx35HzCvQGr+Hbi+ENf5rUadq2X8JVJ5Js3vsi/dMXoXuw2wScltgayEp\nOuyh775uXC/gOrKgfnwANE9VRU9jwBdpZcLeQBfZB2gVQZDYt2wZBSpCwp78I2AS\neWgpvBDXDTp8fV2bJBu7yaLPTdysXVCpdHEkEan7xCAY9yHl9psiqn8aVD4f9T+U\n/oHRIvyAVLpxgQ6w/Lsk2Zcw7lI4feRlF0PYQouoof91gnOIjkYEyFvF/imuL+Xg\nQuA6yMfJ04lfLt8lwu3jAwGw7VIA8LE2pQ6DmJ4pEbFBMU3H626HNel1dxEjW/j+\nTv47nkCPpXGI0w17fc54fbZ7VmtZ6LizxkBfhWf+j8Rm3hpMr6tJ6ISjUajyB17U\n1w9QWU9pOJa/cehOVczEehQLjhX5MZGAUovlmMNojKAtOO/tdcRsDMwOHJyXBqHa\noCykyJ00eIguTtmTTboAqdx3cpom8wNjRh5sUB+YkpsYTVVe/a5r0olfZHDos5bf\nknJXi9X+ppD7nvoCtwrki6AH5Dw9prsrql3sagUHgBKBVLG3EIhDIlkRTQDOO55C\n8OzuyVbDkIbcEX8BIFj8yoUAP/DcpazHHOGhjHRRcFvVHAGRtz8fH6qB9hX3N3a+\nTevIZoANOYLgN6ACWJ0bODLAO9pwWwIDAQABoxAwDjAMBgNVHRMBAf8EAjAAMA0G\nCSqGSIb3DQEBCwUAA4ICAQAT63JAwjc151XNWbMSr5ClNGd+bwEx+zDnQh/YD8V7\n8Wqj2E4r8B+wysDVu7YdOQkoIjtlFOLACg0469F7oC+kPi6N8vMFFZ+xXWk6qLed\nOFYsdUyH+l643GfMprFMA1qbJvqcOnymggeMA1rSJMu9PJ5g7WfoEg6UTKh7H9HV\nvHvgVzLweiZCS37FCC5+RDt/rOCzIrI2DfwDbf4CLKXft7mr3mnA3kVRuT+ufI9X\n+e6UqmM7EBFYeZAHi8/GXIQ8/j34ag5hiIISMhjuFYKEfMtqLYUCTH6X7NTGbGrv\nAs8YB2x5QnUj89N7IRv2hr1uJnaZOIx5feLRmuRmo35scLopAnNu0VT75TOS0Ifh\nyrouqlep4grk4DMFSWEMNodpkHHLr4pOVE8vCYphli75/beOkiilUpxGI6/osKKo\nSOC5CuC6hDarVBF3q6zpNEnqalQf9Vf2d4zeCKMfV2IuUOqKRaRFpVZfVJsbiYTi\nYF1VUCTFdfrIFsC5V9LknxvLyq8ubzpXHnIV6m/l95OxxCEDvI47l5RmwkblKk57\nH9IRmr6l66Ar2WRGQYAxpiOz3aF8IMg8f0+Vk91FNTsgNrSsk9uovQrrDDtm3KyO\nEzhOO4NA9WgaE1c6GzZD87GhrZukHWHE4KvTpkiQ3pGmTqUjIHvon+0lKtG8E5fz\nKg==\n-----END CERTIFICATE-----\n", + "privateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIJKQIBAAKCAgEAy/S9rz2RF1D+M5m1YZYKUMd+R8wr0Bq/h24vhDX+a1Gnatl/\nCVSeSbN77Iv3TF6F7sNsEnJbYGshKTrsoe++blwv4DqyoH58ADRPVUVPY8AXaWXC\n3kAX2QdoFUGQ2LdsGQUqQsKe/CNgEnloKbwQ1w06fH1dmyQbu8miz03crF1QqXRx\nJBGp+8QgGPch5fabIqp/GlQ+H/U/lP6B0SL8gFS6cYEOsPy7JNmXMO5SOH3kZRdD\n2EKLqKH/dYJziI5GBMhbxf4pri/l4ELgOsjHydOJXy7fJcLt4wMBsO1SAPCxNqUO\ng5ieKRGxQTFNx+tuhzXpdXcRI1v4/k7+O55Aj6VxiNMNe33OeH22e1ZrWei4s8ZA\nX4Vn/o/EZt4aTK+rSeiEo1Go8gde1NcPUFlPaTiWv3HoTlXMxHoUC44V+TGRgFKL\n5ZjDaIygLTjv7XXEbAzMDhyclwah2qAspMidNHiILk7Zk026AKncd3KaJvMDY0Ye\nbFAfmJKbGE1VXv2ua9KJX2Rw6LOW35JyV4vV/qaQ+576ArcK5IugB+Q8Paa7K6pd\n7GoFB4ASgVSxtxCIQyJZEU0AzjueQvDs7slWw5CG3BF/ASBY/MqFAD/w3KWsxxzh\noYx0UXBb1RwBkbc/Hx+qgfYV9zd2vk3ryGaADTmC4DegAlidGzgywDvacFsCAwEA\nAQKCAgEAtERUJ4BuLkKa+3afF2qrIWzB06nFC8GoiYY9H0kt3yMjq1AjdVbCNPgb\nzx6C7JAbJsa5TbCfzR/DBpMbNaIWGasHcdPPsAU7il6xw/dnzQ2qY7DaxN+3dE6U\nkz0JTlMIizDCgpFMPiTyNEH0a/bal4kMqZ2Qz5/hl2AHs9zo77vmoG/X1H58VJer\nmwVLg9sskT5K6zWMV2jH0uQET5nxvWemBs5/8rTeoBpmBIyQRXgYF7WxdIKUt+6/\nQNiVTxwZDP8eBmi35EpXjpjtYWe3Fk8O+v8Nom2hHuW4Z+3KbiRPLbJDmtKY8Em/\n9pQiYFJZtc5T00vy7OLMt9GP6ZfdDMXHqGT/VFJuYNQhRWgaf9JE5zZuQ3O/D1BH\nAbY0+a825DcOn2XqP3KlHOR1CJyFhphZDowxg2pjhQ548+30eQ9/IoTvgrEnReRW\n3/USVvcUA4lgmzKv50BLiy9wK55FVglafdRm1fq3ykQwAZ/ok4ah2U+ZA98Hh8/V\n4xZ/KSBlNxSfBEPKlPkSBBrwqUwZtrwcHUg0qiRrJGvGxqKPUb0kOQmQjX2VNPoU\nPYzHO9G83RFeJU5KjMj9+apXV2qSL1m8wFJ/aHraUoaOhQ7AzETY0H8r0EbBunq3\nQ8s3Foeb3/p9DOxZxODaDKYDKHM43h1Oro+JjXy+21KSBBjAQrkCggEBAOZzNUlB\nayl/c6ynVlaYR2UGPdbymbAu8dB2Yj/OFjKQgWl2pKVpjUvva7A8p0smU+oC3fVQ\n9qBT6834N8jUqKUCxkHnVw1UDhXPJofqOkaLwf4cLL3X1PbPShaZbEM45YZqmU/c\npihL/myVcXFxntzQZ9NxzJU1wu4uwII0jd1ciFNssulxobgN0JDLM3jJ+Vf1yFUC\nJgCscZcRWBb0HW1IxHVic3GPEzg1hwgyt9V+e/xdKuy4+LQuPPsVBiy5lsVBtwXY\nN5Ve2k9dp0etnoQE+xjdcDwJVNgD46C4nw8e177u20cDyevILbxCRlSJ/ptQXgVu\nc3UZ9o9Y51N9HfUCggEBAOKRj7vGLhUf0Tv7+qroktTaj6jFUQr+JFQKuOTAHo1C\nghyIAtDjDPl3Be+DWPrvXSswEjOqI/haTjxUmTQgJEmuQEfebE7n0fOf25jcCFwb\nIEFgzvLJSvEiZX7y8nPFffP5TSzS/gxiqNZVJ0im3aAYUK48DXY+6Sg+xhOAPpzY\nysLifc6P2WlGt3OntuMYYgCqGwmlnRNVADdlqt5EH/mRRuxjqGQqXovozlQ8UBTL\nDX4fDLjkcqdG22mOD0qscvsG36LTjpcERposjQ6Qa6QFkGoNd5qYTILW3oq36NsJ\nevucMPSK6HWEbCkrC9Z6Q+PSuILHRNWJSThkAuzKkw8CggEAb6BEomxWvS4oWOxh\njOaMRqokUDcJLOdAaKq/YoqwA+QtW2mFzT34nFynvCFVI7i4EvU6kHacUAL2iLmA\nQ/6Ghg92+ztU1nbtr7C8yD8z5TITUMRTA85FMRwtlg7Q+yrXOyntg1qs/X36CpzE\n65+OxQUKFcjcwTXea0MoKqnMQfptaoOPkjZhkGbYrRpQn2SuK+Y5GLxGrjLZfsR+\n9/ddPa9uwjFjHBGizKpY8yamF3sCEbcLcMkUZyqyjSic6hMnrfrr7Z/TJL5iXulN\nexHlY6uJ+XxhviMC/vO7UgG7wjY9aRYIDzkNmPFI/hTYPmDtfEwMjvL2aDWgUcVN\noApN9QKCAQEAyhT21I7BD4pff1cSj1n9jOicdfX4gQuIr4UYwL8zAN+vWW9ew52g\nNumYW7cVqEvTF/A6a+Z3Ss6RNXJna3y3oRhQsUmL5R0TwG522XJ36l8vd+C29Qnh\nVA5P5Nkgs24VF4Tm9vICMl3VJcax0TU0O9U0MRPTFgKqx4Cl/0LFlfQvdX+6ooDf\nc+zlN70BfLCEyP7wOryCy3lnRgHiU3kD4/9V+QYybZT022l8jtl0u/cYQ8PB/y+T\nq+uhTBavQPVrYMcStRJo/f2MU3slHTZnK9biphT49uScaZ7ow2WhxaxBCyaW66by\nC89fAaEpX9WRtCSA+fRuSt+2dRuPGFDetQKCAQBNxBbtOrw79tpq7NaSWlylTR+K\nQJeUSol1NpktS17dLesFc6c4vVc90tOrQvmK9MoOdYpk7/ZMpIpXtgtoegEnN34r\nbfyb+O4UeOi44Y/cKr1Av3bZmp2lRQtTXZJkRlRI5kowVAHOP70WWytcfIYW+zbZ\nOSRiQOT2UFaIQjdZml9jvD/Zhr8TuLPZoaRuhWVLID0LZrix9ivYD028uHoiONl3\nbmzNhqTlcGC/skh5hn6ohEyizvHLIrpbUPK66xOWjcheFi+wKfGpKOZxt325y64D\nhQkmJquirnONmiUNuKWIUxOkbC/spnrAJ72dStfEo2V59hG5jitTlmoaXAo+\n-----END RSA PRIVATE KEY-----\n" + } + ], + "providers": [ + { + "owner": "admin", + "name": "provider_captcha_default", + "createdTime": "2025-09-20T10:47:17Z", + "displayName": "Captcha Default", + "category": "Captcha", + "type": "Default", + "subType": "", + "method": "", + "clientId": "", + "clientSecret": "", + "clientId2": "", + "clientSecret2": "", + "cert": "", + "customAuthUrl": "", + "customTokenUrl": "", + "customUserInfoUrl": "", + "customLogo": "", + "scopes": "", + "userMapping": null, + "httpHeaders": null, + "host": "", + "port": 0, + "disableSsl": false, + "title": "", + "content": "", + "receiver": "", + "regionId": "", + "signName": "", + "templateCode": "", + "appId": "", + "endpoint": "", + "intranetEndpoint": "", + "domain": "", + "bucket": "", + "pathPrefix": "", + "metadata": "", + "idP": "", + "issuerUrl": "", + "enableSignAuthnRequest": false, + "emailRegex": "", + "providerUrl": "" + } + ], + "ldaps": [ + { + "id": "ldap-built-in", + "owner": "built-in", + "createdTime": "2025-09-20T10:47:18Z", + "serverName": "BuildIn LDAP Server", + "host": "example.com", + "port": 389, + "enableSsl": false, + "allowSelfSignedCert": false, + "username": "cn=buildin,dc=example,dc=com", + "password": "123", + "baseDn": "ou=BuildIn,dc=example,dc=com", + "filter": "", + "filterFields": null, + "defaultGroup": "", + "passwordType": "", + "autoSync": 0, + "lastSync": "" + } + ], + "models": [ + { + "owner": "built-in", + "name": "api-model-built-in", + "createdTime": "2025-09-20T10:47:18Z", + "displayName": "API Model", + "description": "", + "modelText": "[request_definition]\nr = subOwner, subName, method, urlPath, objOwner, objName\n\n[policy_definition]\np = subOwner, subName, method, urlPath, objOwner, objName\n\n[role_definition]\ng = _, _\n\n[policy_effect]\ne = some(where (p.eft == allow))\n\n[matchers]\nm = (r.subOwner == p.subOwner || p.subOwner == \"*\") \u0026\u0026 \\\n (r.subName == p.subName || p.subName == \"*\" || r.subName != \"anonymous\" \u0026\u0026 p.subName == \"!anonymous\") \u0026\u0026 \\\n (r.method == p.method || p.method == \"*\") \u0026\u0026 \\\n (r.urlPath == p.urlPath || p.urlPath == \"*\") \u0026\u0026 \\\n (r.objOwner == p.objOwner || p.objOwner == \"*\") \u0026\u0026 \\\n (r.objName == p.objName || p.objName == \"*\") || \\\n (r.subOwner == r.objOwner \u0026\u0026 r.subName == r.objName)" + }, + { + "owner": "built-in", + "name": "user-model-built-in", + "createdTime": "2025-09-20T10:47:18Z", + "displayName": "Built-in Model", + "description": "", + "modelText": "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _\n\n[policy_effect]\ne = some(where (p.eft == allow))\n\n[matchers]\nm = g(r.sub, p.sub) \u0026\u0026 r.obj == p.obj \u0026\u0026 r.act == p.act" + } + ], + "permissions": [ + { + "owner": "built-in", + "name": "permission-built-in", + "createdTime": "2025-09-20T10:47:17Z", + "displayName": "Built-in Permission", + "description": "Built-in Permission", + "users": [ + "built-in/*" + ], + "groups": [], + "roles": [], + "domains": [], + "model": "user-model-built-in", + "adapter": "", + "resourceType": "Application", + "resources": [ + "app-built-in" + ], + "actions": [ + "Read", + "Write", + "Admin" + ], + "effect": "Allow", + "isEnabled": true, + "submitter": "admin", + "approver": "admin", + "approveTime": "2025-09-20T10:47:17Z", + "state": "Approved" + } + ], + "payments": [], + "products": [], + "resources": [], + "roles": [ + { + "owner": "example-org", + "name": "example-role", + "createdTime": "2025-09-20T18:58:05+08:00", + "displayName": "示例角色", + "description": "", + "users": [ + "example-org/example-user" + ], + "groups": [], + "roles": [], + "domains": [], + "isEnabled": true + }, + { + "owner": "built-in", + "name": "role_m06bnm", + "createdTime": "2025-09-20T18:57:13+08:00", + "displayName": "New Role - m06bnm", + "description": "", + "users": [], + "groups": [], + "roles": [], + "domains": [], + "isEnabled": true + } + ], + "syncers": [], + "tokens": [ + { + "owner": "admin", + "name": "3511665e-fe71-4497-8a96-a2f298e3751d", + "createdTime": "2025-09-20T10:59:43Z", + "application": "app-built-in", + "organization": "built-in", + "user": "admin", + "code": "7f586f871be50a1b2671", + "accessToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImNlcnQtYnVpbHQtaW4iLCJ0eXAiOiJKV1QifQ.eyJvd25lciI6ImJ1aWx0LWluIiwibmFtZSI6ImFkbWluIiwiY3JlYXRlZFRpbWUiOiIyMDI1LTA5LTIwVDEwOjQ3OjE3WiIsInVwZGF0ZWRUaW1lIjoiIiwiZGVsZXRlZFRpbWUiOiIiLCJpZCI6IjFlM2I0ZWU1LTcxNjQtNDdjNC1hNDIxLWEyZmY0OTM4Yzc2NSIsInR5cGUiOiJub3JtYWwtdXNlciIsInBhc3N3b3JkIjoiIiwicGFzc3dvcmRTYWx0IjoiIiwicGFzc3dvcmRUeXBlIjoicGxhaW4iLCJkaXNwbGF5TmFtZSI6IkFkbWluIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4ub3JnL2ltZy9jYXNiaW4uc3ZnIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6IiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxMjM0NTY3ODkxMCIsImNvdW50cnlDb2RlIjoiVVMiLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IkV4YW1wbGUgSW5jLiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjoyMDAwLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjp0cnVlLCJpc0ZvcmJpZGRlbiI6ZmFsc2UsImlzRGVsZXRlZCI6ZmFsc2UsInNpZ251cEFwcGxpY2F0aW9uIjoiYXBwLWJ1aWx0LWluIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIxMjcuMC4wLjEiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoiYWNjZXNzLXRva2VuIiwidGFnIjoic3RhZmYiLCJzY29wZSI6InByb2ZpbGUiLCJhenAiOiIxZDFlYjNjODkxZmE4ZmFhN2Q2MyIsImlzcyI6Imh0dHA6Ly8xNzIuMzAuMzQuMTg0OjgwMDQiLCJzdWIiOiIxZTNiNGVlNS03MTY0LTQ3YzQtYTQyMS1hMmZmNDkzOGM3NjUiLCJhdWQiOlsiMWQxZWIzYzg5MWZhOGZhYTdkNjMiXSwiZXhwIjoxNzU4OTcwNzgzLCJuYmYiOjE3NTgzNjU5ODMsImlhdCI6MTc1ODM2NTk4MywianRpIjoiYWRtaW4vMzUxMTY2NWUtZmU3MS00NDk3LThhOTYtYTJmMjk4ZTM3NTFkIn0.TeqMA2waDtY2CQYNEkMdOdNHzXBpxdk203qMnu_6EbVgR4dEdEmEqaJ4wn-oiLvdTgoMfZ_Fb4De4iyp8jRNYdTMylo82RhcF4jsU_C8sLzeE6tENPcVQ3xJq7oOFtLCWa2V0lmE3SuypJtI2Vki5AEOds9en2Y1RCCryug6LgVo_94MnmCWlQW3pYZG5cmrKVGHBlyIK0Nw01IBBxfkPOga1s50QZaCR3Cva8SjaoY1Cx-AtU5vKzHRjp63bfrhP9JXfeP2xrL0ZyZ6LBHsCsA_1FyojAndZCNahCpAZH0_s6I0nJan0NLkBZhR89TE-Ys5SygvgkofSsyNJ7jhLh21oTdvpheUFDOqNtjBE36Et1EUFsm3jc88fRUsgzArR4pg_6YPybSMJeUrTtgpngBi-yKTs3jOo3hUszMixJrE1kXyVqMeesyrAt-HJWLBh_wx8L5BfwsgZgCRwULvbMRCH33Jfn3hG9jxu9DoLM9OvBm7HqPWXhioGG_4RII0PE9QBmN2cIPfJokf6f_FgO8O-kvwH5LUhW5HpiNJar6oOdn7aamkpuI7BBEn6YxF7c-qr1scVGBum46wQRSJ4Hl_pMwGZ1uyB76zXSaM2nqRO4MX3g7vaySq1FrL68JpYizW8ejDnuSqovVhyDwgJ_iEVbP5z7aDicOemrgoN-I", + "refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJvd25lciI6ImJ1aWx0LWluIiwibmFtZSI6ImFkbWluIiwiY3JlYXRlZFRpbWUiOiIyMDI1LTA5LTIwVDEwOjQ3OjE3WiIsInVwZGF0ZWRUaW1lIjoiIiwiZGVsZXRlZFRpbWUiOiIiLCJpZCI6IjFlM2I0ZWU1LTcxNjQtNDdjNC1hNDIxLWEyZmY0OTM4Yzc2NSIsInR5cGUiOiJub3JtYWwtdXNlciIsInBhc3N3b3JkIjoiIiwicGFzc3dvcmRTYWx0IjoiIiwicGFzc3dvcmRUeXBlIjoicGxhaW4iLCJkaXNwbGF5TmFtZSI6IkFkbWluIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4ub3JnL2ltZy9jYXNiaW4uc3ZnIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6IiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxMjM0NTY3ODkxMCIsImNvdW50cnlDb2RlIjoiVVMiLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IkV4YW1wbGUgSW5jLiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjoyMDAwLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjp0cnVlLCJpc0ZvcmJpZGRlbiI6ZmFsc2UsImlzRGVsZXRlZCI6ZmFsc2UsInNpZ251cEFwcGxpY2F0aW9uIjoiYXBwLWJ1aWx0LWluIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIxMjcuMC4wLjEiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoicmVmcmVzaC10b2tlbiIsInRhZyI6InN0YWZmIiwic2NvcGUiOiJwcm9maWxlIiwiYXpwIjoiMWQxZWIzYzg5MWZhOGZhYTdkNjMiLCJpc3MiOiJodHRwOi8vMTcyLjMwLjM0LjE4NDo4MDA0Iiwic3ViIjoiMWUzYjRlZTUtNzE2NC00N2M0LWE0MjEtYTJmZjQ5MzhjNzY1IiwiYXVkIjpbIjFkMWViM2M4OTFmYThmYWE3ZDYzIl0sImV4cCI6MTc1ODk3MDc4MywibmJmIjoxNzU4MzY1OTgzLCJpYXQiOjE3NTgzNjU5ODMsImp0aSI6ImFkbWluLzM1MTE2NjVlLWZlNzEtNDQ5Ny04YTk2LWEyZjI5OGUzNzUxZCJ9.vTiXef-KdyuwQdMEdReDdw5x4DDtSPRCLp5iDNlKaUTY5zWzUixGXU3GlYyNWqtjB8tl1saENUsvfD8k7womxdxJLnbpBu_DgQePF3woEeTaGrs27vIncbdi8ywUb_I8IEuYhjavi3hvaN5rXqouVr09sLZrbu6E65RBw4LM6GEQcUkwxUqd-qIhtV2p49ip9p2SIsvhe4BxVkbjg2EhbaS9Alf4uBeXl_vgjG9vEKj4vr3mol4yyVuwnr-rYYPjPL2QFsJfrUQCxZI9xpDeKgfoKNpmarPHcwxWK5wKcLCSCfc3Nhvnr_iQWr-lW0ZhkgUCbfATljfYSy_Vp6Ro_sSu9mw3Bke35wKt28nOMBQ2f1bx9Inhoi4ocZvV9AShtS56WXgHl5Ts7oM0HG3Z2LcYh-lCEPqTDjG-LW1R9xxaBFRJeV14g_YlUD_uTECjT94xaQs0eqUJHXebE3QJzHt2-rFagZV2iG-QDZDmij3f8VjLcG2zYG1EXfMR5H76xOu7Xyk5YnV5WQYECu_njTSbb-AEdt8syaqzM5LIvrN4Mp0dzbB6xfwXVZrlCF56zemcR17zdcspgSMa7RWphIBWgKPAm65GgAtGAdQEak81IHiF5dZ5xUyCjzrjS-z_RE_Vrf7ra1NUd0xJtJwUMf4AiIO0qI5JhFaTfjT4KlY", + "accessTokenHash": "ea2da0b06f8554f3ea1f3496e54e15cd87f7b5a53b31caecb8685e996ccf0390", + "refreshTokenHash": "a6943e013ca1031c6851c3220062b3591e94e99f1e98e1400ee7354b45cb475e", + "expiresIn": 604800, + "scope": "profile", + "tokenType": "Bearer", + "codeChallenge": "", + "codeIsUsed": true, + "codeExpireIn": 0 + }, + { + "owner": "admin", + "name": "96e45056-947a-4d29-9b59-46e7b2d25889", + "createdTime": "2025-09-20T10:56:34Z", + "application": "app-built-in", + "organization": "built-in", + "user": "admin", + "code": "a32cf35f5ca08f50732e", + "accessToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImNlcnQtYnVpbHQtaW4iLCJ0eXAiOiJKV1QifQ.eyJvd25lciI6ImJ1aWx0LWluIiwibmFtZSI6ImFkbWluIiwiY3JlYXRlZFRpbWUiOiIyMDI1LTA5LTIwVDEwOjQ3OjE3WiIsInVwZGF0ZWRUaW1lIjoiIiwiZGVsZXRlZFRpbWUiOiIiLCJpZCI6IjFlM2I0ZWU1LTcxNjQtNDdjNC1hNDIxLWEyZmY0OTM4Yzc2NSIsInR5cGUiOiJub3JtYWwtdXNlciIsInBhc3N3b3JkIjoiIiwicGFzc3dvcmRTYWx0IjoiIiwicGFzc3dvcmRUeXBlIjoicGxhaW4iLCJkaXNwbGF5TmFtZSI6IkFkbWluIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4ub3JnL2ltZy9jYXNiaW4uc3ZnIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6IiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxMjM0NTY3ODkxMCIsImNvdW50cnlDb2RlIjoiVVMiLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IkV4YW1wbGUgSW5jLiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjoyMDAwLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjp0cnVlLCJpc0ZvcmJpZGRlbiI6ZmFsc2UsImlzRGVsZXRlZCI6ZmFsc2UsInNpZ251cEFwcGxpY2F0aW9uIjoiYXBwLWJ1aWx0LWluIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIxMjcuMC4wLjEiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoiYWNjZXNzLXRva2VuIiwidGFnIjoic3RhZmYiLCJzY29wZSI6InByb2ZpbGUiLCJhenAiOiIxZDFlYjNjODkxZmE4ZmFhN2Q2MyIsImlzcyI6Imh0dHA6Ly8xNzIuMzAuMzQuMTg0OjgwMDQiLCJzdWIiOiIxZTNiNGVlNS03MTY0LTQ3YzQtYTQyMS1hMmZmNDkzOGM3NjUiLCJhdWQiOlsiMWQxZWIzYzg5MWZhOGZhYTdkNjMiXSwiZXhwIjoxNzU4OTcwNTk0LCJuYmYiOjE3NTgzNjU3OTQsImlhdCI6MTc1ODM2NTc5NCwianRpIjoiYWRtaW4vOTZlNDUwNTYtOTQ3YS00ZDI5LTliNTktNDZlN2IyZDI1ODg5In0.WzQyw21sLPwwhCZp6v7PlPM_Muztxl-XFwKtYdg96Fp0mxWzXB3oPfGECFfcqXjNi6n8C42M32deKKUERimOxESI9LehdDwsweyvZN_wyeJgkxmIhN1gQd59TjIglJ134IFYA2AoIxCC76M78ged9hEW_IzoOF2lQh12DISCLY7RuzYpkuY0DTe4QFcRocAp_ZRMTe6wQPN8zPDqhGvJBs173o1CFSdta7TzE9UyFgrfdhITSv2rNlPqi7hbWvOlazDDjY8Qzw40xi7_v2wnO33hbiX_WLMLlJpOTzWnPFWcw9-nYd4rCL3Vxo0CVteNwP3ZuK2HtN8errnM6vXFAng0ZgdtyIQ3wdI1-65cyG6PJGBBq02d6Hgfg1KktnsTtA0tklO2t9YM3ph-EDAMDj35gUyU3sXFfHpVmtB9qKwx6WmcvA6hJvo8Gc79_-SoLE92a_GW_sRojqJJ5rLmb9d6mrU6UqKVTsa1mfV28CnLMkQq7kyxpjpRD41yVh-vdXv4qquHxTIjPtgw6akS3sCjGbTszO5YvvOzQCcHN8brBKnDX0MYvKu7i8-d0roVF0TYLaCDW8EKm1AQlaP7ts6Pi3INeyf6xaXhJfNqQSeqDkmAWNDUUO3okTu8uq4br48inn7GK4e8Dc2QpZScerPlNjKTliOsKZzK1uNCpIA", + "refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJvd25lciI6ImJ1aWx0LWluIiwibmFtZSI6ImFkbWluIiwiY3JlYXRlZFRpbWUiOiIyMDI1LTA5LTIwVDEwOjQ3OjE3WiIsInVwZGF0ZWRUaW1lIjoiIiwiZGVsZXRlZFRpbWUiOiIiLCJpZCI6IjFlM2I0ZWU1LTcxNjQtNDdjNC1hNDIxLWEyZmY0OTM4Yzc2NSIsInR5cGUiOiJub3JtYWwtdXNlciIsInBhc3N3b3JkIjoiIiwicGFzc3dvcmRTYWx0IjoiIiwicGFzc3dvcmRUeXBlIjoicGxhaW4iLCJkaXNwbGF5TmFtZSI6IkFkbWluIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4ub3JnL2ltZy9jYXNiaW4uc3ZnIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6IiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxMjM0NTY3ODkxMCIsImNvdW50cnlDb2RlIjoiVVMiLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IkV4YW1wbGUgSW5jLiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjoyMDAwLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjp0cnVlLCJpc0ZvcmJpZGRlbiI6ZmFsc2UsImlzRGVsZXRlZCI6ZmFsc2UsInNpZ251cEFwcGxpY2F0aW9uIjoiYXBwLWJ1aWx0LWluIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIxMjcuMC4wLjEiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoicmVmcmVzaC10b2tlbiIsInRhZyI6InN0YWZmIiwic2NvcGUiOiJwcm9maWxlIiwiYXpwIjoiMWQxZWIzYzg5MWZhOGZhYTdkNjMiLCJpc3MiOiJodHRwOi8vMTcyLjMwLjM0LjE4NDo4MDA0Iiwic3ViIjoiMWUzYjRlZTUtNzE2NC00N2M0LWE0MjEtYTJmZjQ5MzhjNzY1IiwiYXVkIjpbIjFkMWViM2M4OTFmYThmYWE3ZDYzIl0sImV4cCI6MTc1ODk3MDU5NCwibmJmIjoxNzU4MzY1Nzk0LCJpYXQiOjE3NTgzNjU3OTQsImp0aSI6ImFkbWluLzk2ZTQ1MDU2LTk0N2EtNGQyOS05YjU5LTQ2ZTdiMmQyNTg4OSJ9.FxxMAsCarLLg6uDuP67z5zqTvgEufohViNlpM9z9127XStlOShcXRR3C4Z-OwDRP65QmqqidWY-Sn2VkaxWnpKB_Du-KLBHDKz2XRKv20Qg9E8Q25rcyiBl2RnRa3pFfnekaOw9fj21S0LAkUEuqqsbotDeOv_B9seMRptAGcuhdTY0pMnurRh6b4-tt0fhH1CxlI1LZX5fFS7EWPACqZ2OCYVujU43jicusnXPpPwq2mKiKBGDx-sBXyVIpBuocLJrJDIClV6S0yqMtfbkwM5n7q8GDg-Md9_wsQ9ZT6MmRHzEOP2LI3B8UNZ4EHkzclVRQSaQWlh4QBXmYpoHJWLH5-inNQ0XON4zGmgdsEY-PKY6sYa2Qkf6tXCY7J_l8lUMLtvU_PUkamrZYNyB29JsCTSBHUpk2CuZ2kVyhSZ2v2oAr6v80kywJrEesuP1ErYR3BXwXRUiDZ4qds5I8BolrNGS0Ew3aMyPVmcJ8FxoDcwViDzcy-aMnaUPnpa7yV1BgLShKp_KD0byd28cns5ARbEi2XZwA7pCsE59QHI655OQNGCIM9hofMK0PIl4aJGyNVOVRZeNc-JvrwNdjR_bGYVJYo5e2XygRoedtlCg5hPpUzr9V82eIqmY8noU1yN0vneH-h24GLeDcb0OILaGvYBuMn8l0cslfDMxeK7Y", + "accessTokenHash": "b731f1895b7fd0397844fb3926495c7791f8cd4670e10661b7d07c67d684ca51", + "refreshTokenHash": "fe4612153bba0a17aecefd1ca69da23dd2e30fcb55f91f16fbc052d4d12739fa", + "expiresIn": 604800, + "scope": "profile", + "tokenType": "Bearer", + "codeChallenge": "", + "codeIsUsed": true, + "codeExpireIn": 0 + }, + { + "owner": "admin", + "name": "c8fea633-4187-49d6-b94c-e43306f5a32e", + "createdTime": "2025-09-20T10:56:24Z", + "application": "example-app", + "organization": "example-org", + "user": "example-user", + "code": "032fd4699c85d5444a80", + "accessToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImNlcnQtYnVpbHQtaW4iLCJ0eXAiOiJKV1QifQ.eyJvd25lciI6ImV4YW1wbGUtb3JnIiwibmFtZSI6ImV4YW1wbGUtdXNlciIsImNyZWF0ZWRUaW1lIjoiMjAyNS0wOS0yMFQxMDo1NjoyMVoiLCJ1cGRhdGVkVGltZSI6IiIsImRlbGV0ZWRUaW1lIjoiIiwiaWQiOiIzZDdjY2EyYi04ZGE5LTQxYmYtYjUzNS02YzlmODNkNzMxZGIiLCJ0eXBlIjoibm9ybWFsLXVzZXIiLCJwYXNzd29yZCI6IiIsInBhc3N3b3JkU2FsdCI6IiIsInBhc3N3b3JkVHlwZSI6InBsYWluIiwiZGlzcGxheU5hbWUiOiLnpLrkvovnlKjmiLciLCJmaXJzdE5hbWUiOiIiLCJsYXN0TmFtZSI6IiIsImF2YXRhciI6Imh0dHBzOi8vY2RuLmNhc2Jpbi5vcmcvaW1nL2Nhc2Jpbi5zdmciLCJhdmF0YXJUeXBlIjoiIiwicGVybWFuZW50QXZhdGFyIjoiIiwiZW1haWwiOiIiLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxODg4ODg4ODg4OCIsImNvdW50cnlDb2RlIjoiQ04iLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjowLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjpmYWxzZSwiaXNGb3JiaWRkZW4iOmZhbHNlLCJpc0RlbGV0ZWQiOmZhbHNlLCJzaWdudXBBcHBsaWNhdGlvbiI6ImV4YW1wbGUtYXBwIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoiYWNjZXNzLXRva2VuIiwidGFnIjoiIiwic2NvcGUiOiJwcm9maWxlIiwiYXpwIjoiZTNiYTZmZWM0MmNmZTk5NjEyMWYiLCJpc3MiOiJodHRwOi8vMTcyLjMwLjM0LjE4NDo4MDA0Iiwic3ViIjoiM2Q3Y2NhMmItOGRhOS00MWJmLWI1MzUtNmM5ZjgzZDczMWRiIiwiYXVkIjpbImUzYmE2ZmVjNDJjZmU5OTYxMjFmIl0sImV4cCI6MTc1ODk3MDU4NCwibmJmIjoxNzU4MzY1Nzg0LCJpYXQiOjE3NTgzNjU3ODQsImp0aSI6ImFkbWluL2M4ZmVhNjMzLTQxODctNDlkNi1iOTRjLWU0MzMwNmY1YTMyZSJ9.buJ10cMxbnIS6LRrAjMkJrtOw-V0NJWJ2ySfk-uzWLTxA1SOXwA1DGa8wsn5k0WUyCy6RSN3d3Kl75hz2qwKZdABc4E9tiqx7J_obXxGjAZwZozmWrzBLMBCXjIHk89qc7b6AEbndNbSR0_MDRWunNNwqGvY6H4q3rSAA0Cu-sKLW1xUIpvRLVq3pF2ddWd3_4t30O4uDR7q3PBzmGeCKfRxiCEB3TYcq89rGfS9frKXl7vN9m9wSM6Q6Pqx1IFkALoUl1Z45GIHSn9nzRTuPr5dbeD2jOI9Y-3tHndRrKioyKGZcBgPhzEFmFY6oBWbzoK1TQEGJMk667RfVxew9aE-hXA07yxL7el1p6ZIG_RoUw9MYC0NzjYtiDWg8qamDX2Om7NRs6-e11hPbq3-kvyO9sFdu9aFzpPE-2vcpUfyI0jgg9QRpPjYJ00_WbtTW1caIfAu1RlWK7M56GFylKXtQkLDlz7R1d5pY9z6kMmoBOu-eiLdKfA1QWhGvDp6g3m3HBPCVd7J0lAGnQFFzTaO5adTpTlfN7PHnd1U4hhfSlU525s7-dRIiKjRLeKgehmAAlwlG_M7_huapbGpAxg_t2kDmOsGf9vxbbiHt9x-vYtnyT9rF6XRttAzRfddl3kEsg8vZpG1K9IV5b0mGmYMB2UAdC-YFlVD6FSAjrQ", + "refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJvd25lciI6ImV4YW1wbGUtb3JnIiwibmFtZSI6ImV4YW1wbGUtdXNlciIsImNyZWF0ZWRUaW1lIjoiMjAyNS0wOS0yMFQxMDo1NjoyMVoiLCJ1cGRhdGVkVGltZSI6IiIsImRlbGV0ZWRUaW1lIjoiIiwiaWQiOiIzZDdjY2EyYi04ZGE5LTQxYmYtYjUzNS02YzlmODNkNzMxZGIiLCJ0eXBlIjoibm9ybWFsLXVzZXIiLCJwYXNzd29yZCI6IiIsInBhc3N3b3JkU2FsdCI6IiIsInBhc3N3b3JkVHlwZSI6InBsYWluIiwiZGlzcGxheU5hbWUiOiLnpLrkvovnlKjmiLciLCJmaXJzdE5hbWUiOiIiLCJsYXN0TmFtZSI6IiIsImF2YXRhciI6Imh0dHBzOi8vY2RuLmNhc2Jpbi5vcmcvaW1nL2Nhc2Jpbi5zdmciLCJhdmF0YXJUeXBlIjoiIiwicGVybWFuZW50QXZhdGFyIjoiIiwiZW1haWwiOiIiLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxODg4ODg4ODg4OCIsImNvdW50cnlDb2RlIjoiQ04iLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjowLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjpmYWxzZSwiaXNGb3JiaWRkZW4iOmZhbHNlLCJpc0RlbGV0ZWQiOmZhbHNlLCJzaWdudXBBcHBsaWNhdGlvbiI6ImV4YW1wbGUtYXBwIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoicmVmcmVzaC10b2tlbiIsInRhZyI6IiIsInNjb3BlIjoicHJvZmlsZSIsImF6cCI6ImUzYmE2ZmVjNDJjZmU5OTYxMjFmIiwiaXNzIjoiaHR0cDovLzE3Mi4zMC4zNC4xODQ6ODAwNCIsInN1YiI6IjNkN2NjYTJiLThkYTktNDFiZi1iNTM1LTZjOWY4M2Q3MzFkYiIsImF1ZCI6WyJlM2JhNmZlYzQyY2ZlOTk2MTIxZiJdLCJleHAiOjE3NTg5NzA1ODQsIm5iZiI6MTc1ODM2NTc4NCwiaWF0IjoxNzU4MzY1Nzg0LCJqdGkiOiJhZG1pbi9jOGZlYTYzMy00MTg3LTQ5ZDYtYjk0Yy1lNDMzMDZmNWEzMmUifQ.ncEansC9KmS4KRzM7J-8X1GWxOZPa6paHyTa71o1-kYA47IxZlnta5V8HPorNDL-uiKy6JaxIa9s9qd8SgBfqNcf1LWjOnsjScJuvbnDthS4db0RTPgqN_roaBAf4O_vSFxhvDAFy796zNXpbRbo3HfVIC7la_K5Y-3Qg4PaviX2oI5Rs9jQ1ao4iWUsADDMkQHTNS5LSlgQee_tAk_DbtJ7tB2Fw6z8xr23BM7FksfxnYLH9HFYxv7NxLkNeeskEGkTVpMgQaQzNs19bVDzfG0O5zcHjxjQIx76Q1GotTD2V-x59_VilM0Avr39exhPRc8v3y6Jp5j0TtMd2LvTMWrGkrINW25mBijbuGB1xfMy7LsyPR8lerFt--xG_kelRK4HL76XaZF9pz73FU6IYCv9QpYothE_zVYOEkrmkaNltpfFckoCPMwY5dIN8_sco3P88X607XervKFVcs3ArCA8sL3mHjX--xZ_FK2A_5Jmi_oriSytU-uwQPbIbMATr5CPKOpwuIrkCugjOIi1HyojzSYcmSdxmM9MiOW5Qx92nTBVd1g_b6Px5bZzENXey2mFtDVLy2P2Eh8ihaZXY1IymTXKbJfn5rgEg5PjkdA_7dyrX-bBTg8xwX3vQH6y8_j_69vDHd57rivUcy_ZbQCz6QQCgVkVallpZZuk7U4", + "accessTokenHash": "5d07861e82306dcbcb9b5dbb7ad4789c19ea0c0208613400af30f1e3bd7fb481", + "refreshTokenHash": "f4c32cfb6450ca7ad9209efe58b3c26dae45a708c6820edd022df31659255850", + "expiresIn": 604800, + "scope": "profile", + "tokenType": "Bearer", + "codeChallenge": "", + "codeIsUsed": true, + "codeExpireIn": 0 + }, + { + "owner": "admin", + "name": "b3bc9cc8-ebe9-4be5-9f1b-439120a263d7", + "createdTime": "2025-09-20T10:48:20Z", + "application": "app-built-in", + "organization": "built-in", + "user": "admin", + "code": "3d4550d03ef798879df7", + "accessToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImNlcnQtYnVpbHQtaW4iLCJ0eXAiOiJKV1QifQ.eyJvd25lciI6ImJ1aWx0LWluIiwibmFtZSI6ImFkbWluIiwiY3JlYXRlZFRpbWUiOiIyMDI1LTA5LTIwVDEwOjQ3OjE3WiIsInVwZGF0ZWRUaW1lIjoiIiwiZGVsZXRlZFRpbWUiOiIiLCJpZCI6IjFlM2I0ZWU1LTcxNjQtNDdjNC1hNDIxLWEyZmY0OTM4Yzc2NSIsInR5cGUiOiJub3JtYWwtdXNlciIsInBhc3N3b3JkIjoiIiwicGFzc3dvcmRTYWx0IjoiIiwicGFzc3dvcmRUeXBlIjoicGxhaW4iLCJkaXNwbGF5TmFtZSI6IkFkbWluIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4ub3JnL2ltZy9jYXNiaW4uc3ZnIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6IiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxMjM0NTY3ODkxMCIsImNvdW50cnlDb2RlIjoiVVMiLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IkV4YW1wbGUgSW5jLiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjoyMDAwLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjp0cnVlLCJpc0ZvcmJpZGRlbiI6ZmFsc2UsImlzRGVsZXRlZCI6ZmFsc2UsInNpZ251cEFwcGxpY2F0aW9uIjoiYXBwLWJ1aWx0LWluIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIxMjcuMC4wLjEiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoiYWNjZXNzLXRva2VuIiwidGFnIjoic3RhZmYiLCJzY29wZSI6InByb2ZpbGUiLCJhenAiOiIxZDFlYjNjODkxZmE4ZmFhN2Q2MyIsImlzcyI6Imh0dHA6Ly8xNzIuMzAuMzQuMTg0OjgwMDQiLCJzdWIiOiIxZTNiNGVlNS03MTY0LTQ3YzQtYTQyMS1hMmZmNDkzOGM3NjUiLCJhdWQiOlsiMWQxZWIzYzg5MWZhOGZhYTdkNjMiXSwiZXhwIjoxNzU4OTcwMTAwLCJuYmYiOjE3NTgzNjUzMDAsImlhdCI6MTc1ODM2NTMwMCwianRpIjoiYWRtaW4vYjNiYzljYzgtZWJlOS00YmU1LTlmMWItNDM5MTIwYTI2M2Q3In0.GD4vk_rKUZ_bgNcgombRXVfoHNQE0KKifFZ0jvlGN7Se_OeJOkLdhJmPnR9LYgAr4hjZnqW90IL-ADJYcWswSS0bqk-D6so5srbDjxWNTa5EIxVOfG9JLBvGJl7spjvwLj84OIQNrtEOdL-4iHGcnK5bxMLoqvYApWWMZjcA99_tlibV4EBk3ajFMnGQAzrl-GhXvsglK0mk6DRWPJuzvHwRu3PvAUBegtBr5guT2WUC1VCS_FSxiwpdHcKAcqe-zArLRH7w84gs9IiR6-5Mqvx2QDO1c4yYH9DqTDplGoqK6Ln4KiIjO5MHu78zG_Mv4ywY-t0-qolZS0EnQ5JiJarZANbsI9SGIj7z_M5HhDYOYtcPvDl5DTq-gFOwyq0F7YJ2VcT9_pPKVm71nZAAkR9D0UocGCu_AHQAdvBK_3gwUYkeotITTGPj4M3U-HLoZwyy54lPjscPpLxaS_HMgeCe_GZSErOvGLV_s9cLJL3IJ5gXo5gc84DQHID-UkmLTAoj7wRwmr64STtGCKjsellJI0Jf62g4TDhOVYerd8l1K5oa520RB-gQ_PkV0nyyPIpVYpzCbByBDPxvjFmVLFgKE1NnYAeoAE-1AJbqH3E2sh9hps9oiYMWBCnym_1eL515_spRRJlxJlGCEETyhTUAYh_RrrMXjEit77P1GIE", + "refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJvd25lciI6ImJ1aWx0LWluIiwibmFtZSI6ImFkbWluIiwiY3JlYXRlZFRpbWUiOiIyMDI1LTA5LTIwVDEwOjQ3OjE3WiIsInVwZGF0ZWRUaW1lIjoiIiwiZGVsZXRlZFRpbWUiOiIiLCJpZCI6IjFlM2I0ZWU1LTcxNjQtNDdjNC1hNDIxLWEyZmY0OTM4Yzc2NSIsInR5cGUiOiJub3JtYWwtdXNlciIsInBhc3N3b3JkIjoiIiwicGFzc3dvcmRTYWx0IjoiIiwicGFzc3dvcmRUeXBlIjoicGxhaW4iLCJkaXNwbGF5TmFtZSI6IkFkbWluIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4ub3JnL2ltZy9jYXNiaW4uc3ZnIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6IiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxMjM0NTY3ODkxMCIsImNvdW50cnlDb2RlIjoiVVMiLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IkV4YW1wbGUgSW5jLiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjoyMDAwLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjp0cnVlLCJpc0ZvcmJpZGRlbiI6ZmFsc2UsImlzRGVsZXRlZCI6ZmFsc2UsInNpZ251cEFwcGxpY2F0aW9uIjoiYXBwLWJ1aWx0LWluIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIxMjcuMC4wLjEiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoicmVmcmVzaC10b2tlbiIsInRhZyI6InN0YWZmIiwic2NvcGUiOiJwcm9maWxlIiwiYXpwIjoiMWQxZWIzYzg5MWZhOGZhYTdkNjMiLCJpc3MiOiJodHRwOi8vMTcyLjMwLjM0LjE4NDo4MDA0Iiwic3ViIjoiMWUzYjRlZTUtNzE2NC00N2M0LWE0MjEtYTJmZjQ5MzhjNzY1IiwiYXVkIjpbIjFkMWViM2M4OTFmYThmYWE3ZDYzIl0sImV4cCI6MTc1ODk3MDEwMCwibmJmIjoxNzU4MzY1MzAwLCJpYXQiOjE3NTgzNjUzMDAsImp0aSI6ImFkbWluL2IzYmM5Y2M4LWViZTktNGJlNS05ZjFiLTQzOTEyMGEyNjNkNyJ9.NJmBGdkB_B8g6ETE-w3s_X68rmy0xQ3V6u6117nZzkMlyhGrQLWNvzBnsS-IpqDpF-AlZs8_5RXbqqE8UjBQQF4Bzx4iVX9uQU5aq-3V2-pfSj_NJC8vUCMWT4m8PW397ca0YoPj9O5CbW_zLhakwHrYCFl5KiWbUeCymiJXi1ga3Bb9F0HfcGs2bQzLaDf3b9QyKcnymMpPAIMKGJtT57PUvSiVkSKFbunG3tXlczGzRG98lKamZ5NLS1pJMCeYt3Q2_IfHk0VsfOz--0SLbEzf1k-NtPMVMBWc95BSAoLwbCzCQAaI8Yt5dkVqVkSVu3xlpHOGYJoQHONxiiPfu9apy1gGlbctFASbOUUlnSliuQa_dBgRfQhPOy44Jbe_sL-jPYjLqdNU8R4eOsoKrjJTx55uSREDw_jdZItrhz_c2a62JKJLTW3GauYUiFNTCx351wRtorrNAa7yQhsP6iKPNLYKQpgtiwRMcMl5uafYqfYCx5WjUmPnh_Dh2YfTG6xZRI9bon-HOTiX3LGqox4lsCKE7xw8fORmFfiJoQHZMT1oZQxhUYOnNaDol2yU1ItKBdDU2OYXJO8CTWx2Pf-3RkhCAJ1GPeGmWb-5fBcTwdjZpUEAcripw3KuAUHtBcj6bh-QJBuMN6Mq_oRMKmj0a2TNaxjcBxOynxrvLB8", + "accessTokenHash": "e8ca10541c424511e14bcb78df856404c90c8214eecb028b6f7a2d397bc17959", + "refreshTokenHash": "3169b450f72be004ea22b63ef669e242fc7eaac1366a1b66bca3f3d15be5e7ab", + "expiresIn": 604800, + "scope": "profile", + "tokenType": "Bearer", + "codeChallenge": "", + "codeIsUsed": true, + "codeExpireIn": 0 + }, + { + "owner": "admin", + "name": "bf581cf2-8eeb-41c0-aee2-a9a395725af5", + "createdTime": "2025-09-20T10:47:51Z", + "application": "app-built-in", + "organization": "built-in", + "user": "admin", + "code": "41f84c4861e1d0024daf", + "accessToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImNlcnQtYnVpbHQtaW4iLCJ0eXAiOiJKV1QifQ.eyJvd25lciI6ImJ1aWx0LWluIiwibmFtZSI6ImFkbWluIiwiY3JlYXRlZFRpbWUiOiIyMDI1LTA5LTIwVDEwOjQ3OjE3WiIsInVwZGF0ZWRUaW1lIjoiIiwiZGVsZXRlZFRpbWUiOiIiLCJpZCI6IjFlM2I0ZWU1LTcxNjQtNDdjNC1hNDIxLWEyZmY0OTM4Yzc2NSIsInR5cGUiOiJub3JtYWwtdXNlciIsInBhc3N3b3JkIjoiIiwicGFzc3dvcmRTYWx0IjoiIiwicGFzc3dvcmRUeXBlIjoicGxhaW4iLCJkaXNwbGF5TmFtZSI6IkFkbWluIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4ub3JnL2ltZy9jYXNiaW4uc3ZnIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6IiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxMjM0NTY3ODkxMCIsImNvdW50cnlDb2RlIjoiVVMiLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IkV4YW1wbGUgSW5jLiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjoyMDAwLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjp0cnVlLCJpc0ZvcmJpZGRlbiI6ZmFsc2UsImlzRGVsZXRlZCI6ZmFsc2UsInNpZ251cEFwcGxpY2F0aW9uIjoiYXBwLWJ1aWx0LWluIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIxMjcuMC4wLjEiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoiYWNjZXNzLXRva2VuIiwidGFnIjoic3RhZmYiLCJzY29wZSI6InByb2ZpbGUiLCJhenAiOiIxZDFlYjNjODkxZmE4ZmFhN2Q2MyIsImlzcyI6Imh0dHA6Ly8xNzIuMzAuMzQuMTg0OjgwMDQiLCJzdWIiOiIxZTNiNGVlNS03MTY0LTQ3YzQtYTQyMS1hMmZmNDkzOGM3NjUiLCJhdWQiOlsiMWQxZWIzYzg5MWZhOGZhYTdkNjMiXSwiZXhwIjoxNzU4OTcwMDcxLCJuYmYiOjE3NTgzNjUyNzEsImlhdCI6MTc1ODM2NTI3MSwianRpIjoiYWRtaW4vYmY1ODFjZjItOGVlYi00MWMwLWFlZTItYTlhMzk1NzI1YWY1In0.ysggMjMtH9BhmwQt87ds-9zCRNZqYLVcUPZuLU0XSBSOyz2pBWfcFHAwb_e5D2VGZx5AAQCOkOdQNASi6DbHMcA3eidejl4e6LsxxoEHQiumpLMcAFuyxLLlgnSrWbsBHAGZr5nvCnlUycX0Ioyt3Z-JRRrHnxg_7fr6ZRG-1-xyau8YeLlVt4j46Gc57dtoDQtv6R6_XFSfIrxBzQr6TITTtC_YVcKA3N_SvwlAuaulldEGWs_oBt4aYd_xyY8uZT-AsTLrf2WmvcDK4tN1gt7MAhPiyAZnsEoZA40T4495cAjaAXb0bPrON6v326A_irjqIayLiZvz3I9TYIId7tZrZG_0h17S9ebr4uK2bFGKAh5uRgrBI_x6rptctYs7IuxrwKRaoXklP530t1Lb7-aZRjKkG6Xx0C9XBGgOJmwx0nnZ0hxJsJ74J_8jJA9GepiItLzUvJNYQupBLQyVQLsdkCF7chiJtcZRNEIP8CtudEUcFT8y6fti_5XmIukCw_ftI5sAS8c7g-cm9Pwn9-6lvHwUjX3mvfccodnGsY2U7-6lj3u5LcTxcrvQ5Yc30-x-whaD9vzuMQ1Rf4UUCU_xFIq2nWyPzME6-XqieLY5TaxKMBqfHtG4fDNGeaYTFvx6to1ZD-v6LMUNJW-lGbZ4T9Ug2OpxV4mzL0lkHDY", + "refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJvd25lciI6ImJ1aWx0LWluIiwibmFtZSI6ImFkbWluIiwiY3JlYXRlZFRpbWUiOiIyMDI1LTA5LTIwVDEwOjQ3OjE3WiIsInVwZGF0ZWRUaW1lIjoiIiwiZGVsZXRlZFRpbWUiOiIiLCJpZCI6IjFlM2I0ZWU1LTcxNjQtNDdjNC1hNDIxLWEyZmY0OTM4Yzc2NSIsInR5cGUiOiJub3JtYWwtdXNlciIsInBhc3N3b3JkIjoiIiwicGFzc3dvcmRTYWx0IjoiIiwicGFzc3dvcmRUeXBlIjoicGxhaW4iLCJkaXNwbGF5TmFtZSI6IkFkbWluIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4ub3JnL2ltZy9jYXNiaW4uc3ZnIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6IiIsImVtYWlsIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJlbWFpbFZlcmlmaWVkIjpmYWxzZSwicGhvbmUiOiIxMjM0NTY3ODkxMCIsImNvdW50cnlDb2RlIjoiVVMiLCJyZWdpb24iOiIiLCJsb2NhdGlvbiI6IiIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IkV4YW1wbGUgSW5jLiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoiIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjoyMDAwLCJrYXJtYSI6MCwicmFua2luZyI6MSwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOmZhbHNlLCJpc0FkbWluIjp0cnVlLCJpc0ZvcmJpZGRlbiI6ZmFsc2UsImlzRGVsZXRlZCI6ZmFsc2UsInNpZ251cEFwcGxpY2F0aW9uIjoiYXBwLWJ1aWx0LWluIiwiaGFzaCI6IiIsInByZUhhc2giOiIiLCJhY2Nlc3NLZXkiOiIiLCJhY2Nlc3NTZWNyZXQiOiIiLCJnaXRodWIiOiIiLCJnb29nbGUiOiIiLCJxcSI6IiIsIndlY2hhdCI6IiIsImZhY2Vib29rIjoiIiwiZGluZ3RhbGsiOiIiLCJ3ZWlibyI6IiIsImdpdGVlIjoiIiwibGlua2VkaW4iOiIiLCJ3ZWNvbSI6IiIsImxhcmsiOiIiLCJnaXRsYWIiOiIiLCJjcmVhdGVkSXAiOiIxMjcuMC4wLjEiLCJsYXN0U2lnbmluVGltZSI6IiIsImxhc3RTaWduaW5JcCI6IiIsInByZWZlcnJlZE1mYVR5cGUiOiIiLCJyZWNvdmVyeUNvZGVzIjpudWxsLCJ0b3RwU2VjcmV0IjoiIiwibWZhUGhvbmVFbmFibGVkIjpmYWxzZSwibWZhRW1haWxFbmFibGVkIjpmYWxzZSwibGRhcCI6IiIsInByb3BlcnRpZXMiOnt9LCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXSwiZ3JvdXBzIjpbXSwibGFzdFNpZ25pbldyb25nVGltZSI6IiIsInNpZ25pbldyb25nVGltZXMiOjAsIm1hbmFnZWRBY2NvdW50cyI6bnVsbCwidG9rZW5UeXBlIjoicmVmcmVzaC10b2tlbiIsInRhZyI6InN0YWZmIiwic2NvcGUiOiJwcm9maWxlIiwiYXpwIjoiMWQxZWIzYzg5MWZhOGZhYTdkNjMiLCJpc3MiOiJodHRwOi8vMTcyLjMwLjM0LjE4NDo4MDA0Iiwic3ViIjoiMWUzYjRlZTUtNzE2NC00N2M0LWE0MjEtYTJmZjQ5MzhjNzY1IiwiYXVkIjpbIjFkMWViM2M4OTFmYThmYWE3ZDYzIl0sImV4cCI6MTc1ODk3MDA3MSwibmJmIjoxNzU4MzY1MjcxLCJpYXQiOjE3NTgzNjUyNzEsImp0aSI6ImFkbWluL2JmNTgxY2YyLThlZWItNDFjMC1hZWUyLWE5YTM5NTcyNWFmNSJ9.FwFmS1F0j9OoVguQiPghg4JsrwM7z_RI2o6hiBBxbL0OTG1uCtOtoHjlB7e8naoGZrfs8GoC7Q_GWjkVBv_uViWmMoOr9-LLjJb96UdhwcDW1jaeTx-ZoFqOr3xuoY9B44TKiXyP69IEI7fCn6_xDPSRlJNLXSE7UtIL3p_eEEYcI8GNhhSYwpQzSYbQLiFmU-du9Ic7kTscALQb6MRwF6duyqOtsjLuNnqX7fbauH3wwUqbP57PN0usniuIgpW5XPySBtm_688WCOqLipptSrQ12NZejTA2H8P3FZvZUj5VS7snN-1bQdX06B4rYNIU4bLZQd5Q-TfZEWX-JIYobhv8nyqBVcjUDYxl57cFzKVKPiXibrfp0Z5qHiBDZgRAvylRkFUsGgI1GCSXNBqJjVQw1eyhTXn3dlQpvMMZ7zqIWFDILtIV_9pFHH04XbHT7ogprKzXgHoxznFKnytM4BrloH-XNRGr9Ka6Mk-uVyVgMq3hS5Yk2wjQVnWbN8oQx4GwuxqMd3UqfY-2Ba4OxJsvWuW2PikW284q-QmcmphX75nuLlaP104WbBG7S1A9_WYdI37IPGAA7wLwBoLt2y1sx6pYRUsrqj9NG5CCWtgnMAWkkFXWAwA3_ipgcfEWDB7VzlGiqvsPFy54VAHJ1oZUvnmE2go5Dx7RIM1VHGk", + "accessTokenHash": "f2e809e71a22b29909f9f1c6e37133ee9a4d38c56f6646cfc9b671aad8ffadc7", + "refreshTokenHash": "5dea79cefe422c3e696e4f7245703b6c1e160cc1631787b5dddb206c35c2024b", + "expiresIn": 604800, + "scope": "profile", + "tokenType": "Bearer", + "codeChallenge": "", + "codeIsUsed": true, + "codeExpireIn": 0 + } + ], + "webhooks": [], + "groups": [], + "adapters": [ + { + "owner": "built-in", + "name": "api-adapter-built-in", + "createdTime": "2025-09-20T10:47:18Z", + "table": "casbin_api_rule", + "useSameDb": true, + "type": "", + "databaseType": "", + "host": "", + "port": 0, + "user": "", + "password": "", + "database": "" + }, + { + "owner": "built-in", + "name": "user-adapter-built-in", + "createdTime": "2025-09-20T10:47:18Z", + "table": "casbin_user_rule", + "useSameDb": true, + "type": "", + "databaseType": "", + "host": "", + "port": 0, + "user": "", + "password": "", + "database": "" + } + ], + "enforcers": [ + { + "owner": "built-in", + "name": "api-enforcer-built-in", + "createdTime": "2025-09-20T10:47:18Z", + "updatedTime": "2025-09-20 10:47:18", + "displayName": "API Enforcer", + "description": "", + "model": "built-in/api-model-built-in", + "adapter": "built-in/api-adapter-built-in", + "modelCfg": null + }, + { + "owner": "built-in", + "name": "user-enforcer-built-in", + "createdTime": "2025-09-20T10:47:18Z", + "updatedTime": "2025-09-20 10:47:18", + "displayName": "User Enforcer", + "description": "", + "model": "built-in/user-model-built-in", + "adapter": "built-in/user-adapter-built-in", + "modelCfg": null + } + ], + "plans": [], + "pricings": [], + "invitations": [], + "records": [ + { + "id": 26, + "owner": "built-in", + "name": "2284aa5d-ad34-402a-a73b-d97a4819409b", + "createdTime": "2025-09-20T10:59:43Z", + "organization": "built-in", + "clientIp": "10.10.125.231", + "user": "admin", + "method": "POST", + "requestUri": "/api/login", + "action": "login", + "language": "zh", + "object": "{\"application\":\"app-built-in\",\"organization\":\"built-in\",\"username\":\"admin\",\"password\":\"***\",\"autoSignin\":true,\"language\":\"\",\"signinMethod\":\"Password\",\"type\":\"login\"}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 25, + "owner": "built-in", + "name": "420a7908-d3fd-4630-aa30-f9afa20260d2", + "createdTime": "2025-09-20T10:58:45Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-role?id=example-org/example-role", + "action": "update-role", + "language": "zh", + "object": "{\"owner\":\"example-org\",\"name\":\"example-role\",\"createdTime\":\"2025-09-20T18:58:05+08:00\",\"displayName\":\"示例角色\",\"description\":\"\",\"users\":[\"example-org/example-user\"],\"groups\":[],\"roles\":[],\"domains\":[],\"isEnabled\":true}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 24, + "owner": "built-in", + "name": "97faa108-d69f-449c-a2fa-c76e90a5fbd5", + "createdTime": "2025-09-20T10:58:41Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-role?id=example-org/example-role", + "action": "update-role", + "language": "zh", + "object": "{\"owner\":\"example-org\",\"name\":\"example-role\",\"createdTime\":\"2025-09-20T18:58:05+08:00\",\"displayName\":\"示例角色\",\"description\":\"\",\"users\":[\"example-org/example-user\"],\"groups\":[],\"roles\":[],\"domains\":[],\"isEnabled\":true}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 23, + "owner": "built-in", + "name": "c54b07c2-b470-40d7-a542-3cf234b10e75", + "createdTime": "2025-09-20T10:58:33Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-role?id=built-in/example-role", + "action": "update-role", + "language": "zh", + "object": "{\"owner\":\"example-org\",\"name\":\"example-role\",\"createdTime\":\"2025-09-20T18:58:05+08:00\",\"displayName\":\"示例角色\",\"description\":\"\",\"users\":[],\"groups\":[],\"roles\":[],\"domains\":[],\"isEnabled\":true}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 22, + "owner": "built-in", + "name": "e51bbeba-bdf3-4ef4-9130-b3c29007e5f2", + "createdTime": "2025-09-20T10:58:31Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-role?id=built-in/role_s52ltl", + "action": "update-role", + "language": "zh", + "object": "{\"owner\":\"example-org\",\"name\":\"example-role\",\"createdTime\":\"2025-09-20T18:58:05+08:00\",\"displayName\":\"示例角色\",\"description\":\"\",\"users\":[],\"groups\":[],\"roles\":[],\"domains\":[],\"isEnabled\":true}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 21, + "owner": "built-in", + "name": "76c504fe-ef57-47e2-9b38-f37bc9254fdb", + "createdTime": "2025-09-20T10:58:05Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/add-role", + "action": "add-role", + "language": "zh", + "object": "{\"owner\":\"built-in\",\"name\":\"role_s52ltl\",\"createdTime\":\"2025-09-20T18:58:05+08:00\",\"displayName\":\"New Role - s52ltl\",\"users\":[],\"groups\":[],\"roles\":[],\"domains\":[],\"isEnabled\":true}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 20, + "owner": "built-in", + "name": "d8f347d3-880c-4991-8094-b61c24aaeefd", + "createdTime": "2025-09-20T10:57:13Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/add-role", + "action": "add-role", + "language": "zh", + "object": "{\"owner\":\"built-in\",\"name\":\"role_m06bnm\",\"createdTime\":\"2025-09-20T18:57:13+08:00\",\"displayName\":\"New Role - m06bnm\",\"users\":[],\"groups\":[],\"roles\":[],\"domains\":[],\"isEnabled\":true}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 19, + "owner": "built-in", + "name": "00355afa-dbab-48a5-a3b1-fd6e96e834f6", + "createdTime": "2025-09-20T10:57:09Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-user?id=example-org/example-user", + "action": "update-user", + "language": "zh", + "object": "{\"owner\":\"example-org\",\"name\":\"example-user\",\"createdTime\":\"2025-09-20T10:56:21Z\",\"updatedTime\":\"\",\"deletedTime\":\"\",\"id\":\"3d7cca2b-8da9-41bf-b535-6c9f83d731db\",\"externalId\":\"\",\"type\":\"normal-user\",\"password\":\"***\",\"passwordSalt\":\"\",\"passwordType\":\"plain\",\"displayName\":\"示例用户\",\"firstName\":\"\",\"lastName\":\"\",\"avatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"avatarType\":\"\",\"permanentAvatar\":\"\",\"email\":\"\",\"emailVerified\":false,\"phone\":\"18888888888\",\"countryCode\":\"CN\",\"region\":\"\",\"location\":\"\",\"address\":[],\"affiliation\":\"\",\"title\":\"\",\"idCardType\":\"\",\"idCard\":\"\",\"homepage\":\"\",\"bio\":\"\",\"tag\":\"\",\"language\":\"\",\"gender\":\"\",\"birthday\":\"\",\"education\":\"\",\"score\":0,\"karma\":0,\"ranking\":1,\"balance\":0,\"currency\":\"\",\"isDefaultAvatar\":false,\"isOnline\":false,\"isAdmin\":false,\"isForbidden\":false,\"isDeleted\":false,\"signupApplication\":\"example-app\",\"hash\":\"\",\"preHash\":\"\",\"accessKey\":\"\",\"accessSecret\":\"\",\"accessToken\":\"\",\"createdIp\":\"\",\"lastSigninTime\":\"\",\"lastSigninIp\":\"\",\"github\":\"\",\"google\":\"\",\"qq\":\"\",\"wechat\":\"\",\"facebook\":\"\",\"dingtalk\":\"\",\"weibo\":\"\",\"gitee\":\"\",\"linkedin\":\"\",\"wecom\":\"\",\"lark\":\"\",\"gitlab\":\"\",\"adfs\":\"\",\"baidu\":\"\",\"alipay\":\"\",\"casdoor\":\"\",\"infoflow\":\"\",\"apple\":\"\",\"azuread\":\"\",\"azureadb2c\":\"\",\"slack\":\"\",\"steam\":\"\",\"bilibili\":\"\",\"okta\":\"\",\"douyin\":\"\",\"kwai\":\"\",\"line\":\"\",\"amazon\":\"\",\"auth0\":\"\",\"battlenet\":\"\",\"bitbucket\":\"\",\"box\":\"\",\"cloudfoundry\":\"\",\"dailymotion\":\"\",\"deezer\":\"\",\"digitalocean\":\"\",\"discord\":\"\",\"dropbox\":\"\",\"eveonline\":\"\",\"fitbit\":\"\",\"gitea\":\"\",\"heroku\":\"\",\"influxcloud\":\"\",\"instagram\":\"\",\"intercom\":\"\",\"kakao\":\"\",\"lastfm\":\"\",\"mailru\":\"\",\"meetup\":\"\",\"microsoftonline\":\"\",\"naver\":\"\",\"nextcloud\":\"\",\"onedrive\":\"\",\"oura\":\"\",\"patreon\":\"\",\"paypal\":\"\",\"salesforce\":\"\",\"shopify\":\"\",\"soundcloud\":\"\",\"spotify\":\"\",\"strava\":\"\",\"stripe\":\"\",\"tiktok\":\"\",\"tumblr\":\"\",\"twitch\":\"\",\"twitter\":\"\",\"typetalk\":\"\",\"uber\":\"\",\"vk\":\"\",\"wepay\":\"\",\"xero\":\"\",\"yahoo\":\"\",\"yammer\":\"\",\"yandex\":\"\",\"zoom\":\"\",\"metamask\":\"\",\"web3onboard\":\"\",\"custom\":\"\",\"webauthnCredentials\":null,\"preferredMfaType\":\"\",\"recoveryCodes\":null,\"totpSecret\":\"\",\"mfaPhoneEnabled\":false,\"mfaEmailEnabled\":false,\"multiFactorAuths\":[{\"enabled\":false,\"isPreferred\":false,\"mfaType\":\"sms\",\"mfaRememberInHours\":0},{\"enabled\":false,\"isPreferred\":false,\"mfaType\":\"email\",\"mfaRememberInHours\":0},{\"enabled\":false,\"isPreferred\":false,\"mfaType\":\"app\",\"mfaRememberInHours\":0}],\"invitation\":\"\",\"invitationCode\":\"\",\"faceIds\":null,\"ldap\":\"\",\"properties\":{},\"roles\":[],\"permissions\":[],\"groups\":[],\"lastChangePasswordTime\":\"\",\"lastSigninWrongTime\":\"\",\"signinWrongTimes\":0,\"managedAccounts\":null,\"mfaAccounts\":null,\"mfaItems\":null,\"mfaRememberDeadline\":\"\",\"needUpdatePassword\":false,\"ipWhitelist\":\"\"}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 18, + "owner": "built-in", + "name": "5a427026-bfbf-48fc-8a1e-ae8e4e573e0e", + "createdTime": "2025-09-20T10:56:34Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/login", + "action": "login", + "language": "zh", + "object": "{\"application\":\"app-built-in\",\"organization\":\"built-in\",\"username\":\"admin\",\"password\":\"***\",\"autoSignin\":true,\"language\":\"\",\"signinMethod\":\"Password\",\"type\":\"login\"}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 17, + "owner": "example-org", + "name": "7f808e0b-2a32-4b18-9cd1-97e732113c1c", + "createdTime": "2025-09-20T10:56:27Z", + "organization": "example-org", + "clientIp": "10.10.122.195", + "user": "example-user", + "method": "POST", + "requestUri": "/api/logout", + "action": "logout", + "language": "zh", + "object": "", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 16, + "owner": "example-org", + "name": "4bc172fd-f388-4423-8314-c7f9b6f6a433", + "createdTime": "2025-09-20T10:56:21Z", + "organization": "example-org", + "clientIp": "10.10.122.195", + "user": "example-user", + "method": "POST", + "requestUri": "/api/signup", + "action": "new-user", + "language": "zh", + "object": "{\"owner\":\"example-org\",\"name\":\"example-user\",\"createdTime\":\"2025-09-20T10:56:21Z\",\"updatedTime\":\"\",\"deletedTime\":\"\",\"id\":\"3d7cca2b-8da9-41bf-b535-6c9f83d731db\",\"externalId\":\"\",\"type\":\"normal-user\",\"password\":\"***\",\"passwordSalt\":\"\",\"passwordType\":\"plain\",\"displayName\":\"示例用户\",\"firstName\":\"\",\"lastName\":\"\",\"avatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"avatarType\":\"\",\"permanentAvatar\":\"\",\"email\":\"\",\"emailVerified\":false,\"phone\":\"18888888888\",\"countryCode\":\"CN\",\"region\":\"\",\"location\":\"\",\"address\":[],\"affiliation\":\"\",\"title\":\"\",\"idCardType\":\"\",\"idCard\":\"\",\"homepage\":\"\",\"bio\":\"\",\"tag\":\"\",\"language\":\"\",\"gender\":\"\",\"birthday\":\"\",\"education\":\"\",\"score\":0,\"karma\":0,\"ranking\":1,\"balance\":0,\"currency\":\"\",\"isDefaultAvatar\":false,\"isOnline\":false,\"isAdmin\":false,\"isForbidden\":false,\"isDeleted\":false,\"signupApplication\":\"example-app\",\"hash\":\"\",\"preHash\":\"\",\"accessKey\":\"\",\"accessSecret\":\"\",\"accessToken\":\"\",\"createdIp\":\"\",\"lastSigninTime\":\"\",\"lastSigninIp\":\"\",\"github\":\"\",\"google\":\"\",\"qq\":\"\",\"wechat\":\"\",\"facebook\":\"\",\"dingtalk\":\"\",\"weibo\":\"\",\"gitee\":\"\",\"linkedin\":\"\",\"wecom\":\"\",\"lark\":\"\",\"gitlab\":\"\",\"adfs\":\"\",\"baidu\":\"\",\"alipay\":\"\",\"casdoor\":\"\",\"infoflow\":\"\",\"apple\":\"\",\"azuread\":\"\",\"azureadb2c\":\"\",\"slack\":\"\",\"steam\":\"\",\"bilibili\":\"\",\"okta\":\"\",\"douyin\":\"\",\"kwai\":\"\",\"line\":\"\",\"amazon\":\"\",\"auth0\":\"\",\"battlenet\":\"\",\"bitbucket\":\"\",\"box\":\"\",\"cloudfoundry\":\"\",\"dailymotion\":\"\",\"deezer\":\"\",\"digitalocean\":\"\",\"discord\":\"\",\"dropbox\":\"\",\"eveonline\":\"\",\"fitbit\":\"\",\"gitea\":\"\",\"heroku\":\"\",\"influxcloud\":\"\",\"instagram\":\"\",\"intercom\":\"\",\"kakao\":\"\",\"lastfm\":\"\",\"mailru\":\"\",\"meetup\":\"\",\"microsoftonline\":\"\",\"naver\":\"\",\"nextcloud\":\"\",\"onedrive\":\"\",\"oura\":\"\",\"patreon\":\"\",\"paypal\":\"\",\"salesforce\":\"\",\"shopify\":\"\",\"soundcloud\":\"\",\"spotify\":\"\",\"strava\":\"\",\"stripe\":\"\",\"tiktok\":\"\",\"tumblr\":\"\",\"twitch\":\"\",\"twitter\":\"\",\"typetalk\":\"\",\"uber\":\"\",\"vk\":\"\",\"wepay\":\"\",\"xero\":\"\",\"yahoo\":\"\",\"yammer\":\"\",\"yandex\":\"\",\"zoom\":\"\",\"metamask\":\"\",\"web3onboard\":\"\",\"custom\":\"\",\"webauthnCredentials\":null,\"preferredMfaType\":\"\",\"recoveryCodes\":null,\"totpSecret\":\"\",\"mfaPhoneEnabled\":false,\"mfaEmailEnabled\":false,\"invitation\":\"\",\"invitationCode\":\"\",\"faceIds\":null,\"ldap\":\"\",\"properties\":{},\"roles\":null,\"permissions\":null,\"groups\":null,\"lastChangePasswordTime\":\"\",\"lastSigninWrongTime\":\"\",\"signinWrongTimes\":0,\"managedAccounts\":null,\"mfaAccounts\":null,\"mfaItems\":null,\"mfaRememberDeadline\":\"\",\"needUpdatePassword\":false,\"ipWhitelist\":\"\"}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 0, + "isTriggered": true + }, + { + "id": 15, + "owner": "example-org", + "name": "4bc172fd-f388-4423-8314-c7f9b6f6a433", + "createdTime": "2025-09-20T10:56:21Z", + "organization": "example-org", + "clientIp": "10.10.122.195", + "user": "example-user", + "method": "POST", + "requestUri": "/api/signup", + "action": "signup", + "language": "zh", + "object": "{\"application\":\"example-app\",\"organization\":\"example-org\",\"username\":\"example-user\",\"name\":\"示例用户\",\"password\":\"***\",\"confirm\":\"123456\",\"countryCode\":\"CN\",\"phone\":\"18888888888\",\"agreement\":true,\"plan\":null,\"pricing\":null}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 14, + "owner": "", + "name": "745e0e6a-5194-4d79-a3cd-90551104fd3c", + "createdTime": "2025-09-20T10:55:17Z", + "organization": "", + "clientIp": "10.10.122.195", + "user": "", + "method": "POST", + "requestUri": "/api/login", + "action": "login", + "language": "zh", + "object": "{\"application\":\"example-app\",\"organization\":\"example-org\",\"username\":\"admin\",\"password\":\"***\",\"autoSignin\":true,\"language\":\"\",\"signinMethod\":\"Password\",\"type\":\"login\"}", + "response": "{status:\"error\", msg:\"用户: example-org/admin不存在\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 13, + "owner": "built-in", + "name": "cb140d8a-27a4-4a60-8185-e60db48ddbfb", + "createdTime": "2025-09-20T10:54:57Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/logout", + "action": "logout", + "language": "zh", + "object": "", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 12, + "owner": "built-in", + "name": "deb63bd0-cfb4-4ddb-80da-0878359aeee9", + "createdTime": "2025-09-20T10:54:42Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/add-user", + "action": "add-user", + "language": "zh", + "object": "{\"owner\":\"built-in\",\"name\":\"user_wght4c\",\"createdTime\":\"2025-09-20T18:54:42+08:00\",\"type\":\"normal-user\",\"password\":\"***\",\"passwordSalt\":\"\",\"displayName\":\"New User - wght4c\",\"avatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"email\":\"wght4c@example.com\",\"phone\":\"30037413383\",\"countryCode\":\"US\",\"address\":[],\"groups\":[],\"affiliation\":\"Example Inc.\",\"tag\":\"staff\",\"region\":\"\",\"isAdmin\":true,\"IsForbidden\":false,\"score\":2000,\"isDeleted\":false,\"properties\":{},\"signupApplication\":\"\"}", + "response": "{status:\"error\", msg:\"目前,向'built-in'组织添加新用户的功能已禁用。请注意:'built-in'组织中的所有用户均为Casdoor的全局管理员。请参阅文档:https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself。如果您仍希望为built-in组织创建用户,请转到该组织的设置页面并启用“特权同意”选项。\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 11, + "owner": "built-in", + "name": "e56c3765-842f-4d9e-adda-9a526d99aed9", + "createdTime": "2025-09-20T10:54:37Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/add-user", + "action": "add-user", + "language": "zh", + "object": "{\"owner\":\"built-in\",\"name\":\"user_1ub2fs\",\"createdTime\":\"2025-09-20T18:54:37+08:00\",\"type\":\"normal-user\",\"password\":\"***\",\"passwordSalt\":\"\",\"displayName\":\"New User - 1ub2fs\",\"avatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"email\":\"1ub2fs@example.com\",\"phone\":\"23130608354\",\"countryCode\":\"US\",\"address\":[],\"groups\":[],\"affiliation\":\"Example Inc.\",\"tag\":\"staff\",\"region\":\"\",\"isAdmin\":true,\"IsForbidden\":false,\"score\":2000,\"isDeleted\":false,\"properties\":{},\"signupApplication\":\"\"}", + "response": "{status:\"error\", msg:\"目前,向'built-in'组织添加新用户的功能已禁用。请注意:'built-in'组织中的所有用户均为Casdoor的全局管理员。请参阅文档:https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself。如果您仍希望为built-in组织创建用户,请转到该组织的设置页面并启用“特权同意”选项。\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 10, + "owner": "built-in", + "name": "9bcd72a5-d4dc-47ab-b300-d7b984507762", + "createdTime": "2025-09-20T10:54:29Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-organization?id=admin/example-org", + "action": "update-organization", + "language": "zh", + "object": "{\"owner\":\"admin\",\"name\":\"example-org\",\"createdTime\":\"2025-09-20T18:48:24+08:00\",\"displayName\":\"示例组织\",\"websiteUrl\":\"https://door.casdoor.com\",\"logo\":\"\",\"logoDark\":\"\",\"favicon\":\"https://cdn.casbin.org/img/favicon.png\",\"hasPrivilegeConsent\":false,\"passwordType\":\"plain\",\"passwordSalt\":\"\",\"passwordOptions\":[\"AtLeast6\"],\"passwordObfuscatorType\":\"Plain\",\"passwordObfuscatorKey\":\"\",\"passwordExpireDays\":0,\"countryCodes\":[\"CN\"],\"defaultAvatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"defaultApplication\":\"example-app\",\"userTypes\":null,\"tags\":[],\"languages\":[\"en\",\"es\",\"fr\",\"de\",\"zh\",\"id\",\"ja\",\"ko\",\"ru\",\"vi\",\"pt\",\"it\",\"ms\",\"tr\",\"ar\",\"he\",\"nl\",\"pl\",\"fi\",\"sv\",\"uk\",\"kk\",\"fa\",\"cs\",\"sk\",\"az\"],\"themeData\":null,\"masterPassword\":\"\",\"defaultPassword\":\"\",\"masterVerificationCode\":\"\",\"ipWhitelist\":\"\",\"initScore\":0,\"enableSoftDeletion\":false,\"isProfilePublic\":true,\"useEmailAsUsername\":false,\"enableTour\":true,\"disableSignin\":false,\"ipRestriction\":\"\",\"navItems\":null,\"widgetItems\":null,\"mfaItems\":null,\"mfaRememberInHours\":12,\"accountItems\":[{\"name\":\"Organization\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"ID\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Display name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Avatar\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"User type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Password\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Email\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Phone\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Country code\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Country/Region\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Location\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Address\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Affiliation\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Title\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"ID card type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"ID card\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"ID card info\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Homepage\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Bio\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Tag\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Language\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Gender\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Birthday\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Education\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Score\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Karma\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Ranking\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Signup application\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"API key\",\"visible\":false,\"viewRule\":\"\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Groups\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Roles\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Permissions\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"3rd-party logins\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Properties\",\"visible\":false,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is online\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is admin\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is forbidden\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is deleted\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Multi-factor authentication\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"WebAuthn credentials\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Managed accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"MFA accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"}],\"enableDarkLogo\":false}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 9, + "owner": "built-in", + "name": "17e560c6-e5a8-4f16-8f0b-8b86b39dcab9", + "createdTime": "2025-09-20T10:54:20Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-application?id=admin/example-app", + "action": "update-application", + "language": "zh", + "object": "{\"owner\":\"admin\",\"name\":\"example-app\",\"createdTime\":\"2025-09-20T18:50:08+08:00\",\"displayName\":\"示例应用\",\"logo\":\"https://cdn.casbin.org/img/casdoor-logo_1185x256.png\",\"order\":0,\"homepageUrl\":\"\",\"description\":\"\",\"organization\":\"example-org\",\"cert\":\"cert-built-in\",\"defaultGroup\":\"\",\"headerHtml\":\"\",\"enablePassword\":true,\"enableSignUp\":true,\"disableSignin\":false,\"enableSigninSession\":false,\"enableAutoSignin\":false,\"enableCodeSignin\":false,\"enableSamlCompress\":false,\"enableSamlC14n10\":false,\"enableSamlPostBinding\":false,\"useEmailAsSamlNameId\":false,\"enableWebAuthn\":false,\"enableLinkWithEmail\":false,\"orgChoiceMode\":\"\",\"samlReplyUrl\":\"\",\"providers\":[{\"owner\":\"\",\"name\":\"provider_captcha_default\",\"canSignUp\":false,\"canSignIn\":false,\"canUnlink\":false,\"countryCodes\":null,\"prompted\":false,\"signupGroup\":\"\",\"rule\":\"\",\"provider\":{\"owner\":\"admin\",\"name\":\"provider_captcha_default\",\"createdTime\":\"2025-09-20T10:47:17Z\",\"displayName\":\"Captcha Default\",\"category\":\"Captcha\",\"type\":\"Default\",\"subType\":\"\",\"method\":\"\",\"clientId\":\"\",\"clientSecret\":\"\",\"clientId2\":\"\",\"clientSecret2\":\"\",\"cert\":\"\",\"customAuthUrl\":\"\",\"customTokenUrl\":\"\",\"customUserInfoUrl\":\"\",\"customLogo\":\"\",\"scopes\":\"\",\"userMapping\":null,\"httpHeaders\":null,\"host\":\"\",\"port\":0,\"disableSsl\":false,\"title\":\"\",\"content\":\"\",\"receiver\":\"\",\"regionId\":\"\",\"signName\":\"\",\"templateCode\":\"\",\"appId\":\"\",\"endpoint\":\"\",\"intranetEndpoint\":\"\",\"domain\":\"\",\"bucket\":\"\",\"pathPrefix\":\"\",\"metadata\":\"\",\"idP\":\"\",\"issuerUrl\":\"\",\"enableSignAuthnRequest\":false,\"emailRegex\":\"\",\"providerUrl\":\"\"}}],\"signinMethods\":[{\"name\":\"Password\",\"displayName\":\"Password\",\"rule\":\"All\"}],\"signupItems\":[{\"name\":\"ID\",\"visible\":false,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"Random\"},{\"name\":\"Username\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Display name\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Password\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Confirm password\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Email\",\"visible\":false,\"required\":false,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"No verification\"},{\"name\":\"Phone\",\"visible\":true,\"required\":false,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"No verification\"},{\"name\":\"Agreement\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Signup button\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Providers\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n }\\n .provider-big-img {\\n margin-bottom: 10px;\\n }\\n \",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"small\"}],\"signinItems\":[{\"name\":\"Back button\",\"visible\":true,\"label\":\"\",\"customCss\":\".back-button {\\n top: 65px;\\n left: 15px;\\n position: absolute;\\n}\\n.back-inner-button{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Languages\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-languages {\\n top: 55px;\\n right: 5px;\\n position: absolute;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Logo\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-logo-box {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Signin methods\",\"visible\":true,\"label\":\"\",\"customCss\":\".signin-methods {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Username\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-username {}\\n.login-username-input{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Password\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-password {}\\n.login-password-input{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Agreement\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-agreement {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Forgot password?\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-forget-password {\\n display: inline-flex;\\n justify-content: space-between;\\n width: 320px;\\n margin-bottom: 25px;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Login button\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-button-box {\\n margin-bottom: 5px;\\n}\\n.login-button {\\n width: 100%;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Signup link\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-signup-link {\\n margin-bottom: 24px;\\n display: flex;\\n justify-content: end;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Providers\",\"visible\":true,\"label\":\"\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n}\\n.provider-big-img {\\n margin-bottom: 10px;\\n}\",\"placeholder\":\"\",\"rule\":\"small\",\"isCustom\":false}],\"grantTypes\":[\"authorization_code\",\"password\",\"client_credentials\",\"token\",\"id_token\",\"refresh_token\"],\"organizationObj\":{\"owner\":\"admin\",\"name\":\"built-in\",\"createdTime\":\"2025-09-20T10:47:17Z\",\"displayName\":\"Built-in Organization\",\"websiteUrl\":\"https://example.com\",\"logo\":\"\",\"logoDark\":\"\",\"favicon\":\"https://cdn.casbin.org/img/casbin/favicon.ico\",\"hasPrivilegeConsent\":false,\"passwordType\":\"plain\",\"passwordSalt\":\"\",\"passwordOptions\":[\"AtLeast6\"],\"passwordObfuscatorType\":\"\",\"passwordObfuscatorKey\":\"\",\"passwordExpireDays\":0,\"countryCodes\":[\"US\",\"ES\",\"FR\",\"DE\",\"GB\",\"CN\",\"JP\",\"KR\",\"VN\",\"ID\",\"SG\",\"IN\"],\"defaultAvatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"defaultApplication\":\"\",\"userTypes\":[],\"tags\":[],\"languages\":[\"en\",\"zh\",\"es\",\"fr\",\"de\",\"id\",\"ja\",\"ko\",\"ru\",\"vi\",\"pt\"],\"themeData\":null,\"masterPassword\":\"\",\"defaultPassword\":\"\",\"masterVerificationCode\":\"\",\"ipWhitelist\":\"\",\"initScore\":2000,\"enableSoftDeletion\":false,\"isProfilePublic\":false,\"useEmailAsUsername\":false,\"enableTour\":true,\"disableSignin\":false,\"ipRestriction\":\"\",\"navItems\":null,\"widgetItems\":null,\"mfaItems\":null,\"mfaRememberInHours\":0,\"accountItems\":[{\"name\":\"Organization\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"ID\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Display name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Avatar\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"User type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Password\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Email\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Phone\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Country code\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Country/Region\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Location\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Affiliation\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Title\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Homepage\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Bio\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Tag\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Signup application\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Roles\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Permissions\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Groups\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"3rd-party logins\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Properties\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is admin\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is forbidden\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is deleted\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Multi-factor authentication\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"WebAuthn credentials\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Managed accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"MFA accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"}]},\"certPublicKey\":\"\",\"tags\":[],\"samlAttributes\":null,\"isShared\":false,\"ipRestriction\":\"\",\"clientId\":\"e3ba6fec42cfe996121f\",\"clientSecret\":\"0c18bf2a11ffbb756ec6ce47dae9e09bdd48e3dd\",\"redirectUris\":[\"http://localhost:9000/callback\"],\"forcedRedirectOrigin\":\"\",\"tokenFormat\":\"JWT\",\"tokenSigningMethod\":\"\",\"tokenFields\":[],\"expireInHours\":168,\"refreshExpireInHours\":168,\"signupUrl\":\"\",\"signinUrl\":\"\",\"forgetUrl\":\"\",\"affiliationUrl\":\"\",\"ipWhitelist\":\"\",\"termsOfUse\":\"\",\"signupHtml\":\"\",\"signinHtml\":\"\",\"themeData\":null,\"footerHtml\":\"\",\"formCss\":\"\",\"formCssMobile\":\"\",\"formOffset\":2,\"formSideHtml\":\"\",\"formBackgroundUrl\":\"\",\"formBackgroundUrlMobile\":\"\",\"failedSigninLimit\":5,\"failedSigninFrozenTime\":15}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 8, + "owner": "built-in", + "name": "c3c1335b-785b-4a27-b12a-96bc649a78fb", + "createdTime": "2025-09-20T10:54:20Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-application?id=admin/example-app", + "action": "update-application", + "language": "zh", + "object": "{\"owner\":\"admin\",\"name\":\"example-app\",\"createdTime\":\"2025-09-20T18:50:08+08:00\",\"displayName\":\"示例应用\",\"logo\":\"https://cdn.casbin.org/img/casdoor-logo_1185x256.png\",\"order\":0,\"homepageUrl\":\"\",\"description\":\"\",\"organization\":\"example-org\",\"cert\":\"cert-built-in\",\"defaultGroup\":\"\",\"headerHtml\":\"\",\"enablePassword\":true,\"enableSignUp\":true,\"disableSignin\":false,\"enableSigninSession\":false,\"enableAutoSignin\":false,\"enableCodeSignin\":false,\"enableSamlCompress\":false,\"enableSamlC14n10\":false,\"enableSamlPostBinding\":false,\"useEmailAsSamlNameId\":false,\"enableWebAuthn\":false,\"enableLinkWithEmail\":false,\"orgChoiceMode\":\"\",\"samlReplyUrl\":\"\",\"providers\":[{\"owner\":\"\",\"name\":\"provider_captcha_default\",\"canSignUp\":false,\"canSignIn\":false,\"canUnlink\":false,\"countryCodes\":null,\"prompted\":false,\"signupGroup\":\"\",\"rule\":\"\",\"provider\":{\"owner\":\"admin\",\"name\":\"provider_captcha_default\",\"createdTime\":\"2025-09-20T10:47:17Z\",\"displayName\":\"Captcha Default\",\"category\":\"Captcha\",\"type\":\"Default\",\"subType\":\"\",\"method\":\"\",\"clientId\":\"\",\"clientSecret\":\"\",\"clientId2\":\"\",\"clientSecret2\":\"\",\"cert\":\"\",\"customAuthUrl\":\"\",\"customTokenUrl\":\"\",\"customUserInfoUrl\":\"\",\"customLogo\":\"\",\"scopes\":\"\",\"userMapping\":null,\"httpHeaders\":null,\"host\":\"\",\"port\":0,\"disableSsl\":false,\"title\":\"\",\"content\":\"\",\"receiver\":\"\",\"regionId\":\"\",\"signName\":\"\",\"templateCode\":\"\",\"appId\":\"\",\"endpoint\":\"\",\"intranetEndpoint\":\"\",\"domain\":\"\",\"bucket\":\"\",\"pathPrefix\":\"\",\"metadata\":\"\",\"idP\":\"\",\"issuerUrl\":\"\",\"enableSignAuthnRequest\":false,\"emailRegex\":\"\",\"providerUrl\":\"\"}}],\"signinMethods\":[{\"name\":\"Password\",\"displayName\":\"Password\",\"rule\":\"All\"}],\"signupItems\":[{\"name\":\"ID\",\"visible\":false,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"Random\"},{\"name\":\"Username\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Display name\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Password\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Confirm password\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Email\",\"visible\":false,\"required\":false,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"No verification\"},{\"name\":\"Phone\",\"visible\":true,\"required\":false,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"No verification\"},{\"name\":\"Agreement\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Signup button\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Providers\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n }\\n .provider-big-img {\\n margin-bottom: 10px;\\n }\\n \",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"small\"}],\"signinItems\":[{\"name\":\"Back button\",\"visible\":true,\"label\":\"\",\"customCss\":\".back-button {\\n top: 65px;\\n left: 15px;\\n position: absolute;\\n}\\n.back-inner-button{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Languages\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-languages {\\n top: 55px;\\n right: 5px;\\n position: absolute;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Logo\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-logo-box {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Signin methods\",\"visible\":true,\"label\":\"\",\"customCss\":\".signin-methods {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Username\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-username {}\\n.login-username-input{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Password\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-password {}\\n.login-password-input{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Agreement\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-agreement {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Forgot password?\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-forget-password {\\n display: inline-flex;\\n justify-content: space-between;\\n width: 320px;\\n margin-bottom: 25px;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Login button\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-button-box {\\n margin-bottom: 5px;\\n}\\n.login-button {\\n width: 100%;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Signup link\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-signup-link {\\n margin-bottom: 24px;\\n display: flex;\\n justify-content: end;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Providers\",\"visible\":true,\"label\":\"\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n}\\n.provider-big-img {\\n margin-bottom: 10px;\\n}\",\"placeholder\":\"\",\"rule\":\"small\",\"isCustom\":false}],\"grantTypes\":[\"authorization_code\",\"password\",\"client_credentials\",\"token\",\"id_token\",\"refresh_token\"],\"organizationObj\":{\"owner\":\"admin\",\"name\":\"built-in\",\"createdTime\":\"2025-09-20T10:47:17Z\",\"displayName\":\"Built-in Organization\",\"websiteUrl\":\"https://example.com\",\"logo\":\"\",\"logoDark\":\"\",\"favicon\":\"https://cdn.casbin.org/img/casbin/favicon.ico\",\"hasPrivilegeConsent\":false,\"passwordType\":\"plain\",\"passwordSalt\":\"\",\"passwordOptions\":[\"AtLeast6\"],\"passwordObfuscatorType\":\"\",\"passwordObfuscatorKey\":\"\",\"passwordExpireDays\":0,\"countryCodes\":[\"US\",\"ES\",\"FR\",\"DE\",\"GB\",\"CN\",\"JP\",\"KR\",\"VN\",\"ID\",\"SG\",\"IN\"],\"defaultAvatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"defaultApplication\":\"\",\"userTypes\":[],\"tags\":[],\"languages\":[\"en\",\"zh\",\"es\",\"fr\",\"de\",\"id\",\"ja\",\"ko\",\"ru\",\"vi\",\"pt\"],\"themeData\":null,\"masterPassword\":\"\",\"defaultPassword\":\"\",\"masterVerificationCode\":\"\",\"ipWhitelist\":\"\",\"initScore\":2000,\"enableSoftDeletion\":false,\"isProfilePublic\":false,\"useEmailAsUsername\":false,\"enableTour\":true,\"disableSignin\":false,\"ipRestriction\":\"\",\"navItems\":null,\"widgetItems\":null,\"mfaItems\":null,\"mfaRememberInHours\":0,\"accountItems\":[{\"name\":\"Organization\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"ID\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Display name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Avatar\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"User type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Password\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Email\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Phone\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Country code\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Country/Region\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Location\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Affiliation\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Title\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Homepage\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Bio\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Tag\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Signup application\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Roles\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Permissions\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Groups\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"3rd-party logins\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Properties\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is admin\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is forbidden\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is deleted\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Multi-factor authentication\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"WebAuthn credentials\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Managed accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"MFA accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"}]},\"certPublicKey\":\"\",\"tags\":[],\"samlAttributes\":null,\"isShared\":false,\"ipRestriction\":\"\",\"clientId\":\"e3ba6fec42cfe996121f\",\"clientSecret\":\"0c18bf2a11ffbb756ec6ce47dae9e09bdd48e3dd\",\"redirectUris\":[\"http://localhost:9000/callback\"],\"forcedRedirectOrigin\":\"\",\"tokenFormat\":\"JWT\",\"tokenSigningMethod\":\"\",\"tokenFields\":[],\"expireInHours\":168,\"refreshExpireInHours\":168,\"signupUrl\":\"\",\"signinUrl\":\"\",\"forgetUrl\":\"\",\"affiliationUrl\":\"\",\"ipWhitelist\":\"\",\"termsOfUse\":\"\",\"signupHtml\":\"\",\"signinHtml\":\"\",\"themeData\":null,\"footerHtml\":\"\",\"formCss\":\"\",\"formCssMobile\":\"\",\"formOffset\":2,\"formSideHtml\":\"\",\"formBackgroundUrl\":\"\",\"formBackgroundUrlMobile\":\"\",\"failedSigninLimit\":5,\"failedSigninFrozenTime\":15}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 7, + "owner": "built-in", + "name": "c617f6f6-d4a3-4f77-a111-49c775b9a01d", + "createdTime": "2025-09-20T10:54:11Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-application?id=admin/example-app", + "action": "update-application", + "language": "zh", + "object": "{\"owner\":\"admin\",\"name\":\"example-app\",\"createdTime\":\"2025-09-20T18:50:08+08:00\",\"displayName\":\"示例应用\",\"logo\":\"https://cdn.casbin.org/img/casdoor-logo_1185x256.png\",\"order\":0,\"homepageUrl\":\"\",\"description\":\"\",\"organization\":\"built-in\",\"cert\":\"cert-built-in\",\"defaultGroup\":\"\",\"headerHtml\":\"\",\"enablePassword\":true,\"enableSignUp\":true,\"disableSignin\":false,\"enableSigninSession\":false,\"enableAutoSignin\":false,\"enableCodeSignin\":false,\"enableSamlCompress\":false,\"enableSamlC14n10\":false,\"enableSamlPostBinding\":false,\"useEmailAsSamlNameId\":false,\"enableWebAuthn\":false,\"enableLinkWithEmail\":false,\"orgChoiceMode\":\"\",\"samlReplyUrl\":\"\",\"providers\":[{\"owner\":\"\",\"name\":\"provider_captcha_default\",\"canSignUp\":false,\"canSignIn\":false,\"canUnlink\":false,\"countryCodes\":null,\"prompted\":false,\"signupGroup\":\"\",\"rule\":\"\",\"provider\":{\"owner\":\"admin\",\"name\":\"provider_captcha_default\",\"createdTime\":\"2025-09-20T10:47:17Z\",\"displayName\":\"Captcha Default\",\"category\":\"Captcha\",\"type\":\"Default\",\"subType\":\"\",\"method\":\"\",\"clientId\":\"\",\"clientSecret\":\"\",\"clientId2\":\"\",\"clientSecret2\":\"\",\"cert\":\"\",\"customAuthUrl\":\"\",\"customTokenUrl\":\"\",\"customUserInfoUrl\":\"\",\"customLogo\":\"\",\"scopes\":\"\",\"userMapping\":null,\"httpHeaders\":null,\"host\":\"\",\"port\":0,\"disableSsl\":false,\"title\":\"\",\"content\":\"\",\"receiver\":\"\",\"regionId\":\"\",\"signName\":\"\",\"templateCode\":\"\",\"appId\":\"\",\"endpoint\":\"\",\"intranetEndpoint\":\"\",\"domain\":\"\",\"bucket\":\"\",\"pathPrefix\":\"\",\"metadata\":\"\",\"idP\":\"\",\"issuerUrl\":\"\",\"enableSignAuthnRequest\":false,\"emailRegex\":\"\",\"providerUrl\":\"\"}}],\"signinMethods\":[{\"name\":\"Password\",\"displayName\":\"Password\",\"rule\":\"All\"}],\"signupItems\":[{\"name\":\"ID\",\"visible\":false,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"Random\"},{\"name\":\"Username\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Display name\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Password\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Confirm password\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Email\",\"visible\":false,\"required\":false,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"No verification\"},{\"name\":\"Phone\",\"visible\":true,\"required\":false,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"No verification\"},{\"name\":\"Agreement\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Signup button\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Providers\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n }\\n .provider-big-img {\\n margin-bottom: 10px;\\n }\\n \",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"small\"}],\"signinItems\":[{\"name\":\"Back button\",\"visible\":true,\"label\":\"\",\"customCss\":\".back-button {\\n top: 65px;\\n left: 15px;\\n position: absolute;\\n}\\n.back-inner-button{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Languages\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-languages {\\n top: 55px;\\n right: 5px;\\n position: absolute;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Logo\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-logo-box {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Signin methods\",\"visible\":true,\"label\":\"\",\"customCss\":\".signin-methods {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Username\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-username {}\\n.login-username-input{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Password\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-password {}\\n.login-password-input{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Agreement\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-agreement {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Forgot password?\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-forget-password {\\n display: inline-flex;\\n justify-content: space-between;\\n width: 320px;\\n margin-bottom: 25px;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Login button\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-button-box {\\n margin-bottom: 5px;\\n}\\n.login-button {\\n width: 100%;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Signup link\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-signup-link {\\n margin-bottom: 24px;\\n display: flex;\\n justify-content: end;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Providers\",\"visible\":true,\"label\":\"\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n}\\n.provider-big-img {\\n margin-bottom: 10px;\\n}\",\"placeholder\":\"\",\"rule\":\"small\",\"isCustom\":false}],\"grantTypes\":[\"authorization_code\",\"password\",\"client_credentials\",\"token\",\"id_token\",\"refresh_token\"],\"organizationObj\":{\"owner\":\"admin\",\"name\":\"built-in\",\"createdTime\":\"2025-09-20T10:47:17Z\",\"displayName\":\"Built-in Organization\",\"websiteUrl\":\"https://example.com\",\"logo\":\"\",\"logoDark\":\"\",\"favicon\":\"https://cdn.casbin.org/img/casbin/favicon.ico\",\"hasPrivilegeConsent\":false,\"passwordType\":\"plain\",\"passwordSalt\":\"\",\"passwordOptions\":[\"AtLeast6\"],\"passwordObfuscatorType\":\"\",\"passwordObfuscatorKey\":\"\",\"passwordExpireDays\":0,\"countryCodes\":[\"US\",\"ES\",\"FR\",\"DE\",\"GB\",\"CN\",\"JP\",\"KR\",\"VN\",\"ID\",\"SG\",\"IN\"],\"defaultAvatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"defaultApplication\":\"\",\"userTypes\":[],\"tags\":[],\"languages\":[\"en\",\"zh\",\"es\",\"fr\",\"de\",\"id\",\"ja\",\"ko\",\"ru\",\"vi\",\"pt\"],\"themeData\":null,\"masterPassword\":\"\",\"defaultPassword\":\"\",\"masterVerificationCode\":\"\",\"ipWhitelist\":\"\",\"initScore\":2000,\"enableSoftDeletion\":false,\"isProfilePublic\":false,\"useEmailAsUsername\":false,\"enableTour\":true,\"disableSignin\":false,\"ipRestriction\":\"\",\"navItems\":null,\"widgetItems\":null,\"mfaItems\":null,\"mfaRememberInHours\":0,\"accountItems\":[{\"name\":\"Organization\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"ID\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Display name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Avatar\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"User type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Password\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Email\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Phone\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Country code\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Country/Region\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Location\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Affiliation\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Title\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Homepage\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Bio\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Tag\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Signup application\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Roles\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Permissions\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Groups\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"3rd-party logins\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Properties\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is admin\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is forbidden\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is deleted\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Multi-factor authentication\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"WebAuthn credentials\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Managed accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"MFA accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"}]},\"certPublicKey\":\"\",\"tags\":[],\"samlAttributes\":null,\"isShared\":false,\"ipRestriction\":\"\",\"clientId\":\"e3ba6fec42cfe996121f\",\"clientSecret\":\"0c18bf2a11ffbb756ec6ce47dae9e09bdd48e3dd\",\"redirectUris\":[\"http://localhost:9000/callback\"],\"forcedRedirectOrigin\":\"\",\"tokenFormat\":\"JWT\",\"tokenSigningMethod\":\"\",\"tokenFields\":[],\"expireInHours\":168,\"refreshExpireInHours\":168,\"signupUrl\":\"\",\"signinUrl\":\"\",\"forgetUrl\":\"\",\"affiliationUrl\":\"\",\"ipWhitelist\":\"\",\"termsOfUse\":\"\",\"signupHtml\":\"\",\"signinHtml\":\"\",\"themeData\":null,\"footerHtml\":\"\",\"formCss\":\"\",\"formCssMobile\":\"\",\"formOffset\":2,\"formSideHtml\":\"\",\"formBackgroundUrl\":\"\",\"formBackgroundUrlMobile\":\"\",\"failedSigninLimit\":5,\"failedSigninFrozenTime\":15}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 6, + "owner": "built-in", + "name": "612a4272-23f0-4289-b7de-e75e0567050d", + "createdTime": "2025-09-20T10:53:39Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-application?id=admin/application_1o1gji", + "action": "update-application", + "language": "zh", + "object": "{\"owner\":\"admin\",\"name\":\"example-app\",\"createdTime\":\"2025-09-20T18:50:08+08:00\",\"displayName\":\"示例应用\",\"logo\":\"https://cdn.casbin.org/img/casdoor-logo_1185x256.png\",\"order\":0,\"homepageUrl\":\"\",\"description\":\"\",\"organization\":\"built-in\",\"cert\":\"cert-built-in\",\"defaultGroup\":\"\",\"headerHtml\":\"\",\"enablePassword\":true,\"enableSignUp\":true,\"disableSignin\":false,\"enableSigninSession\":false,\"enableAutoSignin\":false,\"enableCodeSignin\":false,\"enableSamlCompress\":false,\"enableSamlC14n10\":false,\"enableSamlPostBinding\":false,\"useEmailAsSamlNameId\":false,\"enableWebAuthn\":false,\"enableLinkWithEmail\":false,\"orgChoiceMode\":\"\",\"samlReplyUrl\":\"\",\"providers\":[{\"owner\":\"\",\"name\":\"provider_captcha_default\",\"canSignUp\":false,\"canSignIn\":false,\"canUnlink\":false,\"countryCodes\":null,\"prompted\":false,\"signupGroup\":\"\",\"rule\":\"\",\"provider\":{\"owner\":\"admin\",\"name\":\"provider_captcha_default\",\"createdTime\":\"2025-09-20T10:47:17Z\",\"displayName\":\"Captcha Default\",\"category\":\"Captcha\",\"type\":\"Default\",\"subType\":\"\",\"method\":\"\",\"clientId\":\"\",\"clientSecret\":\"\",\"clientId2\":\"\",\"clientSecret2\":\"\",\"cert\":\"\",\"customAuthUrl\":\"\",\"customTokenUrl\":\"\",\"customUserInfoUrl\":\"\",\"customLogo\":\"\",\"scopes\":\"\",\"userMapping\":null,\"httpHeaders\":null,\"host\":\"\",\"port\":0,\"disableSsl\":false,\"title\":\"\",\"content\":\"\",\"receiver\":\"\",\"regionId\":\"\",\"signName\":\"\",\"templateCode\":\"\",\"appId\":\"\",\"endpoint\":\"\",\"intranetEndpoint\":\"\",\"domain\":\"\",\"bucket\":\"\",\"pathPrefix\":\"\",\"metadata\":\"\",\"idP\":\"\",\"issuerUrl\":\"\",\"enableSignAuthnRequest\":false,\"emailRegex\":\"\",\"providerUrl\":\"\"}}],\"signinMethods\":[{\"name\":\"Password\",\"displayName\":\"Password\",\"rule\":\"All\"}],\"signupItems\":[{\"name\":\"ID\",\"visible\":false,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"Random\"},{\"name\":\"Username\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Display name\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Password\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Confirm password\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Email\",\"visible\":false,\"required\":false,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"No verification\"},{\"name\":\"Phone\",\"visible\":true,\"required\":false,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"No verification\"},{\"name\":\"Agreement\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Signup button\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\"\",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"None\"},{\"name\":\"Providers\",\"visible\":true,\"required\":true,\"prompted\":false,\"type\":\"\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n }\\n .provider-big-img {\\n margin-bottom: 10px;\\n }\\n \",\"label\":\"\",\"placeholder\":\"\",\"options\":null,\"regex\":\"\",\"rule\":\"small\"}],\"signinItems\":[{\"name\":\"Back button\",\"visible\":true,\"label\":\"\",\"customCss\":\".back-button {\\n top: 65px;\\n left: 15px;\\n position: absolute;\\n}\\n.back-inner-button{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Languages\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-languages {\\n top: 55px;\\n right: 5px;\\n position: absolute;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Logo\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-logo-box {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Signin methods\",\"visible\":true,\"label\":\"\",\"customCss\":\".signin-methods {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Username\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-username {}\\n.login-username-input{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Password\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-password {}\\n.login-password-input{}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Agreement\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-agreement {}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Forgot password?\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-forget-password {\\n display: inline-flex;\\n justify-content: space-between;\\n width: 320px;\\n margin-bottom: 25px;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Login button\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-button-box {\\n margin-bottom: 5px;\\n}\\n.login-button {\\n width: 100%;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Signup link\",\"visible\":true,\"label\":\"\",\"customCss\":\".login-signup-link {\\n margin-bottom: 24px;\\n display: flex;\\n justify-content: end;\\n}\",\"placeholder\":\"\",\"rule\":\"None\",\"isCustom\":false},{\"name\":\"Providers\",\"visible\":true,\"label\":\"\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n}\\n.provider-big-img {\\n margin-bottom: 10px;\\n}\",\"placeholder\":\"\",\"rule\":\"small\",\"isCustom\":false}],\"grantTypes\":[\"authorization_code\",\"password\",\"client_credentials\",\"token\",\"id_token\",\"refresh_token\"],\"organizationObj\":{\"owner\":\"admin\",\"name\":\"built-in\",\"createdTime\":\"2025-09-20T10:47:17Z\",\"displayName\":\"Built-in Organization\",\"websiteUrl\":\"https://example.com\",\"logo\":\"\",\"logoDark\":\"\",\"favicon\":\"https://cdn.casbin.org/img/casbin/favicon.ico\",\"hasPrivilegeConsent\":false,\"passwordType\":\"plain\",\"passwordSalt\":\"\",\"passwordOptions\":[\"AtLeast6\"],\"passwordObfuscatorType\":\"\",\"passwordObfuscatorKey\":\"\",\"passwordExpireDays\":0,\"countryCodes\":[\"US\",\"ES\",\"FR\",\"DE\",\"GB\",\"CN\",\"JP\",\"KR\",\"VN\",\"ID\",\"SG\",\"IN\"],\"defaultAvatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"defaultApplication\":\"\",\"userTypes\":[],\"tags\":[],\"languages\":[\"en\",\"zh\",\"es\",\"fr\",\"de\",\"id\",\"ja\",\"ko\",\"ru\",\"vi\",\"pt\"],\"themeData\":null,\"masterPassword\":\"\",\"defaultPassword\":\"\",\"masterVerificationCode\":\"\",\"ipWhitelist\":\"\",\"initScore\":2000,\"enableSoftDeletion\":false,\"isProfilePublic\":false,\"useEmailAsUsername\":false,\"enableTour\":true,\"disableSignin\":false,\"ipRestriction\":\"\",\"navItems\":null,\"widgetItems\":null,\"mfaItems\":null,\"mfaRememberInHours\":0,\"accountItems\":[{\"name\":\"Organization\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"ID\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Display name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Avatar\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"User type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Password\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Email\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Phone\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Country code\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Country/Region\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Location\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Affiliation\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Title\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Homepage\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Bio\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Tag\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Signup application\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Roles\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Permissions\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Groups\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"3rd-party logins\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Properties\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is admin\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is forbidden\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is deleted\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Multi-factor authentication\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"WebAuthn credentials\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Managed accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"MFA accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"}]},\"certPublicKey\":\"\",\"tags\":[],\"samlAttributes\":null,\"isShared\":false,\"ipRestriction\":\"\",\"clientId\":\"e3ba6fec42cfe996121f\",\"clientSecret\":\"0c18bf2a11ffbb756ec6ce47dae9e09bdd48e3dd\",\"redirectUris\":[\"http://localhost:9000/callback\"],\"forcedRedirectOrigin\":\"\",\"tokenFormat\":\"JWT\",\"tokenSigningMethod\":\"\",\"tokenFields\":[],\"expireInHours\":168,\"refreshExpireInHours\":168,\"signupUrl\":\"\",\"signinUrl\":\"\",\"forgetUrl\":\"\",\"affiliationUrl\":\"\",\"ipWhitelist\":\"\",\"termsOfUse\":\"\",\"signupHtml\":\"\",\"signinHtml\":\"\",\"themeData\":null,\"footerHtml\":\"\",\"formCss\":\"\",\"formCssMobile\":\"\",\"formOffset\":2,\"formSideHtml\":\"\",\"formBackgroundUrl\":\"\",\"formBackgroundUrlMobile\":\"\",\"failedSigninLimit\":5,\"failedSigninFrozenTime\":15}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 5, + "owner": "built-in", + "name": "aa5b7413-d9fb-4fee-9565-1a39712643da", + "createdTime": "2025-09-20T10:50:09Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/add-application", + "action": "add-application", + "language": "zh", + "object": "{\"owner\":\"admin\",\"name\":\"application_1o1gji\",\"organization\":\"built-in\",\"createdTime\":\"2025-09-20T18:50:08+08:00\",\"displayName\":\"New Application - 1o1gji\",\"logo\":\"https://cdn.casbin.org/img/casdoor-logo_1185x256.png\",\"enablePassword\":true,\"enableSignUp\":true,\"disableSignin\":false,\"enableSigninSession\":false,\"enableCodeSignin\":false,\"enableSamlCompress\":false,\"providers\":[{\"name\":\"provider_captcha_default\",\"canSignUp\":false,\"canSignIn\":false,\"canUnlink\":false,\"prompted\":false,\"signupGroup\":\"\",\"rule\":\"\"}],\"SigninMethods\":[{\"name\":\"Password\",\"displayName\":\"Password\",\"rule\":\"All\"},{\"name\":\"Verification code\",\"displayName\":\"Verification code\",\"rule\":\"All\"},{\"name\":\"WebAuthn\",\"displayName\":\"WebAuthn\",\"rule\":\"None\"},{\"name\":\"Face ID\",\"displayName\":\"Face ID\",\"rule\":\"None\"}],\"signupItems\":[{\"name\":\"ID\",\"visible\":false,\"required\":true,\"rule\":\"Random\"},{\"name\":\"Username\",\"visible\":true,\"required\":true,\"rule\":\"None\"},{\"name\":\"Display name\",\"visible\":true,\"required\":true,\"rule\":\"None\"},{\"name\":\"Password\",\"visible\":true,\"required\":true,\"rule\":\"None\"},{\"name\":\"Confirm password\",\"visible\":true,\"required\":true,\"rule\":\"None\"},{\"name\":\"Email\",\"visible\":true,\"required\":true,\"rule\":\"Normal\"},{\"name\":\"Phone\",\"visible\":true,\"required\":true,\"rule\":\"None\"},{\"name\":\"Agreement\",\"visible\":true,\"required\":true,\"rule\":\"None\"},{\"name\":\"Signup button\",\"visible\":true,\"required\":true,\"rule\":\"None\"},{\"name\":\"Providers\",\"visible\":true,\"required\":true,\"rule\":\"None\",\"customCss\":\".provider-img {\\n width: 30px;\\n margin: 5px;\\n }\\n .provider-big-img {\\n margin-bottom: 10px;\\n }\\n \"}],\"grantTypes\":[\"authorization_code\",\"password\",\"client_credentials\",\"token\",\"id_token\",\"refresh_token\"],\"cert\":\"cert-built-in\",\"redirectUris\":[\"http://localhost:9000/callback\"],\"tokenFormat\":\"JWT\",\"tokenFields\":[],\"expireInHours\":168,\"refreshExpireInHours\":168,\"formOffset\":2}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 4, + "owner": "built-in", + "name": "fb9b52f4-cee5-4c76-b577-0fa18d5e2162", + "createdTime": "2025-09-20T10:50:04Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/update-organization?id=admin/organization_qe0w97", + "action": "update-organization", + "language": "zh", + "object": "{\"owner\":\"admin\",\"name\":\"example-org\",\"createdTime\":\"2025-09-20T18:48:24+08:00\",\"displayName\":\"示例组织\",\"websiteUrl\":\"https://door.casdoor.com\",\"logo\":\"\",\"logoDark\":\"\",\"favicon\":\"https://cdn.casbin.org/img/favicon.png\",\"hasPrivilegeConsent\":false,\"passwordType\":\"plain\",\"passwordSalt\":\"\",\"passwordOptions\":[\"AtLeast6\"],\"passwordObfuscatorType\":\"Plain\",\"passwordObfuscatorKey\":\"\",\"passwordExpireDays\":0,\"countryCodes\":[\"CN\"],\"defaultAvatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"defaultApplication\":\"\",\"userTypes\":null,\"tags\":[],\"languages\":[\"en\",\"es\",\"fr\",\"de\",\"zh\",\"id\",\"ja\",\"ko\",\"ru\",\"vi\",\"pt\",\"it\",\"ms\",\"tr\",\"ar\",\"he\",\"nl\",\"pl\",\"fi\",\"sv\",\"uk\",\"kk\",\"fa\",\"cs\",\"sk\",\"az\"],\"themeData\":null,\"masterPassword\":\"\",\"defaultPassword\":\"\",\"masterVerificationCode\":\"\",\"ipWhitelist\":\"\",\"initScore\":0,\"enableSoftDeletion\":false,\"isProfilePublic\":true,\"useEmailAsUsername\":false,\"enableTour\":true,\"disableSignin\":false,\"ipRestriction\":\"\",\"navItems\":null,\"widgetItems\":null,\"mfaItems\":null,\"mfaRememberInHours\":12,\"accountItems\":[{\"name\":\"Organization\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"ID\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Display name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Avatar\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"User type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Password\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Email\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Phone\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Country code\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Country/Region\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Location\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Address\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Affiliation\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Title\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"ID card type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"ID card\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"ID card info\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Homepage\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Bio\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Tag\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Language\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Gender\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Birthday\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Education\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Score\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Karma\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Ranking\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Signup application\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"API key\",\"visible\":false,\"viewRule\":\"\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Groups\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Roles\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"Permissions\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\",\"regex\":\"\"},{\"name\":\"3rd-party logins\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Properties\",\"visible\":false,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is online\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is admin\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is forbidden\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Is deleted\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\",\"regex\":\"\"},{\"name\":\"Multi-factor authentication\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"WebAuthn credentials\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"Managed accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"},{\"name\":\"MFA accounts\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\",\"regex\":\"\"}],\"enableDarkLogo\":false}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 3, + "owner": "built-in", + "name": "b0de7ab6-eda7-4d2d-8221-5ac506b21d3e", + "createdTime": "2025-09-20T10:48:24Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/add-organization", + "action": "add-organization", + "language": "zh", + "object": "{\"owner\":\"admin\",\"name\":\"organization_qe0w97\",\"createdTime\":\"2025-09-20T18:48:24+08:00\",\"displayName\":\"New Organization - qe0w97\",\"websiteUrl\":\"https://door.casdoor.com\",\"favicon\":\"https://cdn.casbin.org/img/favicon.png\",\"passwordType\":\"plain\",\"PasswordSalt\":\"\",\"passwordOptions\":[\"AtLeast6\"],\"passwordObfuscatorType\":\"Plain\",\"passwordObfuscatorKey\":\"\",\"passwordExpireDays\":0,\"countryCodes\":[\"US\"],\"defaultAvatar\":\"https://cdn.casbin.org/img/casbin.svg\",\"defaultApplication\":\"\",\"tags\":[],\"languages\":[\"en\",\"es\",\"fr\",\"de\",\"zh\",\"id\",\"ja\",\"ko\",\"ru\",\"vi\",\"pt\",\"it\",\"ms\",\"tr\",\"ar\",\"he\",\"nl\",\"pl\",\"fi\",\"sv\",\"uk\",\"kk\",\"fa\",\"cs\",\"sk\",\"az\"],\"masterPassword\":\"\",\"defaultPassword\":\"\",\"enableSoftDeletion\":false,\"isProfilePublic\":true,\"enableTour\":true,\"disableSignin\":false,\"mfaRememberInHours\":12,\"accountItems\":[{\"name\":\"Organization\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"ID\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\"},{\"name\":\"Name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Display name\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Avatar\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"User type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Password\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\"},{\"name\":\"Email\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Phone\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Country code\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Country/Region\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Location\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Address\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Affiliation\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Title\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"ID card type\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"ID card\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"ID card info\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Homepage\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Bio\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Self\"},{\"name\":\"Tag\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Language\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Gender\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Birthday\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Education\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Score\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Karma\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Ranking\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Signup application\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"API key\",\"label\":\"API 密钥\",\"modifyRule\":\"Self\"},{\"name\":\"Groups\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Admin\"},{\"name\":\"Roles\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\"},{\"name\":\"Permissions\",\"visible\":true,\"viewRule\":\"Public\",\"modifyRule\":\"Immutable\"},{\"name\":\"3rd-party logins\",\"visible\":true,\"viewRule\":\"Self\",\"modifyRule\":\"Self\"},{\"name\":\"Properties\",\"visible\":false,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\"},{\"name\":\"Is online\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\"},{\"name\":\"Is admin\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\"},{\"name\":\"Is forbidden\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\"},{\"name\":\"Is deleted\",\"visible\":true,\"viewRule\":\"Admin\",\"modifyRule\":\"Admin\"},{\"Name\":\"Multi-factor authentication\",\"Visible\":true,\"ViewRule\":\"Self\",\"ModifyRule\":\"Self\"},{\"Name\":\"WebAuthn credentials\",\"Visible\":true,\"ViewRule\":\"Self\",\"ModifyRule\":\"Self\"},{\"Name\":\"Managed accounts\",\"Visible\":true,\"ViewRule\":\"Self\",\"ModifyRule\":\"Self\"},{\"Name\":\"MFA accounts\",\"Visible\":true,\"ViewRule\":\"Self\",\"ModifyRule\":\"Self\"}]}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 2, + "owner": "built-in", + "name": "81b8cee1-efe6-4522-a915-11fc0dc77ff2", + "createdTime": "2025-09-20T10:48:20Z", + "organization": "built-in", + "clientIp": "10.10.122.195", + "user": "admin", + "method": "POST", + "requestUri": "/api/login", + "action": "login", + "language": "zh", + "object": "{\"application\":\"app-built-in\",\"organization\":\"built-in\",\"username\":\"admin\",\"password\":\"***\",\"autoSignin\":true,\"language\":\"\",\"signinMethod\":\"Password\",\"type\":\"login\"}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + }, + { + "id": 1, + "owner": "built-in", + "name": "3041e2e0-2ff5-43cc-8fad-7d424ebc2e07", + "createdTime": "2025-09-20T10:47:51Z", + "organization": "built-in", + "clientIp": "10.10.125.231", + "user": "admin", + "method": "POST", + "requestUri": "/api/login", + "action": "login", + "language": "zh", + "object": "{\"application\":\"app-built-in\",\"organization\":\"built-in\",\"username\":\"admin\",\"autoSignin\":true,\"password\":\"***\",\"language\":\"\",\"signinMethod\":\"Password\",\"type\":\"login\"}", + "response": "{status:\"ok\", msg:\"\"}", + "statusCode": 200, + "isTriggered": true + } + ], + "sessions": [ + { + "owner": "built-in", + "name": "admin", + "application": "app-built-in", + "createdTime": "2025-09-20T10:47:51Z", + "sessionId": [ + "12692e708d7f7348e75ba800df9606d2", + "d60a540308bd43cfae3b88e83c50abd2", + "ae85d04cfecb47522ceeec61a166fcc8" + ] + } + ], + "subscriptions": [], + "transactions": [], + "enforcerPolicies": { + "built-in/api-enforcer-built-in": [ + [ + "built-in", + "*", + "*", + "*", + "*", + "*" + ], + [ + "app", + "*", + "*", + "*", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/signup", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-email-and-phone", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/login", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-app-login", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/logout", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/logout", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/callback", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/device-auth", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-account", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/userinfo", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/user", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/health", + "*", + "*" + ], + [ + "*", + "*", + "*", + "/api/webhook", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-qrcode", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-webhook-event", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-captcha-status", + "*", + "*" + ], + [ + "*", + "*", + "*", + "/api/login/oauth", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-application", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-organization-applications", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-user", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-user-application", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-resources", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-records", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-product", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/buy-product", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-payment", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/update-payment", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/invoice-payment", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/notify-payment", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/unlink", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/set-password", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/send-verification-code", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-captcha", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/verify-captcha", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/verify-code", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/reset-email-or-phone", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/upload-resource", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/.well-known/openid-configuration", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/.well-known/webfinger", + "*", + "*" + ], + [ + "*", + "*", + "*", + "/.well-known/jwks", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-saml-login", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/acs", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/saml/metadata", + "*", + "*" + ], + [ + "*", + "*", + "*", + "/api/saml/redirect", + "*", + "*" + ], + [ + "*", + "*", + "*", + "/cas", + "*", + "*" + ], + [ + "*", + "*", + "*", + "/scim", + "*", + "*" + ], + [ + "*", + "*", + "*", + "/api/webauthn", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-release", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-default-application", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-prometheus-info", + "*", + "*" + ], + [ + "*", + "*", + "*", + "/api/metrics", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-pricing", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-plan", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-subscription", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-provider", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-organization-names", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-all-objects", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-all-actions", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-all-roles", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/run-casbin-command", + "*", + "*" + ], + [ + "*", + "*", + "POST", + "/api/refresh-engines", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/get-invitation-info", + "*", + "*" + ], + [ + "*", + "*", + "GET", + "/api/faceid-signin-begin", + "*", + "*" + ] + ], + "built-in/user-enforcer-built-in": null + } +} \ No newline at end of file diff --git a/docker/astronAgent/casdoor/entrypoint.sh b/docker/astronAgent/casdoor/entrypoint.sh index aea43b7baacb7364c33fcc90293e515af9cd638e..d4c041a308a51010dca0a5fce77d3bb1bca96514 100644 --- a/docker/astronAgent/casdoor/entrypoint.sh +++ b/docker/astronAgent/casdoor/entrypoint.sh @@ -1,29 +1,21 @@ #!/bin/sh - -# Casdoor configuration script -# This script dynamically replaces redirectUris in init_data.json - set -e -CONFIG_FILE="/conf/init_data.json" - -# Check if CONSOLE_DOMAIN is set -if [ -z "$CONSOLE_DOMAIN" ]; then - echo "Warning: CONSOLE_DOMAIN environment variable is not set. Using default value." - CONSOLE_DOMAIN="http://localhost" -fi +chmod -R 777 /conf 2>/dev/null || true -# Construct the redirect URI -REDIRECT_URI="${CONSOLE_DOMAIN}/callback" +echo "===== Initializing Casdoor Configuration =====" +echo "CONSOLE_DOMAIN: ${CONSOLE_DOMAIN:-http://localhost}" +echo "HOST_BASE_ADDRESS: ${HOST_BASE_ADDRESS:-http://localhost}" -echo "===== Casdoor Configuration =====" -echo "CONSOLE_DOMAIN: $CONSOLE_DOMAIN" -echo "REDIRECT_URI: $REDIRECT_URI" -echo "=================================" - -# Use sed to replace the redirectUris value -echo "Updating redirectUris in init_data.json..." -sed -i "s|\"redirectUris\": \[[^]]*\]|\"redirectUris\": [\"${REDIRECT_URI}\"]|g" "$CONFIG_FILE" +# Generate config from template using sed (replace all environment variables) +echo "Generating init_data.json from template..." +sed -e "s|\${CONSOLE_DOMAIN}|${CONSOLE_DOMAIN}|g" \ + -e "s|\${HOST_BASE_ADDRESS}|${HOST_BASE_ADDRESS}|g" \ + /conf/init_data.json.template > /conf/init_data.json echo "Configuration updated successfully!" -echo "RedirectUris set to: [\"${REDIRECT_URI}\"]" \ No newline at end of file +echo "redirectUris: [${CONSOLE_DOMAIN}/callback, ${HOST_BASE_ADDRESS}/callback]" +echo "==========================================" + +# Start Casdoor +exec /server --createDatabase=true \ No newline at end of file diff --git a/docker/astronAgent/docker-compose-with-auth.yml b/docker/astronAgent/docker-compose-auth.yml similarity index 64% rename from docker/astronAgent/docker-compose-with-auth.yml rename to docker/astronAgent/docker-compose-auth.yml index c7da5c78d5c7d68e273e88a71a042de61b091392..ba8ae4a018306db6543ff3bb32926c3b6eb19652 100644 --- a/docker/astronAgent/docker-compose-with-auth.yml +++ b/docker/astronAgent/docker-compose-auth.yml @@ -2,22 +2,23 @@ services: casdoor: image: casbin/casdoor:latest container_name: astron-agent-casdoor - restart: unless-stopped + restart: always + user: root ports: - - "8000:8000" + - "${CASDOOR_PORT:-8000}:8000" environment: - GIN_MODE=release - CONSOLE_DOMAIN=${CONSOLE_DOMAIN:-http://localhost} + - HOST_BASE_ADDRESS=${HOST_BASE_ADDRESS:-http://localhost} volumes: - ./casdoor/conf:/conf - - ./casdoor/entrypoint.sh:/custom-entrypoint.sh:ro + - ./casdoor/entrypoint.sh:/entrypoint.sh:ro - casdoor-logs:/logs networks: - astron-agent-network depends_on: - casdoor-mysql - entrypoint: ["/bin/sh", "-c"] - command: ["sh /custom-entrypoint.sh && /server --createDatabase=true"] + entrypoint: ["/bin/sh", "/entrypoint.sh"] casdoor-mysql: image: mysql:8.4 @@ -37,6 +38,13 @@ services: timeout: 20s retries: 10 +# ============================================================================ +# Network Configuration +# ============================================================================ +networks: + astron-agent-network: + driver: bridge + volumes: casdoor-logs: casdoor-mysql-data: \ No newline at end of file diff --git a/docker/astronAgent/docker-compose-with-auth-rpa.yaml b/docker/astronAgent/docker-compose-with-auth-rpa.yaml new file mode 100644 index 0000000000000000000000000000000000000000..75dba1a0e2bc191b55fec6c658bc7907137f9114 --- /dev/null +++ b/docker/astronAgent/docker-compose-with-auth-rpa.yaml @@ -0,0 +1,18 @@ +# ============================================================================ +# Integrated Docker Compose Configuration +# astronAgent + Casdoor + astronRPA +# ============================================================================ +# All services run in the same Docker network: astron-agent-network + +include: + # Include astronAgent core services with Casdoor authentication + # This includes: docker-compose-auth.yml + docker-compose.yaml + # Uses: docker/astronAgent/.env + - path: docker-compose-with-auth.yaml + env_file: .env + + # Include astronRPA services + # Uses: docker/astronAgent/astronRPA/.env + - path: astronRPA/docker-compose.yml + project_directory: astronRPA + env_file: astronRPA/.env diff --git a/docker/astronAgent/docker-compose-with-auth.yaml b/docker/astronAgent/docker-compose-with-auth.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e7025c1170fd3e480a9995d425c965431b8e3a4d --- /dev/null +++ b/docker/astronAgent/docker-compose-with-auth.yaml @@ -0,0 +1,14 @@ +# ============================================================================ +# astronAgent with Casdoor Authentication +# ============================================================================ +# This configuration includes: +# - Casdoor authentication service (from docker-compose-auth.yml) +# - astronAgent core services (from docker-compose.yaml) +# All services run in the same network: astron-agent-network + +include: + # Include Casdoor authentication service + - docker-compose-auth.yml + + # Include astronAgent core services + - docker-compose.yaml diff --git a/docker/astronAgent/docker-compose.yaml b/docker/astronAgent/docker-compose.yaml index c322b62d8538bcd402ddc5dcf3cac7cc8ad98c9d..81f6cf7e8ffebe34cf538fc189f55aeabe1a389a 100644 --- a/docker/astronAgent/docker-compose.yaml +++ b/docker/astronAgent/docker-compose.yaml @@ -1,6 +1,3 @@ -include: - - docker-compose-with-auth.yml - services: # ============================================================================ # Infrastructure Services @@ -61,53 +58,53 @@ services: timeout: ${HEALTH_CHECK_TIMEOUT:-10s} retries: ${HEALTH_CHECK_RETRIES:-60} - # Elasticsearch Search Engine - elasticsearch: - image: elasticsearch:7.16.2 - container_name: astron-agent-elasticsearch - environment: - - discovery.type=single-node - - "ES_JAVA_OPTS=${ES_JAVA_OPTS:--Xms512m -Xmx512m}" - - xpack.security.enabled=${ELASTICSEARCH_SECURITY_ENABLED:-false} - - cluster.name=astron-agent-cluster - volumes: - - elasticsearch_data:/usr/share/elasticsearch/data - networks: - - astron-agent-network - restart: always - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:9200/_cluster/health"] - interval: ${HEALTH_CHECK_INTERVAL:-30s} - timeout: ${HEALTH_CHECK_TIMEOUT:-10s} - retries: ${HEALTH_CHECK_RETRIES:-60} + # Elasticsearch Search Engine (Disabled by default, uncomment to enable) + # elasticsearch: + # image: elasticsearch:7.16.2 + # container_name: astron-agent-elasticsearch + # environment: + # - discovery.type=single-node + # - "ES_JAVA_OPTS=${ES_JAVA_OPTS:--Xms512m -Xmx512m}" + # - xpack.security.enabled=${ELASTICSEARCH_SECURITY_ENABLED:-false} + # - cluster.name=astron-agent-cluster + # volumes: + # - elasticsearch_data:/usr/share/elasticsearch/data + # networks: + # - astron-agent-network + # restart: always + # healthcheck: + # test: ["CMD", "curl", "-f", "http://localhost:9200/_cluster/health"] + # interval: ${HEALTH_CHECK_INTERVAL:-30s} + # timeout: ${HEALTH_CHECK_TIMEOUT:-10s} + # retries: ${HEALTH_CHECK_RETRIES:-60} - # Kafka Message Queue - kafka: - image: apache/kafka:3.7.0 - container_name: astron-agent-kafka - environment: - KAFKA_NODE_ID: 1 - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT - KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092 - KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:29092,CONTROLLER://0.0.0.0:29093 - KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT - KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER - KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:29093 - KAFKA_PROCESS_ROLES: broker,controller - KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 - KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: ${KAFKA_REPLICATION_FACTOR:-1} - KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: ${KAFKA_REPLICATION_FACTOR:-1} - CLUSTER_ID: ${KAFKA_CLUSTER_ID:-MkU3OEVBNTcwNTJENDM2Qk} - volumes: - - kafka_data:/var/lib/kafka/data - networks: - - astron-agent-network - restart: always - healthcheck: - test: ["CMD-SHELL", "netstat -tulpn | grep 29092 || exit 1"] - interval: ${HEALTH_CHECK_INTERVAL:-30s} - timeout: ${HEALTH_CHECK_TIMEOUT:-10s} - retries: ${HEALTH_CHECK_RETRIES:-60} + # Kafka Message Queue (Disabled by default, uncomment to enable) + # kafka: + # image: apache/kafka:3.7.0 + # container_name: astron-agent-kafka + # environment: + # KAFKA_NODE_ID: 1 + # KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT + # KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092 + # KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:29092,CONTROLLER://0.0.0.0:29093 + # KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT + # KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER + # KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:29093 + # KAFKA_PROCESS_ROLES: broker,controller + # KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 + # KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: ${KAFKA_REPLICATION_FACTOR:-1} + # KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: ${KAFKA_REPLICATION_FACTOR:-1} + # CLUSTER_ID: ${KAFKA_CLUSTER_ID:-MkU3OEVBNTcwNTJENDM2Qk} + # volumes: + # - kafka_data:/var/lib/kafka/data + # networks: + # - astron-agent-network + # restart: always + # healthcheck: + # test: ["CMD-SHELL", "netstat -tulpn | grep 29092 || exit 1"] + # interval: ${HEALTH_CHECK_INTERVAL:-30s} + # timeout: ${HEALTH_CHECK_TIMEOUT:-10s} + # retries: ${HEALTH_CHECK_RETRIES:-60} # MinIO Object Storage minio: @@ -137,7 +134,7 @@ services: # Tenant Service core-tenant: - image: ghcr.io/iflytek/astron-agent/core-tenant:latest + image: ghcr.io/iflytek/astron-agent/core-tenant:${ASTRON_AGENT_VERSION:-latest} container_name: astron-agent-core-tenant environment: SERVICE_PORT: "${CORE_TENANT_PORT:-5052}" @@ -156,10 +153,6 @@ services: condition: service_healthy redis: condition: service_healthy - elasticsearch: - condition: service_healthy - kafka: - condition: service_healthy minio: condition: service_healthy volumes: @@ -173,7 +166,7 @@ services: # Memory Database Service core-database: - image: ghcr.io/iflytek/astron-agent/core-database:latest + image: ghcr.io/iflytek/astron-agent/core-database:${ASTRON_AGENT_VERSION:-latest} container_name: astron-agent-core-database environment: SERVICE_PORT: "${CORE_DATABASE_PORT:-7990}" @@ -191,10 +184,6 @@ services: condition: service_healthy redis: condition: service_healthy - elasticsearch: - condition: service_healthy - kafka: - condition: service_healthy minio: condition: service_healthy volumes: @@ -206,12 +195,13 @@ services: # RPA Plugin Service core-rpa: - image: ghcr.io/iflytek/astron-agent/core-rpa:latest + image: ghcr.io/iflytek/astron-agent/core-rpa:${ASTRON_AGENT_VERSION:-latest} container_name: astron-agent-core-rpa environment: SERVICE_PORT: "${CORE_RPA_PORT:-17198}" OTLP_ENDPOINT: "${OTLP_ENDPOINT:-127.0.0.1:4317}" OTLP_ENABLE: "${OTLP_ENABLE:-0}" + KAFKA_ENABLE: "${KAFKA_ENABLE:-0}" KAFKA_SERVERS: "${KAFKA_SERVERS:-kafka:29092}" XIAOWU_RPA_TASK_CREATE_URL: "${XIAOWU_RPA_TASK_CREATE_URL:-https://newapi.iflyrpa.com/api/rpa-openapi/workflows/execute-async}" XIAOWU_RPA_TASK_QUERY_URL: "${XIAOWU_RPA_TASK_QUERY_URL:-https://newapi.iflyrpa.com/api/rpa-openapi/executions}" @@ -222,10 +212,6 @@ services: condition: service_healthy redis: condition: service_healthy - elasticsearch: - condition: service_healthy - kafka: - condition: service_healthy minio: condition: service_healthy volumes: @@ -237,7 +223,7 @@ services: # Link Plugin Service core-link: - image: ghcr.io/iflytek/astron-agent/core-link:latest + image: ghcr.io/iflytek/astron-agent/core-link:${ASTRON_AGENT_VERSION:-latest} container_name: astron-agent-core-link environment: SERVICE_PORT: "${CORE_LINK_PORT:-18888}" @@ -252,6 +238,7 @@ services: REDIS_PASSWORD: "${REDIS_PASSWORD}" OTLP_ENDPOINT: "${OTLP_ENDPOINT:-127.0.0.1:4317}" OTLP_ENABLE: "${OTLP_ENABLE:-0}" + KAFKA_ENABLE: "${KAFKA_ENABLE:-0}" KAFKA_SERVERS: "${KAFKA_SERVERS:-kafka:29092}" depends_on: postgres: @@ -260,10 +247,6 @@ services: condition: service_healthy redis: condition: service_healthy - elasticsearch: - condition: service_healthy - kafka: - condition: service_healthy minio: condition: service_healthy volumes: @@ -275,7 +258,7 @@ services: # AI Tools Plugin Service core-aitools: - image: ghcr.io/iflytek/astron-agent/core-aitools:latest + image: ghcr.io/iflytek/astron-agent/core-aitools:${ASTRON_AGENT_VERSION:-latest} container_name: astron-agent-core-aitools environment: SERVICE_PORT: "${CORE_AITOOLS_PORT:-18668}" @@ -286,6 +269,7 @@ services: OSS_BUCKET_NAME: "${OSS_BUCKET_NAME}" OSS_DOWNLOAD_HOST: "${OSS_REMOTE_ENDPOINT}" OSS_TTL: "${OSS_TTL:-157788000}" + KAFKA_ENABLE: "${KAFKA_ENABLE:-0}" KAFKA_SERVERS: "${KAFKA_SERVERS:-kafka:29092}" AI_APP_ID: "${PLATFORM_APP_ID}" AI_API_KEY: "${PLATFORM_API_KEY}" @@ -297,10 +281,6 @@ services: condition: service_healthy redis: condition: service_healthy - elasticsearch: - condition: service_healthy - kafka: - condition: service_healthy minio: condition: service_healthy volumes: @@ -312,7 +292,7 @@ services: # Agent Service core-agent: - image: ghcr.io/iflytek/astron-agent/core-agent:latest + image: ghcr.io/iflytek/astron-agent/core-agent:${ASTRON_AGENT_VERSION:-latest} container_name: astron-agent-core-agent environment: SERVICE_LOCATION: "${SERVICE_LOCATION:-hf}" @@ -342,6 +322,7 @@ services: OTLP_TRACE_SCHEDULE_DELAY_MILLIS: "${OTLP_TRACE_SCHEDULE_DELAY_MILLIS:-3000}" OTLP_TRACE_MAX_EXPORT_BATCH_SIZE: "${OTLP_TRACE_MAX_EXPORT_BATCH_SIZE:-2048}" OTLP_TRACE_EXPORT_TIMEOUT_MILLIS: "${OTLP_TRACE_EXPORT_TIMEOUT_MILLIS:-3000}" + KAFKA_ENABLE: "${KAFKA_ENABLE:-0}" KAFKA_SERVERS: "${KAFKA_SERVERS:-kafka:29092}" KAFKA_TIMEOUT: "${KAFKA_TIMEOUT:-60}" KAFKA_TOPIC: "${AGENT_KAFKA_TOPIC:-spark-agent-builder}" @@ -364,10 +345,6 @@ services: condition: service_healthy redis: condition: service_healthy - elasticsearch: - condition: service_healthy - kafka: - condition: service_healthy minio: condition: service_healthy volumes: @@ -378,7 +355,7 @@ services: # Knowledge Base Service core-knowledge: - image: ghcr.io/iflytek/astron-agent/core-knowledge:latest + image: ghcr.io/iflytek/astron-agent/core-knowledge:${ASTRON_AGENT_VERSION:-latest} container_name: astron-agent-core-knowledge environment: SERVICE_PORT: "${CORE_KNOWLEDGE_PORT:-20010}" @@ -397,10 +374,6 @@ services: condition: service_healthy redis: condition: service_healthy - elasticsearch: - condition: service_healthy - kafka: - condition: service_healthy minio: condition: service_healthy volumes: @@ -412,7 +385,7 @@ services: # Workflow Service core-workflow: - image: ghcr.io/iflytek/astron-agent/core-workflow:latest + image: ghcr.io/iflytek/astron-agent/core-workflow:${ASTRON_AGENT_VERSION:-latest} container_name: astron-agent-core-workflow environment: RUNTIME_ENV: "${RUNTIME_ENV:-dev}" @@ -443,6 +416,7 @@ services: OSS_BUCKET_NAME: "${OSS_BUCKET_NAME}" OSS_DOWNLOAD_HOST: "${OSS_REMOTE_ENDPOINT}" OSS_TTL: "${OSS_TTL:-157788000}" + KAFKA_ENABLE: "${KAFKA_ENABLE:-0}" KAFKA_SERVERS: "${KAFKA_SERVERS:-kafka:29092}" KAFKA_TIMEOUT: "${KAFKA_TIMEOUT:-60}" KAFKA_TOPIC: "${WORKFLOW_KAFKA_TOPIC:-spark-agent-builder}" @@ -461,10 +435,6 @@ services: condition: service_healthy redis: condition: service_healthy - elasticsearch: - condition: service_healthy - kafka: - condition: service_healthy minio: condition: service_healthy volumes: @@ -501,7 +471,7 @@ services: # Console Frontend console-frontend: - image: ghcr.io/iflytek/astron-agent/console-frontend:latest + image: ghcr.io/iflytek/astron-agent/console-frontend:${ASTRON_AGENT_VERSION:-latest} container_name: astron-agent-console-frontend environment: CONSOLE_CASDOOR_URL: "${CONSOLE_CASDOOR_URL:-}" @@ -510,15 +480,13 @@ services: CONSOLE_CASDOOR_ORG: "${CONSOLE_CASDOOR_ORG:-}" expose: - "1881" - depends_on: - - casdoor networks: - astron-agent-network restart: always # Console Hub Service console-hub: - image: ghcr.io/iflytek/astron-agent/console-hub:latest + image: ghcr.io/iflytek/astron-agent/console-hub:${ASTRON_AGENT_VERSION:-latest} container_name: astron-agent-console-hub environment: CONSOLE_CASDOOR_URL: "${CONSOLE_CASDOOR_URL:-}" @@ -570,6 +538,7 @@ services: APP_URL: "${APP_URL:-}" KNOWLEDGE_URL: "${KNOWLEDGE_URL:-}" TOOL_URL: "${TOOL_URL:-}" + TOOL_RPA_URL: "${TOOL_RPA_URL:-}" WORKFLOW_URL: "${WORKFLOW_URL:-}" SPARK_DB_URL: "${SPARK_DB_URL:-}" LOCAL_MODEL_URL: "${LOCAL_MODEL_URL:-}" @@ -598,18 +567,12 @@ services: expose: - "8080" depends_on: - casdoor: - condition: service_started postgres: condition: service_healthy mysql: condition: service_healthy redis: condition: service_healthy - elasticsearch: - condition: service_healthy - kafka: - condition: service_healthy minio: condition: service_healthy networks: @@ -622,9 +585,6 @@ services: networks: astron-agent-network: driver: bridge - ipam: - config: - - subnet: ${NETWORK_SUBNET:-172.40.0.0/16} # ============================================================================ # Volume Configuration diff --git a/docker/astronAgent/mysql/workflow.sql b/docker/astronAgent/mysql/workflow.sql index 377770ad0bd1230e1add92fab8606be4155a1f96..259c3e083ac0ba5c9e64bc883c8112689b4496d5 100644 --- a/docker/astronAgent/mysql/workflow.sql +++ b/docker/astronAgent/mysql/workflow.sql @@ -57,7 +57,6 @@ CREATE TABLE `flow` ( `release_data` mediumtext COMMENT '发布后的数据', `description` varchar(1024) DEFAULT NULL, `version` varchar(128) DEFAULT '' COMMENT '协议版本', - `status` tinyint(1) NOT NULL COMMENT 'flow的状态,0是草稿,1是发布', `release_status` tinyint(4) DEFAULT NULL COMMENT '发布状态或值', `app_id` varchar(255) DEFAULT NULL COMMENT 'app_id', `source` tinyint(4) DEFAULT '0' COMMENT '来源', diff --git a/docker/ragflow/docker-compose.yml b/docker/ragflow/docker-compose.yml index ace761e8bc391e6f5500967f77a73663c840d895..9459d1e1b686702e3f4a3a094e08715bedf5fe40 100644 --- a/docker/ragflow/docker-compose.yml +++ b/docker/ragflow/docker-compose.yml @@ -25,8 +25,8 @@ services: container_name: ragflow-server ports: - ${SVR_HTTP_PORT}:9380 - - 10080:80 - - 10443:443 + - 18080:80 + - 18443:443 - 5678:5678 - 5679:5679 - 9382:9382 # entry for MCP (host_port:docker_port). The docker_port must match the value you set for `mcp-port` above. diff --git a/docs/DEPLOYMENT_GUIDE_zh.md b/docs/DEPLOYMENT_GUIDE_zh.md index 7ae770af93513208156a2f5d532f7afb8ed72b61..49fe3d56f25151e59c80f6f65a9c0bcbda32e603 100644 --- a/docs/DEPLOYMENT_GUIDE_zh.md +++ b/docs/DEPLOYMENT_GUIDE_zh.md @@ -48,7 +48,7 @@ docker compose logs -f ragflow ``` **访问地址:** -- RagFlow Web界面:http://localhost:10080 +- RagFlow Web界面:http://localhost:18080 **模型配置步骤:** 1. 点击头像进入 **Model Providers(模型提供商)** 页面,选择 **Add Model(添加模型)**,填写对应的 **API 地址** 和 **API Key**,分别添加 **Chat 模型** 和 **Embedding 模型**。 @@ -87,14 +87,14 @@ vim .env ```env # RAGFlow配置 -RAGFLOW_BASE_URL=http://localhost:10080 +RAGFLOW_BASE_URL=http://localhost:18080 RAGFLOW_API_TOKEN=ragflow-your-api-token-here RAGFLOW_TIMEOUT=60 RAGFLOW_DEFAULT_GROUP=星辰知识库 ``` **获取 RagFlow API Token:** -1. 访问 RagFlow Web界面:http://localhost:10080 +1. 访问 RagFlow Web界面:http://localhost:18080 2. 登录并点击头像进入用户设置 3. 点击API生成 API KEY 4. 将生成的 API KEY 更新到.env文件中的RAGFLOW_API_TOKEN @@ -164,41 +164,9 @@ HOST_BASE_ADDRESS=http://localhost - 如果您使用域名访问,请将 `localhost` 替换为您的域名 - 确保 nginx 和 minio 的端口已正确开放 -#### 2.5 配置 Casdoor 认证服务 - -编辑 docker/astronAgent/.env 文件,配置 Casdoor 连接信息: - -```env -# Casdoor配置 -CONSOLE_CASDOOR_URL=http://localhost:8000 -CONSOLE_CASDOOR_ID=astron-agent-client -CONSOLE_CASDOOR_APP=astron-agent-app -CONSOLE_CASDOOR_ORG=built-in -``` - -**说明:** -- `CONSOLE_CASDOOR_URL`: Casdoor 服务地址 -- 默认使用内置的应用配置 (`astron-agent-app`) 和组织 (`built-in`) - -**如果修改了 Casdoor 服务地址或 Nginx 端口,需要同步修改回调地址:** - -编辑 `docker/astronAgent/casdoor/conf/init_data.json` 文件,修改 `redirectUris`: - -```json -"redirectUris": [ - "http://your-domain/callback" -] -``` - -**回调地址配置示例:** -- 如果 Nginx 端口为 `80`: `http://your-domain/callback` -- 如果 Nginx 端口为 `888`: `http://your-domain:888/callback` -- 如果使用 localhost: `http://localhost/callback` (默认配置) - - ### 第三步:启动 AstronAgent 核心服务(包含 Casdoor 认证服务) -启动 AstronAgent 服务请运行我们的 [docker-compose.yaml](/docker/astronAgent/docker-compose.yaml) 文件。**该文件已通过 `include` 机制集成了 Casdoor 认证服务**,会自动启动 Casdoor 及其 MySQL 数据库。 +启动 AstronAgent 服务请运行我们的 [docker-compose.yaml](/docker/astronAgent/docker-compose.yaml) 文件。**该文件已通过 `include` 机制集成了 Casdoor 认证服务**,会自动启动 Casdoor。 ```bash # 进入 astronAgent 目录 @@ -214,6 +182,9 @@ docker compose ps docker compose logs -f ``` +**说明:** +- Casdoor默认的登录账户名:`admin`,密码:`123` + ### 第四步:修改 Casdoor 认证(可选) 您可以根据需要在 Casdoor 中创建新的应用和组织,并将配置信息更新到 `.env` 文件中(已存在默认组织和应用)。 @@ -272,7 +243,7 @@ docker compose restart console-frontend console-hub - **Casdoor 管理界面**:http://localhost:8000 ### 知识库服务 -- **RagFlow Web界面**:http://localhost:10080 +- **RagFlow Web界面**:http://localhost:18080 ### AstronAgent 核心服务 - **控制台前端(nginx代理)**:http://localhost/