v4.0.17企业微信API插件优化
This commit is contained in:
@@ -3,7 +3,10 @@ import { maskContactPhone } from './phone';
|
||||
import {
|
||||
clampWecomPluginPageSize,
|
||||
isWecomPluginEnabled,
|
||||
matchWecomPluginByApiKey,
|
||||
parseWecomPluginDateRange,
|
||||
parseWecomPluginMetricsKind,
|
||||
toWecomPluginMetricsView,
|
||||
toWecomPluginUserView,
|
||||
verifyWecomPluginApiKey,
|
||||
wecomPluginMetricsPeriod,
|
||||
@@ -23,6 +26,17 @@ describe('verifyWecomPluginApiKey', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('matchWecomPluginByApiKey', () => {
|
||||
it('returns the matching enabled instance', () => {
|
||||
const rows = [
|
||||
{ id: '1', apiKey: 'alpha-key-aaaa' },
|
||||
{ id: '2', apiKey: 'beta-key-bbbbb' },
|
||||
];
|
||||
expect(matchWecomPluginByApiKey('beta-key-bbbbb', rows)?.id).toBe('2');
|
||||
expect(matchWecomPluginByApiKey('missing', rows)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isWecomPluginEnabled', () => {
|
||||
it('requires both the switch and a non-empty key', () => {
|
||||
expect(isWecomPluginEnabled({ WECOM_PLUGIN_ENABLED: 'true', WECOM_PLUGIN_API_KEY: 'k' })).toBe(
|
||||
@@ -52,6 +66,35 @@ describe('clampWecomPluginPageSize / parseWecomPluginMetricsKind', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseWecomPluginDateRange / toWecomPluginMetricsView', () => {
|
||||
it('parses YYYY-MM-DD range with inclusive end day', () => {
|
||||
const range = parseWecomPluginDateRange('2026-09-01', '2026-09-03');
|
||||
expect(range?.gte?.toISOString()).toBe(new Date('2026-09-01T00:00:00+08:00').toISOString());
|
||||
expect(range?.lt?.toISOString()).toBe(new Date('2026-09-04T00:00:00+08:00').toISOString());
|
||||
});
|
||||
|
||||
it('exposes newStores alias on metrics stats', () => {
|
||||
const view = toWecomPluginMetricsView({
|
||||
usersTotal: 1,
|
||||
usersIncrement: 0,
|
||||
partnersTotal: 1,
|
||||
partnersIncrement: 0,
|
||||
storesTotal: 10,
|
||||
storesIncrement: 2,
|
||||
ordersTotal: 0,
|
||||
ordersIncrement: 0,
|
||||
orderAmountTotal: 0,
|
||||
orderAmountIncrement: 0,
|
||||
redeemsTotal: 0,
|
||||
redeemsIncrement: 0,
|
||||
redeemAmountTotal: 0,
|
||||
redeemAmountIncrement: 0,
|
||||
});
|
||||
expect(view.newStores).toBe(2);
|
||||
expect(view.storesIncrement).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toWecomPluginUserView', () => {
|
||||
it('masks phone and fills empty nickname', () => {
|
||||
expect(toWecomPluginUserView({ userNo: 'DK1', nickname: null, phone: '13800138000' })).toEqual({
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { maskContactPhone } from './phone';
|
||||
import { shanghaiYmd, startOfShanghaiDay } from './shanghai-date';
|
||||
import { wecomReportPeriod, type WecomReportKind, type WecomReportPeriod } from './wecom-report';
|
||||
import { addShanghaiDays, shanghaiYmd, startOfShanghaiDay } from './shanghai-date';
|
||||
import {
|
||||
wecomReportPeriod,
|
||||
type WecomReportKind,
|
||||
type WecomReportPeriod,
|
||||
type WecomReportStats,
|
||||
} from './wecom-report';
|
||||
|
||||
export const WECOM_PLUGIN_PAGE_SIZE_DEFAULT = 5;
|
||||
export const WECOM_PLUGIN_PAGE_SIZE_MAX = 10;
|
||||
@@ -53,6 +58,20 @@ export function isWecomPluginEnabled(env: {
|
||||
return env.WECOM_PLUGIN_ENABLED === 'true' && Boolean(String(env.WECOM_PLUGIN_API_KEY ?? '').trim());
|
||||
}
|
||||
|
||||
/** 在少量启用实例中做常量时间匹配(长度不等仍会先失败) */
|
||||
export function matchWecomPluginByApiKey<T extends { apiKey: string }>(
|
||||
provided: string,
|
||||
candidates: T[],
|
||||
): T | null {
|
||||
const got = String(provided ?? '').trim();
|
||||
if (!got) return null;
|
||||
let hit: T | null = null;
|
||||
for (const row of candidates) {
|
||||
if (verifyWecomPluginApiKey(got, row.apiKey)) hit = row;
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
export function wecomPluginMetricsPeriod(
|
||||
kind: WecomPluginMetricsKind,
|
||||
now = new Date(),
|
||||
@@ -74,6 +93,45 @@ export function wecomPluginMetricsPeriod(
|
||||
return { ...period, kind };
|
||||
}
|
||||
|
||||
export type WecomPluginDateRange = { gte?: Date; lt?: Date };
|
||||
|
||||
/** 插件时间筛选:from/to 支持 YYYY-MM-DD 或 ISO;日期含当天全天 */
|
||||
export function parseWecomPluginDateRange(
|
||||
fromRaw?: string | null,
|
||||
toRaw?: string | null,
|
||||
): WecomPluginDateRange | undefined {
|
||||
const from = parseWecomPluginDate(fromRaw);
|
||||
const to = parseWecomPluginDate(toRaw);
|
||||
if (!from && !to) return undefined;
|
||||
const range: WecomPluginDateRange = {};
|
||||
if (from) range.gte = from;
|
||||
if (to) {
|
||||
range.lt = isWecomPluginDateOnly(toRaw) ? addShanghaiDays(startOfShanghaiDay(to), 1) : to;
|
||||
}
|
||||
return range;
|
||||
}
|
||||
|
||||
function isWecomPluginDateOnly(raw?: string | null): boolean {
|
||||
return /^\d{4}-\d{2}-\d{2}$/.test(String(raw ?? '').trim());
|
||||
}
|
||||
|
||||
function parseWecomPluginDate(raw?: string | null): Date | null {
|
||||
const v = String(raw ?? '').trim();
|
||||
if (!v) return null;
|
||||
if (/^\d{4}-\d{2}-\d{2}$/.test(v)) {
|
||||
return startOfShanghaiDay(new Date(`${v}T00:00:00+08:00`));
|
||||
}
|
||||
const d = new Date(v);
|
||||
return Number.isFinite(d.getTime()) ? d : null;
|
||||
}
|
||||
|
||||
export function toWecomPluginMetricsView(stats: WecomReportStats) {
|
||||
return {
|
||||
...stats,
|
||||
newStores: stats.storesIncrement,
|
||||
};
|
||||
}
|
||||
|
||||
export function toWecomPluginUserView(user: {
|
||||
userNo: string;
|
||||
nickname?: string | null;
|
||||
|
||||
Reference in New Issue
Block a user