/**
|
* 建档模块 接口适配层(2026-10-11 新版接口)
|
* ------------------------------------------------------------------
|
* 新版后端把「新增 / 修改」合并成一个 insertOrUpdate 接口,请求体是
|
* 主表字段 + 详情表字段的扁平混合,一次调用同时维护两张表,并返回主表 ID。
|
* 因此这里不再做「主表一次请求 + 详情表一次请求」的拆分,只负责:
|
* 1. 前端单一档案对象 <-> 后端扁平字段的转换
|
* 2. 量表 / 可编辑表格数据的 JSON 打包与解包
|
*
|
* 对外函数签名与旧版保持一致,页面无需改动。
|
*/
|
|
import {
|
ARCHIVE_TYPE_CODE,
|
resolveTarget,
|
resolveKey,
|
toApiFields,
|
fromApiFields,
|
toApiParent,
|
packJson,
|
unpackJson,
|
splitLearningForm,
|
normalizeDates,
|
FORM_FIELD_BY_TAB,
|
archiveApi,
|
nowDateTime,
|
today,
|
toDateTime,
|
calcAge,
|
} from "@/api/patient/archive";
|
import { getTypeByKey } from "./types";
|
|
/* ==================== 内部工具 ==================== */
|
|
function pick(obj, keys) {
|
const out = {};
|
keys.forEach((k) => {
|
const v = obj && obj[k];
|
if (v !== undefined && v !== null && v !== "") out[k] = v;
|
});
|
return out;
|
}
|
|
/** 后端字段 -> 前端字段(列表行、详情记录共用)
|
* 注意:appointmentSituation 不在这里,它存的是 JSON 串,由 parseAppointmentStatus 单独解析
|
*/
|
const API_TO_FRONT = {
|
highRiskChildType: "highriskCategory",
|
highRiskChildName: "highriskName",
|
nutritionIcd10Code: "nutritionCode",
|
nutritionDiagName: "nutritionName",
|
plannedFollowTime: "followupDate",
|
birthWeight: "birthWeight",
|
gestationalWeek: "gestationalWeek",
|
pregnancySituation: "pregnancyStatus",
|
followupCycleTimes: "followupCycles",
|
};
|
|
/**
|
* 解析「预约情况」
|
* 后端这个字段存的是 JSON 串:{"appointmentStatus":"无预约"},
|
* 直接铺到列表上会把整串 JSON 显示出来,这里统一取里面的 appointmentStatus。
|
* 已经是纯文本时原样返回,解析不出内容则返回空。
|
*/
|
function parseAppointmentStatus(val) {
|
if (val === undefined || val === null || val === "") return "";
|
if (typeof val !== "string") return val.appointmentStatus || "";
|
const s = val.trim();
|
if (s.charAt(0) !== "{") return s;
|
try {
|
const o = JSON.parse(s);
|
return (o && o.appointmentStatus) || "";
|
} catch (e) {
|
return "";
|
}
|
}
|
|
/* ------------------------------------------------------------------
|
* 模块名口径不一致的统一入口
|
* 页面(types.js)用 maternal|child,接口层(ARCHIVE_TYPE_CODE)用 maternity|child。
|
* 两边不统一会导致 resolveKey 匹配不上,列表页所有专案都识别不出来。
|
*/
|
function innerModule(module) {
|
return module === "child" ? "child" : "maternity";
|
}
|
|
/** 接口层模块名 -> 页面口径 */
|
function frontModule(module) {
|
return module === "child" ? "child" : "maternal";
|
}
|
|
/** 详情表冗余的患者基本信息 -> 前端对象 */
|
function applyCommonFields(target, row) {
|
const front = fromApiFields(row);
|
Object.keys(front).forEach((k) => {
|
// id / detailId / subType 属于骨架自身的字段,不能被原始行数据覆盖
|
if (k === "id" || k === "detailId" || k === "subType") return;
|
const v = front[k];
|
if (v !== undefined && v !== null && v !== "") target[k] = v;
|
});
|
Object.keys(API_TO_FRONT).forEach((apiKey) => {
|
const v = row[apiKey];
|
if (v !== undefined && v !== null && v !== "") target[API_TO_FRONT[apiKey]] = v;
|
});
|
if (row.appointmentSituation) {
|
target.appointmentStatus = parseAppointmentStatus(row.appointmentSituation);
|
}
|
if (row.birthdate) target.age = calcAge(row.birthdate);
|
if (row.parentname || row.parentPhone || row.parentRelation) {
|
target.parentInfo = Object.assign({}, target.parentInfo, {
|
parentName: row.parentname || "",
|
relation: row.parentRelation || "",
|
parentPhone: row.parentPhone || "",
|
parentIdCard: row.parentIdcardno || "",
|
address: row.parentAddress || "",
|
});
|
}
|
if (row.sourceType === "1" || row.sourceType === 1) target.sourcePage = "outpatient";
|
return target;
|
}
|
|
/**
|
* 后端行 -> 前端档案对象骨架
|
*
|
* ⚠️ id 与 archiveid 是两个独立字段,不能互相赋值,必须由调用方显式声明这一行来自哪张表:
|
* from='main' 主表行(列表接口返回):row.id 是主表主键,没有 archiveid
|
* from='detail' 详情行(详情接口返回):row.id 是详情表主键,row.archiveid 是主表 ID
|
*
|
* 前端对象上:
|
* archive.id 永远 = 主表主键
|
* archive.detailId 永远 = 详情表主键(只有详情行才有)
|
*
|
* @param {Object} row 后端行
|
* @param {String} typeKey 专案 key
|
* @param {String} module maternity|child
|
* @param {String} from main|detail 这一行的来源表
|
*/
|
function skeletonFrom(row, typeKey, module, from) {
|
const t = ARCHIVE_TYPE_CODE[typeKey] || {};
|
const typeCfg = getTypeByKey(typeKey) || {};
|
const isDetail = from === "detail";
|
const archive = {
|
// 主表主键:主表行直接取 row.id;详情行取外键 row.archiveid
|
id: isDetail ? row.archiveid : row.id,
|
// 详情表主键:只有详情行才有,主表行(列表)拿不到,保持为空
|
detailId: isDetail ? row.id : "",
|
subType: typeKey,
|
subTypeLabel: typeCfg.subTypeLabel || t.label || "",
|
mainCategory: frontModule(module),
|
mainCategoryLabel: frontModule(module) === "child" ? "儿保科建档" : "妇保科建档",
|
sourcePage: "",
|
parentInfo: {},
|
archiveForm: {},
|
};
|
return applyCommonFields(archive, row);
|
}
|
|
/** 列表行(主表行) -> 前端档案对象 */
|
function normalizeRow(row, module) {
|
const inner = innerModule(module);
|
const key = resolveKey(inner, row.archiveType) || "";
|
return skeletonFrom(row, key, inner, "main");
|
}
|
|
/* ------------------------------------------------------------------
|
* 主表行缓存
|
* 列表接口只返回主表行(不含详情主键),详情接口按主表 ID 查,两者用主表 id 就能串起来。
|
* 把列表行按主表 id 暂存到 sessionStorage,getArchive 取不到详情时用它兜底,
|
* 至少能把姓名、性别、诊断、联系方式这些主表字段显示出来,而不是一片空白。
|
*/
|
const ROW_PREFIX = "archiveRow:";
|
|
function cacheRows(rows = []) {
|
try {
|
rows.forEach((r) => {
|
// 列表行是主表行,主键只认 row.id;不要用 archiveid 兜底,主表行根本没有这个字段
|
const id = r.id;
|
if (id) sessionStorage.setItem(ROW_PREFIX + id, JSON.stringify(r));
|
});
|
} catch (e) {
|
/* 忽略隐私模式等写入异常 */
|
}
|
}
|
|
function readRow(id) {
|
if (!id) return null;
|
try {
|
return JSON.parse(sessionStorage.getItem(ROW_PREFIX + id) || "null");
|
} catch (e) {
|
return null;
|
}
|
}
|
|
/* ------------------------------------------------------------------
|
* 新建草稿缓存
|
* 详情接口按【主表 ID】查询,但 insertOrUpdate 刚返回主表 ID 时后端详情行可能还没落好,
|
* 新建完立刻跳详情页有概率取不到详情记录。这里把新建时的档案对象暂存到
|
* sessionStorage,getArchive 取不到详情时用它兜底,避免详情页一片空白。
|
* 保存成功后清除。
|
*/
|
const DRAFT_PREFIX = "archiveDraft:";
|
|
function saveDraft(id, archive) {
|
if (!id) return;
|
try {
|
sessionStorage.setItem(DRAFT_PREFIX + id, JSON.stringify(archive));
|
} catch (e) {
|
/* 忽略隐私模式等写入异常 */
|
}
|
}
|
|
function readDraft(id) {
|
if (!id) return null;
|
try {
|
return JSON.parse(sessionStorage.getItem(DRAFT_PREFIX + id) || "null");
|
} catch (e) {
|
return null;
|
}
|
}
|
|
function clearDraft(id) {
|
if (!id) return;
|
try {
|
sessionStorage.removeItem(DRAFT_PREFIX + id);
|
} catch (e) {
|
/* ignore */
|
}
|
}
|
|
/* ==================== 前端对象 -> 扁平 payload ==================== */
|
|
/**
|
* 构造 insertOrUpdate 的请求体(主表 + 详情表字段扁平混合)
|
* @param {Object} archive 前端档案对象
|
* @param {Object} t resolveTarget 结果
|
* @param {Boolean} forUpdate 是否更新(带 archiveid / id)
|
*/
|
export function buildPayload(archive, t, forUpdate) {
|
const key = archive.subType;
|
const F = FORM_FIELD_BY_TAB[key] || {};
|
const payload = toApiFields(archive);
|
|
payload.archiveType = t.archiveType;
|
if (forUpdate) {
|
// 扁平请求体里这两个字段各自代表一张表的主键,值来源不同,不能互相顶替:
|
// archiveid = 主表 ID(来自 archive.id)
|
// id = 详情表主键(来自 archive.detailId,列表接口不返回,取不到就不传,后端按新增处理)
|
if (archive.id) payload.archiveid = archive.id;
|
if (archive.detailId) payload.id = archive.detailId;
|
}
|
if (archive.sourcePage === "outpatient") payload.sourceType = "1";
|
|
// 冗余的患者基本信息:详情表也存一份
|
const common = pick(archive, [
|
"outhospno", "inhospno", "serialnum", "patid", "patname", "sex",
|
"deptcode", "deptname", "wardcode", "wardname",
|
"icd10code", "diagname", "idcardno",
|
]);
|
Object.assign(payload, common, {
|
birthdate: toDateTime(archive.birthday),
|
diagTime: toDateTime(archive.diagnosisDate),
|
archiveTime: toDateTime(archive.createTime),
|
doctorName: archive.attendingDoctor || "",
|
managementDoctorName: archive.managingDoctor || "",
|
registerUser: archive.registrant || "",
|
closeStatus: archive.closeStatus == null ? "0" : String(archive.closeStatus),
|
});
|
|
if (key === "pregnancy") {
|
const p = archive.pregFormData || {};
|
const reg = p.registration || {};
|
const preg = p.pregnancy || {};
|
const fv = p.firstVisit || {};
|
Object.assign(payload, {
|
lastMenstrualTime: toDateTime(fv.lmp),
|
firstDoctorName: fv.firstDoctor || "",
|
contactPhone: fv.contactPhone || fv.selfPhone || "",
|
address: fv.address || "",
|
pregnancySituation: archive.pregnancyStatus || "",
|
specificSituation: packJson(preg.details || []),
|
handleSuggestion: packJson(preg.hint || []),
|
isRecordEstablished: reg.isRegistered === "是" ? "1" : reg.isRegistered === "否" ? "0" : "",
|
dueDate: toDateTime(reg.edd),
|
followupPeriod: packJson(p.followupCycle || []),
|
[F.followup]: packJson(p),
|
});
|
} else if (key === "menopause") {
|
const f = archive.formData || {};
|
Object.assign(payload, {
|
[F.sysQ]: packJson(f.menoSysQ || {}),
|
[F.mhtFirst]: packJson(f.mhtFirst || {}),
|
[F.mhtFollow]: packJson(f.mhtFollow || {}),
|
[F.kupperman]: packJson(f.kupperman || {}),
|
[F.mrs]: packJson(f.mrs || {}),
|
[F.psqi]: packJson(f.psqi || {}),
|
});
|
} else if (key === "highrisk") {
|
Object.assign(payload, toApiParent(archive.parentInfo || {}), {
|
highRiskChildType: archive.highriskCategory || "",
|
highRiskChildName: archive.highriskName || "",
|
plannedFollowTime: toDateTime(archive.followupDate),
|
[F.growth]: packJson(archive.growthData || []),
|
[F.neuro]: packJson(archive.neuroData || []),
|
[F.intervention]: packJson(archive.interventionData || []),
|
});
|
} else if (key === "nutrition") {
|
Object.assign(payload, toApiParent(archive.parentInfo || {}), {
|
nutritionDiagName: archive.nutritionName || "",
|
nutritionIcd10Code: archive.nutritionCode || "",
|
[F.measure]: packJson(archive.measureData || []),
|
[F.diet]: packJson(archive.dietData || []),
|
[F.plan]: packJson(archive.planData || []),
|
});
|
} else if (key === "learning") {
|
const ld =
|
(archive.archiveForm && archive.archiveForm.learningData) || archive.archiveForm || {};
|
Object.assign(
|
payload,
|
toApiParent(archive.parentInfo || {}),
|
splitLearningForm(ld, archive.appointmentStatus || "")
|
);
|
}
|
|
delete payload.age;
|
return normalizeDates(payload);
|
}
|
|
/* ==================== 详情记录 -> 页面表单数据 ==================== */
|
|
/** 把详情表 TEXT 字段还原成页面表单数据 */
|
function applyDetailToForms(archive, detail) {
|
const key = archive.subType;
|
const F = FORM_FIELD_BY_TAB[key] || {};
|
|
if (key === "pregnancy") {
|
const early = unpackJson(detail.epEarlyPregnancyFollowupForm, null);
|
archive.pregFormData = early || {};
|
if (!archive.pregFormData.followupCycle) {
|
archive.pregFormData.followupCycle = unpackJson(detail.followupPeriod, []);
|
}
|
if (!archive.pregFormData.pregnancy) {
|
archive.pregFormData.pregnancy = {
|
status: "",
|
details: unpackJson(detail.specificSituation, []),
|
hint: unpackJson(detail.handleSuggestion, []),
|
};
|
}
|
if (!archive.pregFormData.registration) archive.pregFormData.registration = {};
|
if (detail.isRecordEstablished != null && detail.isRecordEstablished !== "") {
|
archive.pregFormData.registration.isRegistered =
|
detail.isRecordEstablished === "1" ? "是" : "否";
|
}
|
if (detail.dueDate && !archive.pregFormData.registration.edd) {
|
archive.pregFormData.registration.edd = String(detail.dueDate).substring(0, 10);
|
}
|
if (detail.lastMenstrualTime && !archive.pregFormData.firstVisit) {
|
archive.pregFormData.firstVisit = {
|
lmp: String(detail.lastMenstrualTime).substring(0, 10),
|
};
|
}
|
} else if (key === "menopause") {
|
archive.formData = {
|
menoSysQ: unpackJson(detail.mhiMenopauseFollowupSystemIssuesForm, {}),
|
mhtFirst: unpackJson(detail.mhiMhtInitialVisitMedicalRecordForm, {}),
|
mhtFollow: unpackJson(detail.mhiMhtFollowUpMedicalRecordForm, {}),
|
kupperman: unpackJson(detail.mhiModifiedKuppermanScoringScaleForm, {}),
|
mrs: unpackJson(detail.mhiMenopauseRatingScaleForm, {}),
|
psqi: unpackJson(detail.mhiPittsburghSleepQualityIndexForm, {}),
|
};
|
} else if (key === "highrisk") {
|
archive.growthData = unpackJson(detail.hrcGrowthDevelopmentMonitoring, []);
|
archive.neuroData = unpackJson(detail.hrcNeurologicalEvaluation, []);
|
archive.interventionData = unpackJson(detail.hrcInterventionRecords, []);
|
} else if (key === "nutrition") {
|
archive.measureData = unpackJson(detail.ndPhysicalMeasurements, []);
|
archive.dietData = unpackJson(detail.ndDietaryAssessment, []);
|
archive.planData = unpackJson(detail.ndInterventionProgram, []);
|
} else if (key === "learning") {
|
const appt = unpackJson(detail.appointmentSituation, {});
|
const ability = unpackJson(detail.ldLearningAbilityAssessment, {});
|
const behavior = unpackJson(detail.ldBehavioralAssessment, {});
|
const train = unpackJson(detail.ldInterventionTrainingRecord, {});
|
archive.appointmentStatus = appt.appointmentStatus || "";
|
archive.archiveForm = {
|
learningData: Object.assign({}, ability, behavior, train),
|
};
|
}
|
}
|
|
/* ==================== 查询 ==================== */
|
|
/**
|
* 分页查询某专案档案(自动带上 archiveType)
|
* @param {String} typeKey 专案 key
|
* @param {Object} params 查询条件,支持 params.beginTime / params.endTime
|
* @returns Promise<{ rows, total }>
|
*/
|
export function listArchives(typeKey, params = {}) {
|
const t = resolveTarget(typeKey);
|
if (!t) return Promise.resolve({ rows: [], total: 0 });
|
const api = archiveApi(typeKey);
|
const query = Object.assign({}, params, { archiveType: t.archiveType });
|
return api.list(query).then((res) => {
|
const rows = res.rows || [];
|
cacheRows(rows);
|
return {
|
rows: rows.map((r) => normalizeRow(r, t.module)),
|
total: res.total || 0,
|
};
|
});
|
}
|
|
/**
|
* 按科室查询全部专案(妇保 / 儿保总列表页用,不带 archiveType)
|
* @param {String} module maternal|child
|
*/
|
export function listArchivesByModule(module, params = {}) {
|
const isChild = innerModule(module) === "child";
|
// 两个模块共用一个控制器,取任一专案 key 只是为了拿到接口
|
const api = archiveApi(isChild ? "highrisk" : "pregnancy");
|
return api.list(Object.assign({}, params)).then((res) => {
|
const rows = res.rows || [];
|
cacheRows(rows);
|
return {
|
rows: rows.map((r) => normalizeRow(r, module)),
|
total: res.total || 0,
|
};
|
});
|
}
|
|
/**
|
* 查询单个档案详情,返回前端完整对象
|
* @param {String} typeKey 专案 key
|
* @param {String|Number} id 主表 ID(详情接口 getInfo/{archiveid} 就是按它查的)
|
* @param {String|Number} [detailId] 已废弃,保留只为兼容旧调用,不再参与请求
|
* @returns Promise<前端档案对象 | null>
|
*/
|
export function getArchive(typeKey, id, detailId) {
|
const t = resolveTarget(typeKey);
|
if (!t || !id) return Promise.resolve(null);
|
const api = archiveApi(typeKey);
|
|
return api
|
.getDetail(id)
|
.then((res) => {
|
const detail = res.data || res;
|
if (!detail || !detail.id) return fallbackArchive(typeKey, id, t);
|
// 详情记录里的 archiveid 必须等于当前主表 id,否则说明数据串了,宁可不要
|
if (detail.archiveid != null && String(detail.archiveid) !== String(id)) {
|
console.warn(
|
"[archive] 详情记录与主表 id 不匹配,已忽略详情数据:",
|
{ archiveid: detail.archiveid, expectId: id }
|
);
|
return fallbackArchive(typeKey, id, t);
|
}
|
// 详情行:row.id 是详情主键 -> detailId,row.archiveid 是主表 ID -> id
|
const archive = skeletonFrom(detail, typeKey, t.module, "detail");
|
applyDetailToForms(archive, detail);
|
return archive;
|
})
|
.catch(() => fallbackArchive(typeKey, id, t));
|
}
|
|
/** 详情取不到时的兜底:新建草稿 > 主表行缓存 > 仅带主表 id 的空档案 */
|
function fallbackArchive(typeKey, id, t) {
|
const cached = readDraft(id);
|
if (cached && cached.subType === typeKey) {
|
return Object.assign(emptyArchive(typeKey, id, t), cached, { id });
|
}
|
const row = readRow(id);
|
if (row) return skeletonFrom(row, typeKey, t.module, "main");
|
return emptyArchive(typeKey, id, t);
|
}
|
|
/** 详情取不到时的兜底:只带主表 id 的空档案,页面仍可填写并保存 */
|
function emptyArchive(typeKey, id, t) {
|
const typeCfg = getTypeByKey(typeKey) || {};
|
return {
|
id,
|
detailId: "",
|
subType: typeKey,
|
subTypeLabel: typeCfg.subTypeLabel || t.label || "",
|
mainCategory: frontModule(t.module),
|
mainCategoryLabel: frontModule(t.module) === "child" ? "儿保科建档" : "妇保科建档",
|
sourcePage: "",
|
parentInfo: {},
|
archiveForm: {},
|
};
|
}
|
|
/* ==================== 新增 ==================== */
|
|
/**
|
* 由一条患者记录(门诊 / 住院 / 独立录入)建档
|
* @param {Object} patient 患者记录
|
* @param {String} typeKey 专案 key
|
* @param {String} sourcePage outpatient|inpatient|standalone
|
* @returns Promise<前端档案对象>
|
*/
|
export function createArchive(patient, typeKey, sourcePage) {
|
const t = resolveTarget(typeKey);
|
if (!t) return Promise.reject(new Error("未知的档案专案类型:" + typeKey));
|
const api = archiveApi(typeKey);
|
const now = nowDateTime();
|
|
const draft = {
|
subType: typeKey,
|
patid: patient.patid || patient.id || "",
|
patname: patient.patname || patient.name || "",
|
sex: patient.sex,
|
telcode: patient.telcode || patient.phone || "",
|
idcardno: patient.idcardno || "",
|
birthday: patient.birthday || patient.birthdate || patient.goday || "",
|
// 门诊/住院记录里诊断日期字段名不统一(admitdate / diagTime / diagnosisDate),且可能只有日期
|
diagnosisDate: patient.diagnosisDate || patient.diagTime || patient.admitdate || "",
|
createTime: now,
|
outhospno: patient.outhospno || "",
|
inhospno: patient.inhospno || "",
|
serialnum: patient.serialnum || "",
|
deptcode: patient.deptcode || "",
|
deptname: patient.deptname || "",
|
wardcode: patient.wardcode || "",
|
wardname: patient.wardname || "",
|
icd10code: patient.icd10code || "",
|
diagname: patient.diagname || "",
|
attendingDoctor: patient.drname || "",
|
registrant: localStorage.getItem("YongHuXM") || "",
|
closeStatus: "0",
|
sourcePage: sourcePage || "outpatient",
|
parentInfo: {},
|
archiveForm: {},
|
};
|
|
const payload = buildPayload(draft, t, false);
|
return api.save(payload).then((res) => {
|
const newId = res && res.data != null ? res.data : "";
|
const typeCfg = getTypeByKey(typeKey) || {};
|
const archive = Object.assign({}, draft, {
|
id: newId,
|
detailId: "",
|
subTypeLabel: typeCfg.subTypeLabel || t.label,
|
mainCategory: frontModule(t.module),
|
mainCategoryLabel: frontModule(t.module) === "child" ? "儿保科建档" : "妇保科建档",
|
age: calcAge(draft.birthday),
|
});
|
saveDraft(newId, archive);
|
return archive;
|
});
|
}
|
|
/* ==================== 保存 / 结案 / 删除 ==================== */
|
|
/**
|
* 保存档案:一次 insertOrUpdate 同时更新主表与详情表
|
* @param {Object} archive 前端档案对象
|
* @param {Boolean} onlyCloseStatus 仅更新结案状态
|
*/
|
export function saveArchive(archive, onlyCloseStatus) {
|
const key = archive.subType;
|
const t = resolveTarget(key);
|
if (!t || !archive.id) return Promise.reject(new Error("档案缺少 subType 或 id"));
|
const api = archiveApi(key);
|
|
if (onlyCloseStatus) {
|
return api.save({ archiveid: archive.id, archiveType: t.archiveType, closeStatus: "1" });
|
}
|
return api.save(buildPayload(archive, t, true)).then((res) => {
|
clearDraft(archive.id);
|
return res;
|
});
|
}
|
|
/** 结案 */
|
export function closeArchive(archive) {
|
return saveArchive(archive, true);
|
}
|
|
/**
|
* 删除档案(主表逻辑删除,详情表在同一事务里一起删)
|
* @param {String} typeKey 专案 key
|
* @param {Array} ids 主表 id 数组
|
*/
|
export function removeArchives(typeKey, ids) {
|
const t = resolveTarget(typeKey);
|
if (!t || !ids || !ids.length) return Promise.resolve();
|
return archiveApi(typeKey).batchDelete(ids);
|
}
|
|
/** 删除档案(按行数组,自动按专案分组) */
|
export function removeArchiveList(rows = []) {
|
const groups = {};
|
rows.forEach((r) => {
|
const key = r.subType || "";
|
if (!key) return;
|
(groups[key] = groups[key] || []).push(r.id);
|
});
|
return Promise.all(
|
Object.keys(groups).map((key) => removeArchives(key, groups[key]))
|
);
|
}
|
|
export { calcAge, nowDateTime, today, toDateTime };
|