ANTONNECT TS/JS (英语)
通过这个软件包,您可以让您的应用程序简单访问 ANT api
安装 npm 包
npm install axios
需要axios,而不包含在软件包中
npm install ant_tsconnect
这将允许您访问需要 httpclient 的 AntConnect 类(见下文)
http客户端
要连接到 ANT 环境之一, 您需要 httpclient 设置以下属性
- 客户端( d)
- 客户端 机密
- 基数url
- ưμ㼯a
- 此客户端您会传递到 AntConnect, 您可以连接到给定的 api
const httpClient = new CustomHttpClient('http://api-antcde.io', '/api/1.0', 'X', 'SECRET')
const antConnect = newAntConnect(httpClient)
认证
以下列方式访问认证方法
antConnect.httpClient.authenticate({
username: '[email protected]',
password: 'password'
})
您可以保存本地存储器或饼干的访问符并添加自定义截取器到每个请求中(见下文)
双要素授权(2fa)
如果用户启用了 2fa , 您将会收到数据错误响应
{ code: 1707747196 }
内
antConnect.users.getAuthenticatedUser()
在这种情况下,最好的方法是用错误代码处理自定义截取器中的这个错误,并用已准备好的 antConnect 请求验证您的登录令牌
antConnect.users.verifyTwoFactor({ code })
拦截器
可以创建自定义请求和响应截取器.
您可以创建具有以下功能的自定义类:
// Custom request interceptor
export function requestInterceptor(config) {
config.headers = {}
config.headers['Authorization'] = 'Bearer Client'
return config
}
// Custom response interceptor
export function responseInterceptor(response) {
// Modify the response as needed
// For example, you can extract specific data or handle errors
return response
}
然后可以将这些截取器添加到 httpclient
import { requestInterceptor } from '@/interceptors' // import
const httpClient = new CustomHttpClient(
'http://192.168.1.50:8000',
'/api/1.0',
'2',
'OEQWm6a4rsbqTSEiB2y32O2yR0J3MFlUPbZJWI9w'
)
httpClient.addRequestInterceptor(requestInterceptor) // add here
const antConnect = newAntConnect(httpClient)
创建单个实例
根据您的框架, 您整个应用程序中都有多种创建 AntConnect 实例的方法
5个(3)
// TODO 更改此选项
const httpClient = new CustomHttpClient(
'http://192.168.1.50:8000',
'/api/1.0',
'2',
'OEQWm6a4rsbqTSEiB2y32O2yR0J3MFlUPbZJWI9w'
)
httpClient.addRequestInterceptor(requestInterceptor)
const antConnect = newAntConnect(httpClient)
app.provide('antConnect', antConnect) // here we provide the instance to the whole application
通过注射我们的阴道组件 我们可以访问这样的实例:
const antConnect = inject('antConnect')
let projects = await antConnect.projects.getProjects()
中,我们获取给定用户的工程.
既然我们想把所有的项目都移到单列车上 也许最好能移到Pnpm包机上
查询表实例
这个 queryTables 方法允许您通过 connect.tables.queryTables(query)。 。 。 .
1. 选择所有栏
const query: TablesQuery = {
tables: [{
name: 'EMPLOYEES',
project: projectId,
as: 'employees',
columns: ['*'],
}],
}
2. 具体栏目,无过滤器
const query: TablesQuery = {
tables: [{
name: 'EMPLOYEES',
project: projectId,
as: 'employees',
columns: [
{ name: 'first_name' },
{ name: 'last_name' },
{ name: 'department' },
],
}],
}
3. 平等条件
const query: TablesQuery = {
tables: [{
name: 'EMPLOYEES',
project: projectId,
as: 'employees',
columns: [
{
name: 'department',
conditions: [{ operator: '=', value: 'Engineering' }],
},
{ name: 'first_name' },
{ name: 'last_name' },
],
}],
}
4. 查询-匹配多个值
const query: TablesQuery = {
tables: [{
name: 'EMPLOYEES',
project: projectId,
as: 'employees',
columns: [
{
name: 'status',
conditions: [{ operator: 'in', value: ['active', 'on_leave', 'probation'] }],
},
{ name: 'first_name' },
{ name: 'last_name' },
{ name: 'department' },
],
}],
}
5. 多重条件(AND)
const query: TablesQuery = {
tables: [{
name: 'EMPLOYEES',
project: projectId,
as: 'employees',
columns: [
{
name: 'department',
conditions: [{ operator: '=', value: 'Engineering' }],
},
{
name: 'status',
conditions: [{ operator: 'in', value: ['active', 'probation'] }],
},
{ name: 'first_name' },
{ name: 'last_name' },
],
}],
}
6. 分拣+分拣
const query: TablesQuery = {
limit: 25,
offset: 50,
tables: [{
name: 'EMPLOYEES',
project: projectId,
as: 'employees',
columns: ['*'],
sortBy: 'last_name',
sortByOrder: 'asc',
}],
}
7. 一个请求中的多个表格
const query: TablesQuery = {
tables: [
{
name: 'DEPARTMENTS',
project: projectId,
as: 'departments',
columns: ['*'],
},
{
name: 'EMPLOYEES',
project: projectId,
as: 'employees',
columns: [
{
name: 'status',
conditions: [{ operator: 'in', value: ['active'] }],
},
{ name: 'first_name' },
{ name: 'last_name' },
{ name: 'department' },
],
},
],
}
阅读结果
const response = await connect.tables.queryTables(query)
const departments = response.departments.records // records array
const employees = response.employees.records
const totalEmployees = response.employees.stats.count
支持的条件运算符
=, (中文(简体) ), !=, (中文(简体) ), >, (中文(简体) ), <, (中文(简体) ), >=, (中文(简体) ), <=, (中文(简体) ), like, (中文(简体) ), in, (中文(简体) ), not in, (中文(简体) ), between, (中文(简体) ), not between, (中文(简体) ), is null, (中文(简体) ), is not null
对于 in 编号 : not in,通过 value 作为数组 : value: ['a', 'b']。 。 。 .
对于 between 编号 : not between,通过两个元素阵列: value: [10, 50]。 。 。 .
任务查询参数
联合国文件 query 参数在 TaskService.getV2Tasks()。 。 。 .
后端: 用途 拉拉维尔纯净 用于使用 Spatie QueryBuilder 过滤.
查询结构
interface TaskQuery {
filters?: FilterObject
fields?: FieldsObject
include?: string // comma-separated relations
per_page?: number // pagination limit (default: 10)
page?: number // current page (1-indexed)
sort?: string[] // sort fields
is_task?: boolean // filter tasks vs workflows (default: true)
}
过滤器
过滤运算符( Laravel 纯度)
| 运算符 | 说明 | 示例 |
|---|---|---|
$eq | 平等 | { status: { $eq: 'open' } } |
$ne | 不相等 | { status: { $ne: 'closed' } } |
$gt | 超过 | { progress: { $gt: 50 } } |
$lt | 少于 | { progress: { $lt: 100 } } |
$gte | 大于或等于 | { due: { $gte: '2024-01-01' } } |
$lte | 少于或等于 | { due: { $lte: '2024-12-31' } } |
$in | 在数组中( OR) | { status: { $in: ['open', 'processing'] } } |
$notIn | 未在阵列中 | { status: { $notIn: ['closed', 'canceled'] } } |
$contains | 包含子字符串( 对大小写不敏感) | { title: { $contains: 'bug' } } |
$notContains | 不包含 | { title: { $notContains: 'test' } } |
$containss | 包含( 对大小写敏感) | { title: { $containss: 'BUG' } } |
$notContainss | 未包含( 对大小写敏感) | { title: { $notContainss: 'TEST' } } |
$startsWith | 从( 对大小写不敏感) 开始 | { title: { $startsWith: 'task-' } } |
$startsWiths | 以( 对大小写敏感) 开头 | { title: { $startsWiths: 'TASK-' } } |
$endsWith | 结尾( 不区分大小写) | { title: { $endsWith: '-urgent' } } |
$endsWiths | 结尾( 对大小写敏感) | { title: { $endsWiths: '-URGENT' } } |
$eqs | 相等( 对大小写敏感) | { title: { $eqs: 'Exact Match' } } |
$between | 两个值之间 | { progress: { $between: [25, 75] } } |
$notBetween | 不在两者之间 | { progress: { $notBetween: [0, 10] } } |
$null | 无效 | { assigned_to: { $null: true } } |
$notNull | 不为空 | { assigned_to: { $notNull: true } } |
$doesntHave | 关系不存在 | { type: { $doesntHave: true } } |
逻辑运算符
| 运算符 | 说明 | 示例 |
|---|---|---|
$or | 或条件(条件的组合) | { $or: [{ status: { $eq: 'open' } }, { status: { $eq: 'processing' } }] } |
$and | 和条件(条件组合) | { $and: [{ priority: { $eq: 'high' } }, { status: { $eq: 'open' } }] } |
组合运算符
多个运算符可以在同一字段合并:
{
status: {
$in: ['open', 'processing'], // include these
$notIn: ['failed'] // but exclude this
}
}
嵌入式关系过滤器
相关模型的过滤 :
{
filters: {
relationsToMe: {
source_id: { $eq: taskId }
}
}
}
可过滤的任务字段
这些字段在后端定义 Task 型号 $filterFields数字 :
| 外地 | 类型 | 说明 |
|---|---|---|
id | 乌伊德 | 任务 UUID |
title | 字符串 | 任务标题 |
description | 字符串 | 任务说明 |
number | 整数 | 任务编号 |
status | 语句 | 'open', (中文(简体) ), 'closed', (中文(简体) ), 'canceled', (中文(简体) ), 'processing', (中文(简体) ), 'executed', (中文(简体) ), 'failed', (中文(简体) ), 'inactive' |
priority | 语句 | 'low', (中文(简体) ), 'normal', (中文(简体) ), 'high', (中文(简体) ), 'urgent' |
planned_start | 约会时间 | 计划开始日期 |
planned_end | 约会时间 | 计划结束日期 |
due | 约会时间 | 应交日期 |
license | 乌伊德 | 许可 UUID |
parent | 乌伊德 | 父任务 UUID |
project | 乌伊德 | 项目 UUID |
type | 关系 | 任务类型关系 |
sbscode | 字符串 | SBS 代码参考 |
assigned_to | 乌伊德 | 指定用户 UUID |
taskProject | 关系 | 项目关系 |
is_private | 布尔 | 私有任务旗 |
is_task | 布尔 | 是任务( vs 工作流程) |
is_locked | 布尔 | 锁定任务旗 |
relations | 关系 | 外出任务关系 |
relationsToMe | 关系 | 即将到来的任务关系 |
特殊过滤字段
| 外地 | 类型 | 说明 |
|---|---|---|
label_ids | 数组 | 要过滤的标签 UUID 矩阵 |
label_operator | 字符串 | 'and' (所有标签)或 'or' (任何标签) - 默认 : 'and' |
说明:标签过滤器与纯度过滤器分开处理.
可选择字段
可以通过 fields 参数 :
id, title, description, number, status, priority, planned_start, planned_end,
due, project, license, parent, sbscode, assigned_to, created_by, position_x,
position_y, is_private, is_task, is_locked, script, trigger_id
包含( 关系)
装入相关资源 。 定义 TaskQueryBuilder::getRelations()数字 :
{
include: 'taskProject,labels,children,assignedTo,trigger,trigger.event'
}
可用关系
| 关系 | 型号 | 说明 |
|---|---|---|
taskProject | 项目 | 相关项目 |
parentTask | 任务 | 父任务 |
children | 任务 | 儿童任务 |
activities | 任务活动 | 活动日志条目 |
createdBy | 用户 | 创建任务的用户 |
assignedTo | 用户 | 指定用户 |
activities.activityUser | 用户 | 用户的活动日志 |
labels | 标签Os | 任务标签( V2) |
attachments | 任务文件 | 文件附件 |
checks | 任务检查 | 核对清单项目 |
type | 任务类型 | 任务类型 |
sbsObject | 斯布斯记录 | SBS 代码记录 |
relations | 任务关系 | 正在发展的关系 |
relations.queries | 表格查询 | 关系查询 |
relationsToMe | 任务关系 | 即将到来的关系 |
rules | 任务规则 | 任务规则 |
rules.resource | 用户/操作 | 规则资源 |
app | 资源App | 相关应用 |
trigger | 触发 | 相关触发 |
trigger.event | 活动 | 触发事件 |
assignableUsers | (计算) | 可指派的用户 |
说明数字 : assignableUsers 是一个计算的财产,而不是一个真实的关系。 专门处理的.
倾斜
{
per_page: 200, // items per page (default: 10)
page: 1 // page number (1-indexed)
}
没有 pagination 参数,所有结果都通过 ->get()。 。 。 .
使用 pagination 参数,结果使用 ->simplePaginate()。 。 。 .
排序
使用 Spatie 查询构建器排序 :
{
sort: ['created_at'] // ascending
sort: ['-created_at'] // descending (prefix with -)
sort: ['priority', '-due'] // multiple fields
}
完整示例
import qs from 'qs'
const query = qs.stringify({
filters: {
status: { $in: ['open', 'processing'] },
priority: { $notIn: ['low'] },
project: { $eq: projectId },
title: { $contains: 'bug' },
$or: [
{ assigned_to: { $eq: null } },
{ assigned_to: { $eq: currentUserId } }
],
label_ids: ['label-uuid-1', 'label-uuid-2'],
label_operator: 'or'
},
fields: {
'tasks': 'id,title,status,priority,due',
'taskProject': 'id,name',
'labels': 'id,name,color'
},
include: 'taskProject,labels,assignedTo',
per_page: 50,
page: 1,
sort: ['-priority', 'due']
})
const tasks = await taskService.getV2Tasks(licenseId, query)
URL 编码
使用 qs.stringify() 用于正确编码 :
import qs from 'qs'
// Basic usage
const query = qs.stringify(params)
// With options for complex queries
const query = qs.stringify(params, {
encodeValuesOnly: true, // don't encode bracket keys
arrayFormat: 'brackets' // arrays as foo[]=a&foo[]=b
})
响应格式
预留答复
{
data: Task[],
links: {
first: string | null,
last: string | null,
prev: string | null,
next: string | null
},
meta: {
current_page: number,
from: number,
path: string,
per_page: number,
to: number
}
}
未加入的答复
{
data: Task[]
}
App 说明app-config.json(中文(简体) )
每个ANT应用程序都可以运送 app-config.json 在它的发行捆绑。 OS和App Store读取了这个文件,以发现该应用程序对自己宣布的内容:它的版本,标签行,表格,信号主题,以及——对于AI的覆盖——它的能力.
Schema 验证
与此软件包一起出版的 JSON Schema schemas/app-config.schema.json。指向 $schema 键,用于编辑器自动补全、盘旋文件以及验证:
{
"$schema": "node_modules/@antcde/connect-ts/schemas/app-config.schema.json",
"version": "1.0.0",
"tagline": "My App",
"tables": [],
"signals": {
"topics": {}
},
"capabilities": {
"queryParams": {},
"intents": []
}
}
从包中导出整个清单的脚本类型 : AppManifest, (中文(简体) ), AppManifestCapabilities, (中文(简体) ), AppManifestQueryParam, (中文(简体) ), AppManifestIntent, (中文(简体) ), AppManifestTable, (中文(简体) ), AppManifestTopic。 。 。 .
向OS发送清单
Apps在通讯握手期间可以向OS发送其清单. 这使得表格和话题在OS上下文菜单中可见而无需额外的API调用,并跨CORS边界工作(如远程OS + 本地dev服务器).
import { useCommsClient } from '@antcde/vue-utils'
import manifest from '../app-config.json'
const comms = useCommsClient(connect, undefined, manifest)
OS通过握手ACK接收出出货单,并在通讯主机上被曝光. 任何通过列表的应用程序都会在OS上下文菜单中与其所声明的表格和主题一起出现.
表格
应用安装时会创建表格. 每个条目都宣布它所居住的表格名称(context)及其栏:
{
"tables": [
{
"name": "MY_APP_ITEMS",
"context": "project",
"master_table": true,
"columns": [
{ "name": "title", "type": "text", "required": true },
{ "name": "status", "type": "dropdown", "options_value": ["draft", "active"] }
]
}
]
}
| 外地 | 需求 | 说明 |
|---|---|---|
name | 对 | 表格名称, 应用程序中唯一的 |
context | 没有 | "project" (默认) 在安装时创建工程中的表格; "license" 在许可证一级创建它 |
master_table | 没有 | 标记应用程序的主表格( 默认) false(中文(简体) ) |
columns | 对 | 列定义( 至少一个) |
列类型 : integer, (中文(简体) ), text, (中文(简体) ), text-field, (中文(简体) ), boolean, (中文(简体) ), date, (中文(简体) ), link, (中文(简体) ), email, (中文(简体) ), dropdown, (中文(简体) ), document, (中文(简体) ), float, (中文(简体) ), sbscode, (中文(简体) ), table。列字段包括 required, (中文(简体) ), is_unique, (中文(简体) ), is_indexed (每表最多2个), default_value, (中文(简体) ), options_value (需为 dropdown, (中文(简体) ), hint,以及 field_nameA级 document 列可以添加 dms_folder,表格所有者 DMS 根下的一个文件夹路径("Inspections/Photos": 缺少的文件夹是在安装时创建的,上传到那里的地上,用户在应用程序宣布时不能更改.
专题声明
主题通过 Echo 低语频道在应用程序之间允许通用的 pub/ sub 。 每个键下 signals.topics 是话题名称( 必须匹配) [A-Za-z0-9_-]:
{
"signals": {
"topics": {
"cursor-positions": {
"scope": "project",
"description": "Live cursor positions shared between editors",
"direction": ["send", "receive"],
"schema": { "type": "object" }
}
}
}
}
| 外地 | 需求 | 说明 |
|---|---|---|
scope | 没有 | "project" (违约)或 "license" |
description | 没有 | App Store 显示的可读摘要 |
direction | 没有 | 矩阵 "send" 和(或) "receive"默认为 ["receive"] |
schema | 没有 | JSON Schema 描述有效载荷形状 |
发送和接收专题
// publish
signal.send({ topic: { name: 'cursor-positions', data: { x: 10, y: 20 } } })
// subscribe
signal.receive((s) => {
if (s.topic?.name === 'cursor-positions') {
handleCursor(s.topic.data)
}
})
OS处理扇出:当一个应用程序发布一个话题信号时,OS将它重新分配到所有其他已加载的应用程序上并低语到范围Echo频道,因此其他浏览器标签中的应用程序也接收.
能力
capabilities 声明 应用程序可以通过它的 URL 驱动它做什么 ——它读取的查询参数和它所揭露的被命名的动作(意图). AI 覆盖读取此以将一个自然语言的请求("打开套接字标签上的应用程序")变成一个带有右向查询字符串的混凝土启动. 是元数据 关于 应用程序的 URL 表面 —— 它不会改变应用程序的制作方式 .
{
"capabilities": {
"queryParams": {
"tab": {
"type": "string",
"description": "Which tab to open on load.",
"enum": ["overview", "items", "settings"]
},
"status": {
"type": "string",
"description": "Filter the list to this status.",
"enum": ["draft", "active", "archived"]
}
},
"intents": [
{ "id": "open-tab", "description": "Open the app on a specific tab", "params": ["tab"] },
{ "id": "filter-items", "description": "Open the app filtered to a status", "params": ["tab", "status"] }
]
}
}
queryParams ——由param名键入的地图. 每个条目描述一个查询参数 应用程序读取其 URL .
| 外地 | 需求 | 说明 |
|---|---|---|
type | 对 | 数值类型 - "string", (中文(简体) ), "number", (中文(简体) ), "boolean", (中文(简体) ), "date", (中文(简体) ), "time" 或者说 "datetime"。在 URL 上,一切都是一个字符串;非字符串类型正在渲染 + 验证提示 |
description | 没有 | 抛出的东西 表面到AI作为工具参数帮助——写作模型读取 |
enum | 没有 | 允许的值 。 成为硬约束,所以人工智能只能选择一个列出的值 |
multiple | 没有 | 接受多个值( 多选择, CSV 在线上)( 默认) false(中文(简体) ) |
required | 没有 | 引用应用程序是否必须提供参数( 默认) false(中文(简体) ) |
access | 没有 | "readwrite" (违约)或 "write" ——可指挥. "read" 仅限 反映 应用程序在 URL 上状态: AI 查看当前值, 确认表显示其已禁用, 但两者都无法设置 |
intents - 指定该组的行动 queryParams 成为可识别的目标 意图不增加任何行为;它指向已经存在的parms,给予AI一个标有标签的行动,以匹配针对的请求.
| 外地 | 需求 | 说明 |
|---|---|---|
id | 对 | 稳定意图标识符 |
description | 对 | 意所为. 由人工智能读取以匹配用户请求 |
params | 没有 | 名称 queryParams 此意图用途( 必须在地图中存在) |
叠加 每个可用的应用程序一个工具 从活应用程序列表:每个 queryParams 条目成为工具参数( e)enum - 受限制的选择, required 非选择性, description + 参数帮助),加上内置的线框选择器. access: "read" 参数被排除在工具计划之外。 模型如何可靠地填充 正确的参数是好的直接函数 description紧紧的 enums) 把它们视为即时工程。 您的应用程序必须读取这些参数 window.location.search并对他们采取行动.
对于当前打开的应用程序, 覆盖还读取已声明的参数 离开 uRL 并把它们作为当前状态输入到模型中,并预先填入它们的确认表 (URL 输入会话内存,则输入到提示中). 只有在您的应用程序在用户导航时保持参数同步的情况下, 宣布原约 read 当应用程序保持状态时,AI应该知道但不能命令.
资源信号
任意资源信号让app发送并接收特定域的事件(如, cat, (中文(简体) ), homeowner, (中文(简体) ), invoice(不修改核心) ChangeSignal 类型。 信号通过分屏应用在本地分布,可以选择由WebSocket(Echo)支持后端驱动的事件.
食谱1: 本地 – 在所有应用程序中发送并接收
所有分屏应用程序通过OS再分配监视器接收信号. 不需要后端 .
发送
const { signal } = comms
signal.send({
resource: {
cat: {
id: crypto.randomUUID().slice(0, 8),
action: 'created',
data: { sound: 'meow', volume: 'loud' },
},
},
})
接收( raw- 无 Echo 订阅)
signal.receive((s) => {
const cat = s.resource?.cat
if (cat) {
console.log(cat.id, cat.action, cat.data)
}
})
接收( 同时设置 Echo 订阅)
// Also sends an `observe` signal → host subscribes to Echo channel
signal.with('cat').receive((cause) => {
console.log(cause.id, cause.action, cause.data)
})
signal.send()只为本地 - 它从来不碰后端/口袋. OS再分配监视器将其转发至所有其他分屏应用程序.
signal.receive()获取所有信号( 本地 + Echo 后置) .signal.with('cat').receive()过滤器cat并订阅后端事件的回声频道.
食谱2:过Socket(Echo-backed)——对所有客户端的后端广播
只有后端模块的广播输入到插座上方。 例如,DHME公司 DhmeResourceChanged 发布 production-location 和类似类型 App.License.{id}.Resources。后端已经 无一般事件 播放自定义的应用程序类型,例如 cat因此,对于使用Repipe 1(当地)或一个专题。 以下实例 cat 仅作为占位符类型名称.
接收( 项目范围)
const { signal, context } = comms
watch(context, ({ project }, _, onCleanup) => {
if (project) {
onCleanup(
signal.with('cat', undefined, undefined, ['project']).receive((cause) => {
// cause.meta?.source === 'timeseries' (from Echo)
console.log(cause.id, cause.action, cause.data)
})
)
}
})
盖子下面发生了什么
signal.with('cat', ..., ['project'])发送一个observe向主机发出信号- 主机通话
newSignalEchoAdapter• 订阅App.Project.{projectId}.Resources - 后端广播
resource.cat.created编号 :resource.cat.updated在频道上 - Echo适配器接收到 ~ 向 Iframe 客户端发送回信号
cause.meta.source实值'timeseries'
后端边
后端模块在 App.{Project|License}.{id}.Resources 与 broadcastAs() 返回时 resource.<type>.<action> 和载荷 id 财务报告和审定财务报表 action (见 app/Modules/DHME/Realtime/DhmeResourceChanged.php 以一分计。 这个没有共享事件类,所以添加一个新的广播类型是后端更改.
内容提要
| 方法 | 分发 | 需要后端吗? | 使用大小写 |
|---|---|---|---|
signal.send() + 键 signal.receive() | 本地( 所有分屏应用程序) | 没有 | 应用对应用通信 |
signal.with('cat').receive() | 回声支持 | 是- 后端模块必须播放此类型 | 后端驱动( 默认范围) |
signal.with('cat', ..., ['project']).receive() | 回声支持( 项目范围) | 是- 后端模块必须播放此类型 | 后端驱动的实时更新 |