From c4d7079ac30b4ed0393c2dc831627825c7a545d6 Mon Sep 17 00:00:00 2001
From: wangrong <wangrong@shsening.com>
Date: 星期一, 10 八月 2026 18:51:37 +0800
Subject: [PATCH] 增加监控点每日抓图
---
src/modules/monitor/service/ys7.ts | 314 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 308 insertions(+), 6 deletions(-)
diff --git a/src/modules/monitor/service/ys7.ts b/src/modules/monitor/service/ys7.ts
index 91037e3..bbdfaff 100644
--- a/src/modules/monitor/service/ys7.ts
+++ b/src/modules/monitor/service/ys7.ts
@@ -5,6 +5,7 @@
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
+
interface Ys7TokenData {
accessToken: string;
/** 钀ょ煶杩斿洖鐨勬绉掔骇杩囨湡鏃堕棿鎴� */
@@ -37,13 +38,11 @@
private async fetchAndSaveRemote(): Promise<Ys7TokenData> {
const appKey_result = await this.baseSysParamEntity.findOneBy({ keyName: 'ys7.appKey' });
const appSecret_result = await this.baseSysParamEntity.findOneBy({ keyName: 'ys7.appSecret' });
-
if (!appKey_result || !appSecret_result) {
throw new Error(
'钀ょ煶浜� appKey/appSecret 鏈厤缃紝璇峰湪銆愮郴缁熷弬鏁般�戜腑缁存姢 ys7.appKey / ys7.appSecret'
);
}
-
const { data: res } = await axios.post(
'https://open.ys7.com/api/lapp/token/get',
new URLSearchParams({ appKey: appKey_result.data, appSecret: appSecret_result.data }),
@@ -52,7 +51,6 @@
timeout: 8000,
}
);
-
if (String(res.code) !== '200') {
throw new Error(`钀ょ煶浜戣幏鍙� Token 澶辫触锛�${res.msg}锛坈ode: ${res.code}锛塦);
}
@@ -61,8 +59,6 @@
accessToken: res.data.accessToken,
expireTime: res.data.expireTime,
};
-
- // 鍐欏洖绯荤粺鍙傛暟琛紙Cool-Admin 鑷甫 upsert锛�
const token = await this.baseSysParamEntity.findOneBy({ keyName: 'ys7.accessToken' });
this.baseSysParamEntity.save({
...token,
@@ -70,7 +66,313 @@
updateTime: new Date(),
}).catch(() => {
// 蹇界暐鍐欏洖澶辫触
- });
+ });
return tokenData;
}
+
+ async getSpaceID(): Promise<string> {
+ const entity = await this.baseSysParamEntity.findOneBy({ keyName: 'ys7.storageSpaceID' });
+ if (!entity ||
+ !entity.updateTime ||
+ Date.now() - new Date(entity.updateTime).getTime() >
+ 6 * 24 * 60 * 60 * 1000) {
+ const spaceId = await this.createCaptureSpace();
+ await this.baseSysParamEntity.save({
+ id: entity?.id,
+ keyName: 'ys7.storageSpaceID',
+ data: spaceId,
+ updateTime: new Date(),
+ });
+ return spaceId;
+ }
+ return entity!.data as string;
+ }
+
+ /**
+ * 鍒涘缓钀ょ煶浜戙�愯澶囨姄鍥俱�戝瓨鍌ㄧ┖闂�
+ * - spaceName 鍙栬嚜绯荤粺鍙傛暟 ys7.spaceName
+ * - 杩囨湡澶╂暟榛樿 7 澶�
+ * - 鍒涘缓鎴愬姛鍚� storageSpaceID 鍐欏叆 ys7.storageSpaceID
+ * - 璋冪敤钀ょ煶浜戠┖闂村垱寤烘帴鍙o細https://open.ys7.com/api/service/open/storage/engine/space
+ * - 鎺ュ彛璇存槑鍦板潃锛歨ttps://open.ys7.com/help/5236
+ * - 灏嗗垱寤哄ソ鐨勫瓨鍌ㄧ┖闂碔D瀛樺叆鍙傛暟锛歽s7.storageSpaceID
+ */
+ async createCaptureSpace(expireDays = 7): Promise<string> {
+ // 1. accessToken
+ const tokenEntity = await this.baseSysParamEntity.findOneBy({ keyName: 'ys7.accessToken' });
+ if (!tokenEntity?.data) {
+ console.error('[Ys7Service] ys7.accessToken 涓虹┖');
+ throw new Error('ys7.accessToken 涓虹┖');
+ }
+ const accessToken = String(tokenEntity.data).trim();
+
+ // 2. spaceName
+ const spaceEntity = await this.baseSysParamEntity.findOneBy({ keyName: 'ys7.spaceName' });
+ if (!spaceEntity?.data) {
+ console.error('[Ys7Service] ys7.spaceName 鏈厤缃�');
+ throw new Error('ys7.spaceName 鏈厤缃�');
+ }
+ const spaceName = String(spaceEntity.data).trim();
+ // 4. 钀ょ煶渚ф槸鍚﹀凡瀛樺湪鍚屽悕绌洪棿
+ const existId = await this.getSpaceIdByName(accessToken, spaceName);
+ if (existId) {
+ console.log('[Ys7Service] 钀ょ煶渚у凡瀛樺湪鍚屽悕绌洪棿锛宻paceId=%s', existId);
+ await this.saveStorageSpaceID(existId);
+ return existId;
+ }
+ // 5. 鐪熸鍒涘缓
+ const params = new URLSearchParams({
+ bizType: 'capture',
+ expireDays: String(expireDays),
+ spaceName,
+ storageType: '1',
+ });
+
+ let res: any;
+ try {
+ const resp = await axios.post(
+ 'https://open.ys7.com/api/service/open/storage/engine/space',
+ params,
+ {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ accessToken,
+ },
+ timeout: 8000,
+ }
+ );
+ res = resp.data;
+ } catch (err: any) {
+ console.error('[Ys7Service] 钀ょ煶鎺ュ彛璇锋眰澶辫触');
+ if (err.response) {
+ console.error('[Ys7Service] RESPONSE BODY=%s', JSON.stringify(err.response.data));
+ } else {
+ console.error('[Ys7Service] ERROR MSG=%s', err.message);
+ }
+ throw err;
+ }
+ // 6. 鏍¢獙钀ょ煶涓氬姟杩斿洖
+ if (!res || res.meta?.code !== 200) {
+ console.error('[Ys7Service] 钀ょ煶鍒涘缓绌洪棿涓氬姟澶辫触: %s', JSON.stringify(res?.meta));
+ throw new Error(`钀ょ煶鍒涘缓绌洪棿澶辫触: ${JSON.stringify(res?.meta)}`);
+ }
+ const storageSpaceID = String(res.data); // data 灏辨槸 spaceId
+ // 7. 淇濆瓨鍒扮郴缁熷弬鏁�
+ await this.saveStorageSpaceID(storageSpaceID);
+ return storageSpaceID;
+ }
+
+ /**
+ * 淇敼钀ょ煶浜戙�愯澶囨姄鍥俱�戝瓨鍌ㄧ┖闂�
+ * - spaceId 鍙栬嚜 ys7.storageSpaceID
+ * - accessToken 鍙栬嚜 ys7.accessToken
+ * - 榛樿杩囨湡澶╂暟 7 澶�
+ */
+ async updateCaptureSpace(expireDays = 7): Promise<boolean> {
+ // 1. accessToken
+ const tokenEntity = await this.baseSysParamEntity.findOneBy({ keyName: 'ys7.accessToken' });
+ if (!tokenEntity?.data) {
+ throw new Error('钀ょ煶 accessToken 涓嶅瓨鍦紝璇峰厛鑾峰彇 Token');
+ }
+ const accessToken = tokenEntity.data as string;
+
+ // 2. spaceId
+ const spaceEntity = await this.baseSysParamEntity.findOneBy({ keyName: 'ys7.storageSpaceID' });
+ if (!spaceEntity?.data) {
+ throw new Error('钀ょ煶 storageSpaceID 涓嶅瓨鍦紝璇峰厛鍒涘缓鎶撳浘绌洪棿');
+ }
+ const spaceId = Number(spaceEntity.data);
+
+ // 3. 缁勮鍙傛暟锛圥UT 浣跨敤 URLSearchParams锛�
+ const params = new URLSearchParams();
+ params.append('spaceId', String(spaceId));
+ params.append('expireDays', String(expireDays));
+
+ const url = 'https://open.ys7.com/api/service/open/storage/engine/space';
+ const { data: res } = await axios.put(url, params, {
+ headers: {
+ accessToken,
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ timeout: 8000,
+ });
+ if (res.meta?.code !== 200) {
+ throw new Error(
+ `钀ょ煶浜戜慨鏀瑰瓨鍌ㄧ┖闂村け璐ワ細${res.meta?.message}锛坈ode: ${res.meta?.code}锛塦
+ );
+ }
+ if (res.data) {
+ this.baseSysParamEntity.save({
+ ...spaceEntity,
+ updateTime: new Date(),
+ }).catch(() => {
+ // 蹇界暐鍐欏洖澶辫触
+ });
+ }
+ return !!res.data;
+ }
+
+ /**
+ * 鍒犻櫎钀ょ煶浜戙�愯澶囨姄鍥俱�戝瓨鍌ㄧ┖闂�
+ * - spaceId 鍙栬嚜 ys7.storageSpaceID
+ * - accessToken 鍙栬嚜 ys7.accessToken
+ * - 鍒犻櫎鎴愬姛鍚庯紝娓呯┖ ys7.storageSpaceID
+ */
+ async deleteCaptureSpace(): Promise<boolean> {
+ // 1. accessToken
+ const tokenEntity = await this.baseSysParamEntity.findOneBy({ keyName: 'ys7.accessToken' });
+ if (!tokenEntity?.data) {
+ throw new Error('钀ょ煶 accessToken 涓嶅瓨鍦紝璇峰厛鑾峰彇 Token');
+ }
+ const accessToken = tokenEntity.data as string;
+
+ // 2. spaceId
+ const spaceEntity = await this.baseSysParamEntity.findOneBy({ keyName: 'ys7.storageSpaceID' });
+ if (!spaceEntity?.data) {
+ throw new Error('钀ょ煶 storageSpaceID 涓嶅瓨鍦紝鏃犳硶鍒犻櫎');
+ }
+ const spaceId = Number(spaceEntity.data);
+
+ // 3. DELETE 璇锋眰锛坆ody 浣跨敤 URLSearchParams锛�
+ const params = new URLSearchParams();
+ params.append('spaceId', String(spaceId));
+
+ const url = 'https://open.ys7.com/api/service/open/storage/engine/space';
+ const { data: res } = await axios.delete(url, {
+ headers: {
+ accessToken,
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ data: params.toString(),
+ timeout: 8000,
+ });
+ if (res.meta?.code !== 200) {
+ throw new Error(
+ `钀ょ煶浜戝垹闄ゅ瓨鍌ㄧ┖闂村け璐ワ細${res.meta?.message}锛坈ode: ${res.meta?.code}锛塦
+ );
+ }
+ // 4. 娓呯悊鏈湴鍙傛暟
+ spaceEntity.data = '';
+ spaceEntity.updateTime = new Date();
+ await this.baseSysParamEntity.save(spaceEntity);
+
+ return !!res.data;
+ }
+
+ /**
+ * 鏍规嵁 spaceName 鏌ヨ钀ょ煶鏄惁宸插瓨鍦ㄣ�愯澶囨姄鍥俱�戠┖闂�
+ * 浣跨敤瀹樻柟 listById 鎺ュ彛锛屾敮鎸佺炕椤�
+ * 杩斿洖 storageSpaceID 鎴� null
+ */
+ private async getSpaceIdByName(
+ accessToken: string,
+ spaceName: string
+ ): Promise<string | null> {
+
+ const url = 'https://open.ys7.com/api/service/open/storage/engine/space/listById';
+
+ // 鏌ヨ鏃堕棿绐楀彛锛氭渶杩� 30 澶╋紙钀ょ煶寮哄埗瑕佹眰锛�
+ const endTime = new Date();
+ const startTime = new Date(endTime.getTime() - 30 * 24 * 60 * 60 * 1000);
+
+ const format = (d: Date) =>
+ d.getFullYear() +
+ '-' +
+ String(d.getMonth() + 1).padStart(2, '0') +
+ '-' +
+ String(d.getDate()).padStart(2, '0') +
+ ' ' +
+ String(d.getHours()).padStart(2, '0') +
+ ':' +
+ String(d.getMinutes()).padStart(2, '0') +
+ ':' +
+ String(d.getSeconds()).padStart(2, '0');
+
+ const queryParams = new URLSearchParams({
+ startTime: format(startTime),
+ endTime: format(endTime),
+ pageSize: '50',
+ bizTypeList: 'capture', // 鍙煡璁惧鎶撳浘绌洪棿
+ });
+
+ let lastId: number | null = null;
+ let page = 1;
+
+ try {
+ while (true) {
+ if (lastId !== null) {
+ queryParams.set('lastSpaceId', String(lastId));
+ }
+
+ const fullUrl = `${url}?${queryParams.toString()}`;
+
+ const resp = await axios.get(fullUrl, {
+ headers: {
+ accessToken,
+ },
+ timeout: 8000,
+ });
+ const res = resp.data;
+ if (res?.meta?.code !== 200) {
+ console.error('[Ys7Service] 鏌ヨ绌洪棿鍒楄〃澶辫触: %s', JSON.stringify(res.meta));
+ throw new Error(`鏌ヨ钀ょ煶绌洪棿澶辫触: ${JSON.stringify(res.meta)}`);
+ }
+
+ const data = res.data || {};
+ const list = data.result || [];
+
+ // 绮剧‘鍖归厤 spaceName
+ const match = list.find(
+ (item: any) => item.spaceName === spaceName && item.bizType === 'capture'
+ );
+
+ if (match) {
+ console.log(
+ '[Ys7Service] 鉁� 鎵惧埌宸插瓨鍦ㄧ殑绌洪棿锛歴paceId=%s, spaceName=%s, bizType=%s',
+ match.spaceId,
+ match.spaceName,
+ match.bizType
+ );
+ return String(match.spaceId);
+ }
+
+ // 娌℃湁涓嬩竴椤碉紝缁堟
+ if (!data.hasNext) {
+ break;
+ }
+
+ lastId = data.lastId;
+ page++;
+ }
+ return null;
+ } catch (err: any) {
+ console.error('[Ys7Service] 鏌ヨ钀ょ煶绌洪棿寮傚父');
+ if (err.response) {
+ console.error('[Ys7Service] HTTP STATUS=%d', err.response.status);
+ console.error('[Ys7Service] RESPONSE=%s', JSON.stringify(err.response.data));
+ } else {
+ console.error('[Ys7Service] ERROR=%s', err.message);
+ }
+ throw err;
+ }
+ }
+
+ /** 鍏叡淇濆瓨鏂规硶 */
+ private async saveStorageSpaceID(spaceId: string) {
+ let e = await this.baseSysParamEntity.findOneBy({ keyName: 'ys7.storageSpaceID' });
+ if (!e) {
+ e = this.baseSysParamEntity.create({
+ keyName: 'ys7.storageSpaceID',
+ name: '钀ょ煶浜戞姄鍥剧┖闂碔D',
+ dataType: 1,
+ data: spaceId,
+ updateTime: new Date(),
+ });
+ } else {
+ e.data = spaceId;
+ e.updateTime = new Date();
+ }
+ await this.baseSysParamEntity.save(e);
+ }
+
}
\ No newline at end of file
--
Gitblit v1.9.1