| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- 'use strict';
- const axios = require('axios');
- const FILES_PATH = '/api/v1/files';
- const FILE_ACCESS_PATH = '/api/v1/files/access';
- const DEFAULT_TIMEOUT = 120000;
- /**
- * 纵横图纸接口客户端。
- *
- * 推荐传入 app.config.pdfDrawing:
- * new ZhDrawing(ctx.app.config.pdfDrawing)
- */
- class ZhDrawing {
- /**
- * @param {Object} config 接口配置
- * @param {String} config.baseUrl 纵横图纸访问地址
- * @param {String} config.token 外部 API 访问凭证
- * @param {Number} [config.timeout=120000] 请求超时时间,单位毫秒
- * @param {Object} [httpClient=axios] HTTP 客户端,主要用于单元测试注入
- */
- constructor(config = {}, httpClient = axios) {
- if (typeof config.baseUrl !== 'string' || !config.baseUrl.trim()) {
- throw new TypeError('pdfDrawing.baseUrl 不能为空');
- }
- if (typeof config.token !== 'string' || !config.token.trim()) {
- throw new TypeError('pdfDrawing.token 不能为空');
- }
- if (!httpClient || typeof httpClient.post !== 'function') {
- throw new TypeError('httpClient 必须提供 post 方法');
- }
- this.baseUrl = config.baseUrl.trim().replace(/\/+$/, '');
- this.token = config.token.trim();
- this.timeout = Number(config.timeout) > 0 ? Number(config.timeout) : DEFAULT_TIMEOUT;
- this.httpClient = httpClient;
- }
- /**
- * 读取 PDF 图纸数据,返回图纸 ID 与访问地址等信息。
- *
- * @param {String} file 可下载的 PDF 文件地址
- * @param {String} [filename] 文件名称;传入后以该名称为准
- * @return {Promise<Object>} 接口响应数据
- */
- async createFile(file, filename) {
- const payload = {
- file: this._requiredString(file, 'file'),
- };
- const normalizedFilename = this._optionalString(filename, 'filename');
- if (normalizedFilename) {
- payload.filename = normalizedFilename;
- }
- return this._post(FILES_PATH, payload);
- }
- /**
- * 为指定图纸签发短期可编辑访问凭证。
- *
- * @param {String} fileId 图纸 ID
- * @return {Promise<Object>} 接口响应数据
- */
- async createEditableAccess(fileId) {
- const payload = {
- file_id: this._requiredString(fileId, 'fileId'),
- };
- return this._post(FILE_ACCESS_PATH, payload);
- }
- /** 按传入文件顺序查找包含图表号的首个文件;未找到返回 { file_id: null }。 */
- async findDrawing(fileIds, drawingNumber) {
- if (!Array.isArray(fileIds) || !fileIds.length || fileIds.length > 100) {
- throw new TypeError('fileIds 必须为包含 1–100 个文件 ID 的数组');
- }
- return this._post('/api/v1/drawings/find', {
- file_id: fileIds.map(id => this._requiredString(id, 'fileId')),
- drawing_number: this._requiredString(drawingNumber, 'drawingNumber'),
- });
- }
- /** 标记删除图纸,立即停止访问,保留30天后后台清理;调用方应先取得用户确认。 */
- async deleteFile(fileId) {
- return this._post('/api/v1/files/delete', {
- file_id: this._requiredString(fileId, 'fileId'),
- });
- }
- /**
- * 将接口返回的相对 document_path 转换为可直接访问的完整地址。
- *
- * @param {String} documentPath 接口返回的 document_path
- * @return {String} 完整访问地址
- */
- resolveDocumentUrl(documentPath) {
- const path = this._requiredString(documentPath, 'documentPath');
- if (/^https?:\/\//i.test(path)) {
- return path;
- }
- return `${this.baseUrl}/${path.replace(/^\/+/, '')}`;
- }
- async _post(path, payload) {
- try {
- const response = await this.httpClient.post(
- `${this.baseUrl}${path}`,
- Object.assign({}, payload, { token: this.token }),
- {
- headers: {
- 'Content-Type': 'application/json',
- },
- timeout: this.timeout,
- }
- );
- return response.data;
- } catch (error) {
- throw this._normalizeError(error);
- }
- }
- _normalizeError(error) {
- const response = error && error.response;
- const responseData = response && response.data;
- const detail = responseData && responseData.detail;
- let message = error && error.message ? error.message : '纵横图纸接口请求失败';
- if (typeof detail === 'string' && detail) {
- message = detail;
- } else if (detail !== undefined) {
- try {
- message = JSON.stringify(detail);
- } catch (jsonError) {
- message = '纵横图纸接口请求失败';
- }
- }
- const normalizedError = new Error(message);
- normalizedError.name = 'ZhDrawingError';
- normalizedError.status = response && response.status;
- normalizedError.detail = detail;
- normalizedError.code = error && error.code;
- normalizedError.originalError = error;
- return normalizedError;
- }
- _requiredString(value, fieldName) {
- if (typeof value !== 'string' || !value.trim()) {
- throw new TypeError(`${fieldName} 不能为空`);
- }
- return value.trim();
- }
- _optionalString(value, fieldName) {
- if (value === undefined || value === null || value === '') {
- return '';
- }
- if (typeof value !== 'string') {
- throw new TypeError(`${fieldName} 必须是字符串`);
- }
- return value.trim();
- }
- }
- module.exports = ZhDrawing;
|