Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

135 lines
3.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 工单数据库读取器
* GH-GMP-005 · M1 · Notion Sync Layer
*
* 读取半体工单数据库,解析工单属性
*/
'use strict';
const { parseAllProperties } = require('./property-parser');
/**
* 工单字段映射Notion属性名 → 工单对象键名)
* 保持与半体工单数据库schema完全一致
*/
const TICKET_FIELDS = [
'任务标题', '编号', '状态', '优先级', '负责Agent',
'开发内容', '约束', '仓库路径', '分支名', '阶段编号',
'自检结果', '审核结果', '下一轮指引', '创建时间',
];
class DBReader {
/**
* @param {object} opts
* @param {import('./client')} opts.client - NotionSyncClient实例
* @param {string} opts.databaseId - 半体工单数据库ID
* @param {object} [opts.logger]
*/
constructor({ client, databaseId, logger }) {
this.client = client;
this.databaseId = databaseId;
this.logger = logger || console;
}
/**
* 查询指定状态的工单
* @param {string} status - 如 '待开发', '开发中', '待审查'
* @returns {Promise<Array>}
*/
async queryByStatus(status) {
const filter = {
property: '状态',
select: { equals: status },
};
const sorts = [{ property: '创建时间', direction: 'descending' }];
const results = await this.client.queryDatabaseAll(
this.databaseId, filter, sorts
);
return results.map((page) => this._parseTicket(page));
}
/**
* 查询指定Agent负责的工单
* @param {string} agentName - 如 '译典A05'
* @param {string} [status] - 可选状态过滤
*/
async queryByAgent(agentName, status) {
const conditions = [
{
property: '负责Agent',
select: { equals: agentName },
},
];
if (status) {
conditions.push({
property: '状态',
select: { equals: status },
});
}
const filter = conditions.length === 1
? conditions[0]
: { and: conditions };
const results = await this.client.queryDatabaseAll(
this.databaseId, filter
);
return results.map((page) => this._parseTicket(page));
}
/**
* 查询最近更新的工单(用于轮询检测变更)
* @param {string} since - ISO 8601 时间戳
*/
async queryUpdatedSince(since) {
const filter = {
timestamp: 'last_edited_time',
last_edited_time: { after: since },
};
const sorts = [{ timestamp: 'last_edited_time', direction: 'descending' }];
const results = await this.client.queryDatabaseAll(
this.databaseId, filter, sorts
);
return results.map((page) => this._parseTicket(page));
}
/**
* 查询待处理工单(状态=待开发 且 有负责Agent
*/
async queryPendingTickets() {
const filter = {
and: [
{ property: '状态', select: { equals: '待开发' } },
{ property: '负责Agent', select: { is_not_empty: true } },
],
};
const results = await this.client.queryDatabaseAll(
this.databaseId, filter
);
return results.map((page) => this._parseTicket(page));
}
/**
* 获取单个工单通过页面ID
*/
async getTicket(pageId) {
const page = await this.client.getPage(pageId);
return this._parseTicket(page);
}
/**
* 解析 Notion page → 工单对象
*/
_parseTicket(page) {
const props = parseAllProperties(page.properties);
return {
pageId: page.id,
url: page.url,
lastEditedTime: page.last_edited_time,
createdTime: page.created_time,
...props,
};
}
}
module.exports = DBReader;