增加发货记录查询功能-1
This commit is contained in:
@@ -28,6 +28,7 @@ import {
|
||||
useCloudtentaclesSku,
|
||||
} from "../../../platforms/cloudtentacles/catalog-service.js";
|
||||
import { getCloudtentaclesKnapsack } from "../../../platforms/cloudtentacles/knapsack-service.js";
|
||||
import { listCloudtentaclesDeliveryRecords } from "../../../platforms/cloudtentacles/record-service.js";
|
||||
import {
|
||||
appointCloudtentaclesVirtualNumber,
|
||||
backCloudtentaclesVirtualNumber,
|
||||
@@ -59,6 +60,7 @@ import { createHttpError } from "../../../../utils/http.js";
|
||||
|
||||
import type {
|
||||
AdminCloudtentaclesCatalogQueryInput,
|
||||
AdminCloudtentaclesDeliveryRecordQueryInput,
|
||||
AdminCloudtentaclesFullFlowInput,
|
||||
AdminCloudtentaclesSendSmsCodeInput,
|
||||
AdminCloudtentaclesSkuBuyInput,
|
||||
@@ -93,6 +95,26 @@ export function listAdminCloudtentaclesSources() {
|
||||
};
|
||||
}
|
||||
|
||||
export function listAdminCloudtentaclesRecordSources() {
|
||||
const list = listCloudtentaclesSources();
|
||||
const sessions = getAllCloudtentaclesSessionStates();
|
||||
const sources = Array.isArray(list.sources) ? list.sources : [];
|
||||
|
||||
return {
|
||||
sources: sources.map((source) => {
|
||||
const key = String(source.key || "").trim();
|
||||
const session = (sessions.sessions?.[key] || {}) as JsonObject;
|
||||
return {
|
||||
key,
|
||||
label: String(source.label || source.username || key || "未命名账号").trim(),
|
||||
enabled: source.enabled !== false,
|
||||
hasToken: Boolean(String(session.token || "").trim()),
|
||||
loggedInAt: String(session.loggedInAt || "").trim(),
|
||||
};
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
export function updateAdminCloudtentaclesSourceConfig(
|
||||
payload: AdminCloudtentaclesSourceConfigInput = {}
|
||||
) {
|
||||
@@ -286,6 +308,57 @@ export async function getAdminCloudtentaclesKnapsack(
|
||||
);
|
||||
}
|
||||
|
||||
export async function listAdminCloudtentaclesDeliveryRecords(
|
||||
payload: AdminCloudtentaclesDeliveryRecordQueryInput = {}
|
||||
) {
|
||||
const context = resolveAdminCloudtentaclesSessionPayload(payload);
|
||||
const query = {
|
||||
...context,
|
||||
...pickDefined({
|
||||
page: payload.page,
|
||||
size: payload.size,
|
||||
startDate: payload.startDate,
|
||||
endDate: payload.endDate,
|
||||
recordCode: payload.recordCode,
|
||||
}),
|
||||
};
|
||||
const [records, skuList] = await Promise.all([
|
||||
listCloudtentaclesDeliveryRecords(query),
|
||||
listCloudtentaclesSku(context),
|
||||
]);
|
||||
const skuImageByName = new Map<string, {
|
||||
skuId: number;
|
||||
skuName: string;
|
||||
skuImage: string;
|
||||
}>();
|
||||
for (const sku of Array.isArray(skuList.items) ? skuList.items : []) {
|
||||
const name = normalizeSkuName(sku.name);
|
||||
const skuImage = String(sku.image || "").trim();
|
||||
if (!name || !skuImage) {
|
||||
continue;
|
||||
}
|
||||
|
||||
skuImageByName.set(name, {
|
||||
skuId: Number(sku.id || 0),
|
||||
skuName: String(sku.name || "").trim(),
|
||||
skuImage,
|
||||
});
|
||||
}
|
||||
|
||||
const recordItems: JsonObject[] = Array.isArray(records.items) ? records.items : [];
|
||||
return {
|
||||
...records,
|
||||
items: recordItems.map((record) => ({
|
||||
...record,
|
||||
...(skuImageByName.get(normalizeSkuName(record.name)) || {
|
||||
skuId: 0,
|
||||
skuName: "",
|
||||
skuImage: "",
|
||||
}),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
export async function listAdminCloudtentaclesVirtualNumbers(
|
||||
payload: AdminCloudtentaclesVirtualNumberInput = {}
|
||||
) {
|
||||
@@ -373,3 +446,13 @@ export async function runAdminCloudtentaclesFullFlow(
|
||||
vnKey: payload.vnKey,
|
||||
});
|
||||
}
|
||||
|
||||
function pickDefined(values: JsonObject = {}) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(values).filter(([, value]) => typeof value !== "undefined")
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeSkuName(value: unknown) {
|
||||
return String(value || "").trim().replace(/\s+/g, "").toLowerCase();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
import { createHttpError } from '../../../utils/http.js'
|
||||
import { cloudtentaclesRequest } from './http-client.js'
|
||||
import { resolveCloudtentaclesConfig } from './helpers.js'
|
||||
|
||||
type JsonObject = Record<string, any>
|
||||
|
||||
export type CloudtentaclesDeliveryRecordQuery = JsonObject & {
|
||||
baseUrl?: string
|
||||
timeoutMs?: number | string
|
||||
token?: string
|
||||
deviceId?: string
|
||||
deviceType?: number | string
|
||||
page?: number | string
|
||||
size?: number | string
|
||||
startDate?: string
|
||||
endDate?: string
|
||||
recordCode?: number | string
|
||||
}
|
||||
|
||||
export async function listCloudtentaclesDeliveryRecords(
|
||||
payload: CloudtentaclesDeliveryRecordQuery = {},
|
||||
) {
|
||||
const config = resolveCloudtentaclesConfig({
|
||||
...pickDefined({
|
||||
baseUrl: payload.baseUrl,
|
||||
deviceId: payload.deviceId,
|
||||
deviceType: payload.deviceType,
|
||||
}),
|
||||
...(
|
||||
typeof payload.timeoutMs === 'undefined'
|
||||
? {}
|
||||
: { timeoutMs: normalizePositiveInteger(payload.timeoutMs, 5000) }
|
||||
),
|
||||
})
|
||||
const page = normalizePositiveInteger(payload.page, 1)
|
||||
const size = normalizePageSize(payload.size)
|
||||
const startDate = normalizeDateInput(payload.startDate)
|
||||
const endDate = normalizeDateInput(payload.endDate)
|
||||
|
||||
if (!String(payload.token || '').trim()) {
|
||||
throw createHttpError('cloudtentacles 发货记录查询缺少 token', {
|
||||
statusCode: 409,
|
||||
errorCode: 'cloudtentacles_record_missing_token',
|
||||
})
|
||||
}
|
||||
|
||||
if (!startDate || !endDate) {
|
||||
throw createHttpError('cloudtentacles 发货记录查询需要选择开始和结束时间', {
|
||||
statusCode: 400,
|
||||
errorCode: 'cloudtentacles_record_date_required',
|
||||
})
|
||||
}
|
||||
|
||||
const result = await cloudtentaclesRequest('/record/paging', {
|
||||
...payload,
|
||||
method: 'POST',
|
||||
body: {
|
||||
record_code: normalizePositiveInteger(payload.recordCode, 4),
|
||||
page,
|
||||
size,
|
||||
start_date: startDate,
|
||||
end_date: endDate,
|
||||
},
|
||||
businessErrorCode: 'cloudtentacles_record_query_failed',
|
||||
timeoutMs: payload.timeoutMs || config.timeoutMs,
|
||||
})
|
||||
|
||||
const data = isPlainObject(result.payload?.data) ? result.payload.data : {}
|
||||
const values = Array.isArray(data.values) ? data.values : []
|
||||
|
||||
return {
|
||||
baseUrl: config.baseUrl,
|
||||
page,
|
||||
size,
|
||||
total: normalizeNonNegativeInteger(data.total, values.length),
|
||||
items: values.map(mapCloudtentaclesDeliveryRecord),
|
||||
raw: data,
|
||||
}
|
||||
}
|
||||
|
||||
function mapCloudtentaclesDeliveryRecord(raw: JsonObject) {
|
||||
return {
|
||||
createdAt: String(raw.c_time || '').trim(),
|
||||
recordId: String(raw.record_id || '').trim(),
|
||||
virtualNumberId: normalizeNonNegativeInteger(raw.virtual_number_id, 0),
|
||||
userId: normalizeNonNegativeInteger(raw.user_id, 0),
|
||||
count: normalizeNonNegativeInteger(raw.count, 0),
|
||||
cdk: String(raw.cdk || '').trim(),
|
||||
exchangeUrl: String(raw.exchange_url || '').trim(),
|
||||
name: String(raw.name || '').trim(),
|
||||
phone: String(raw.phone || '').trim(),
|
||||
status: normalizeNonNegativeInteger(raw.status, 0),
|
||||
fulfillUser: String(raw.fulfill_user || '').trim(),
|
||||
operatorName: String(raw.u_name || '').trim(),
|
||||
raw,
|
||||
}
|
||||
}
|
||||
|
||||
function normalizePositiveInteger(value: unknown, fallback: number) {
|
||||
const parsed = Number(value)
|
||||
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback
|
||||
}
|
||||
|
||||
function normalizePageSize(value: unknown) {
|
||||
const parsed = normalizePositiveInteger(value, 100)
|
||||
return Math.min(Math.max(parsed, 100), 1000)
|
||||
}
|
||||
|
||||
function normalizeNonNegativeInteger(value: unknown, fallback: number) {
|
||||
const parsed = Number(value)
|
||||
return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback
|
||||
}
|
||||
|
||||
function normalizeDateInput(value: unknown) {
|
||||
const raw = String(value || '').trim()
|
||||
if (!raw) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const date = new Date(raw)
|
||||
return Number.isNaN(date.getTime()) ? raw : date.toISOString()
|
||||
}
|
||||
|
||||
function isPlainObject(value: unknown): value is JsonObject {
|
||||
return Object.prototype.toString.call(value) === '[object Object]'
|
||||
}
|
||||
|
||||
function pickDefined(values: JsonObject = {}) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(values).filter(([, value]) => typeof value !== 'undefined'),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user