334 lines
14 KiB
JavaScript
334 lines
14 KiB
JavaScript
|
|
import dayjs from 'dayjs';
|
|||
|
|
|
|||
|
|
const DB_KEY = 'ykt_case_archive_detail_mockdb_v1';
|
|||
|
|
|
|||
|
|
export const VISIT_RECORD_TEMPLATES = [
|
|||
|
|
{
|
|||
|
|
templateType: 'outpatient',
|
|||
|
|
templateName: '门诊记录',
|
|||
|
|
templateList: [
|
|||
|
|
{ title: 'visitTime', name: '就诊日期', type: 'date', required: true, format: 'YYYY-MM-DD' },
|
|||
|
|
{ title: 'corpName', name: '就诊机构', type: 'input', required: false, wordLimit: 30, inputType: 'text' },
|
|||
|
|
{ title: 'deptName', name: '科室', type: 'input', required: false, wordLimit: 30, inputType: 'text' },
|
|||
|
|
{ title: 'doctor', name: '医生', type: 'input', required: false, wordLimit: 30, inputType: 'text' },
|
|||
|
|
{ title: 'diagnosisName', name: '诊断', type: 'textarea', required: false, wordLimit: 200 },
|
|||
|
|
{ title: 'summary', name: '摘要', type: 'textarea', required: false, wordLimit: 200 },
|
|||
|
|
],
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
templateType: 'inhospital',
|
|||
|
|
templateName: '住院记录',
|
|||
|
|
templateList: [
|
|||
|
|
{ title: 'inhospitalDate', name: '入院日期', type: 'date', required: true, format: 'YYYY-MM-DD' },
|
|||
|
|
{ title: 'corpName', name: '住院机构', type: 'input', required: false, wordLimit: 30, inputType: 'text' },
|
|||
|
|
{ title: 'diagnosisName', name: '诊断', type: 'textarea', required: false, wordLimit: 200 },
|
|||
|
|
{ title: 'summary', name: '摘要', type: 'textarea', required: false, wordLimit: 200 },
|
|||
|
|
],
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
templateType: 'physicalExaminationTemplate',
|
|||
|
|
templateName: '体检记录',
|
|||
|
|
templateList: [
|
|||
|
|
{ title: 'inspectDate', name: '体检日期', type: 'date', required: true, format: 'YYYY-MM-DD' },
|
|||
|
|
{ title: 'corpName', name: '体检机构', type: 'input', required: false, wordLimit: 30, inputType: 'text' },
|
|||
|
|
{ title: 'inspectPakageName', name: '体检套餐', type: 'input', required: false, wordLimit: 50, inputType: 'text' },
|
|||
|
|
{ title: 'positiveFind', name: '阳性发现', type: 'textarea', required: false, wordLimit: 300 },
|
|||
|
|
{ title: 'summary', name: '摘要', type: 'textarea', required: false, wordLimit: 200 },
|
|||
|
|
],
|
|||
|
|
},
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
export function getVisitRecordTemplates() {
|
|||
|
|
return VISIT_RECORD_TEMPLATES.map((i) => ({ templateType: i.templateType, name: i.templateName, templateList: i.templateList }));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function getVisitRecordTemplate(templateType) {
|
|||
|
|
return VISIT_RECORD_TEMPLATES.find((i) => i.templateType === templateType) || null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function safeParse(json) {
|
|||
|
|
try {
|
|||
|
|
return JSON.parse(json);
|
|||
|
|
} catch {
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function getDb() {
|
|||
|
|
const raw = uni.getStorageSync(DB_KEY);
|
|||
|
|
const db = raw && typeof raw === 'string' ? safeParse(raw) : raw;
|
|||
|
|
const next = db && typeof db === 'object' ? db : {};
|
|||
|
|
next.visitRecordsByArchiveId = next.visitRecordsByArchiveId || {};
|
|||
|
|
next.serviceRecordsByArchiveId = next.serviceRecordsByArchiveId || {};
|
|||
|
|
next.followupsByArchiveId = next.followupsByArchiveId || {};
|
|||
|
|
return next;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function setDb(db) {
|
|||
|
|
uni.setStorageSync(DB_KEY, JSON.stringify(db));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function uid(prefix) {
|
|||
|
|
return `${prefix}_${Date.now()}_${Math.random().toString(16).slice(2)}`;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function ensureSeed(archiveId, archive) {
|
|||
|
|
if (!archiveId) return;
|
|||
|
|
const db = getDb();
|
|||
|
|
|
|||
|
|
if (!Array.isArray(db.visitRecordsByArchiveId[archiveId]) || db.visitRecordsByArchiveId[archiveId].length === 0) {
|
|||
|
|
const now = Date.now();
|
|||
|
|
db.visitRecordsByArchiveId[archiveId] = [
|
|||
|
|
{
|
|||
|
|
_id: uid('mr'),
|
|||
|
|
medicalType: 'outpatient',
|
|||
|
|
tempName: '门诊记录',
|
|||
|
|
templateType: 'outpatient',
|
|||
|
|
sortTime: now - 1000 * 60 * 60 * 24 * 2,
|
|||
|
|
visitTime: dayjs(now - 1000 * 60 * 60 * 24 * 2).format('YYYY-MM-DD'),
|
|||
|
|
corpName: '某某医院',
|
|||
|
|
deptName: '口腔科',
|
|||
|
|
doctor: '李医生',
|
|||
|
|
diagnosisName: '牙列不齐(mock)',
|
|||
|
|
summary: '初诊:拍片、取模,制定治疗方案。',
|
|||
|
|
createTime: now - 1000 * 60 * 60 * 24 * 2,
|
|||
|
|
creatorName: '李医生',
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
_id: uid('mr'),
|
|||
|
|
medicalType: 'inhospital',
|
|||
|
|
tempName: '住院记录',
|
|||
|
|
templateType: 'inhospital',
|
|||
|
|
sortTime: now - 1000 * 60 * 60 * 24 * 15,
|
|||
|
|
inhospitalDate: dayjs(now - 1000 * 60 * 60 * 24 * 15).format('YYYY-MM-DD'),
|
|||
|
|
corpName: '某某医院',
|
|||
|
|
diagnosisName: '术后复查(mock)',
|
|||
|
|
summary: '复诊:术后复查,恢复良好。',
|
|||
|
|
createTime: now - 1000 * 60 * 60 * 24 * 15,
|
|||
|
|
creatorName: '王护士',
|
|||
|
|
},
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!Array.isArray(db.serviceRecordsByArchiveId[archiveId]) || db.serviceRecordsByArchiveId[archiveId].length === 0) {
|
|||
|
|
const now = Date.now();
|
|||
|
|
db.serviceRecordsByArchiveId[archiveId] = Array.from({ length: 18 }).map((_, idx) => {
|
|||
|
|
const eventType =
|
|||
|
|
idx % 5 === 0 ? 'questionnaire' : idx % 4 === 0 ? 'article' : idx % 3 === 0 ? 'sms' : 'phone';
|
|||
|
|
const executionTime = now - 1000 * 60 * 60 * (idx * 6 + 3);
|
|||
|
|
const executeTeamId = idx % 2 === 0 ? 'team_1' : 'team_2';
|
|||
|
|
const executeTeamName = executeTeamId === 'team_1' ? '口腔一科(示例)' : '正畸团队(示例)';
|
|||
|
|
return {
|
|||
|
|
_id: uid('sr'),
|
|||
|
|
eventType,
|
|||
|
|
taskContent: `服务内容示例 #${idx + 1}:这里是任务描述,支持长文本展开收起。`,
|
|||
|
|
result: idx % 7 === 0 ? '已联系患者,已确认到院时间。' : '',
|
|||
|
|
executorName: idx % 2 === 0 ? '李医生' : '王护士',
|
|||
|
|
executeTeamId,
|
|||
|
|
executeTeamName,
|
|||
|
|
executionTime,
|
|||
|
|
pannedEventSendFile:
|
|||
|
|
eventType === 'article'
|
|||
|
|
? { type: 'article', url: 'https://example.com/article/1' }
|
|||
|
|
: eventType === 'questionnaire'
|
|||
|
|
? { type: 'questionnaire', surveryId: 'q_1' }
|
|||
|
|
: null,
|
|||
|
|
archiveName: archive?.name || '',
|
|||
|
|
};
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!Array.isArray(db.followupsByArchiveId[archiveId]) || db.followupsByArchiveId[archiveId].length === 0) {
|
|||
|
|
const now = Date.now();
|
|||
|
|
db.followupsByArchiveId[archiveId] = Array.from({ length: 22 }).map((_, idx) => {
|
|||
|
|
const plannedExecutionTime = now + 1000 * 60 * 60 * 24 * ((idx % 9) - 2);
|
|||
|
|
const createTime = now - 1000 * 60 * 60 * (idx * 5 + 2);
|
|||
|
|
const statusPool = ['processing', 'notStart', 'treated', 'cancelled', 'expired'];
|
|||
|
|
const status = statusPool[idx % statusPool.length];
|
|||
|
|
const eventTypePool = ['followup', 'revisit', 'questionnaire', 'other'];
|
|||
|
|
const eventType = eventTypePool[idx % eventTypePool.length];
|
|||
|
|
const executeTeamId = idx % 2 === 0 ? 'team_1' : 'team_2';
|
|||
|
|
const executeTeamName = executeTeamId === 'team_1' ? '口腔一科(示例)' : '正畸团队(示例)';
|
|||
|
|
return {
|
|||
|
|
_id: uid('td'),
|
|||
|
|
plannedExecutionTime,
|
|||
|
|
planDate: dayjs(plannedExecutionTime).format('YYYY-MM-DD'),
|
|||
|
|
createTime,
|
|||
|
|
createTimeStr: dayjs(createTime).format('YYYY-MM-DD HH:mm'),
|
|||
|
|
executorName: idx % 2 === 0 ? '李医生' : '王护士',
|
|||
|
|
executeTeamId,
|
|||
|
|
executeTeamName,
|
|||
|
|
creatorName: idx % 3 === 0 ? '系统' : '管理员A',
|
|||
|
|
status,
|
|||
|
|
eventType,
|
|||
|
|
eventTypeLabel:
|
|||
|
|
eventType === 'followup' ? '回访' : eventType === 'revisit' ? '复诊提醒' : eventType === 'questionnaire' ? '问卷' : '其他',
|
|||
|
|
eventStatusLabel:
|
|||
|
|
status === 'processing'
|
|||
|
|
? '待处理'
|
|||
|
|
: status === 'notStart'
|
|||
|
|
? '未开始'
|
|||
|
|
: status === 'treated'
|
|||
|
|
? '已完成'
|
|||
|
|
: status === 'cancelled'
|
|||
|
|
? '已取消'
|
|||
|
|
: '已过期',
|
|||
|
|
taskContent: `回访任务示例 #${idx + 1}:电话回访/提醒到院等。`,
|
|||
|
|
result: status === 'treated' ? '已完成回访,患者反馈良好。' : '',
|
|||
|
|
archiveName: archive?.name || '',
|
|||
|
|
};
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
setDb(db);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function queryVisitRecords({ archiveId, medicalType = 'ALL', date = '' }) {
|
|||
|
|
const db = getDb();
|
|||
|
|
const list = Array.isArray(db.visitRecordsByArchiveId[archiveId]) ? db.visitRecordsByArchiveId[archiveId] : [];
|
|||
|
|
|
|||
|
|
const withDate = list.map((i) => ({
|
|||
|
|
...i,
|
|||
|
|
dateStr: i.sortTime ? dayjs(i.sortTime).format('YYYY-MM-DD') : '',
|
|||
|
|
}));
|
|||
|
|
|
|||
|
|
const matchType = medicalType === 'ALL' ? withDate : withDate.filter((i) => i.medicalType === medicalType);
|
|||
|
|
const matchDate = date ? matchType.filter((i) => i.dateStr === date) : matchType;
|
|||
|
|
return matchDate.sort((a, b) => (b.sortTime || 0) - (a.sortTime || 0));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function getVisitRecord({ archiveId, id }) {
|
|||
|
|
const db = getDb();
|
|||
|
|
const list = Array.isArray(db.visitRecordsByArchiveId[archiveId]) ? db.visitRecordsByArchiveId[archiveId] : [];
|
|||
|
|
return list.find((i) => i._id === id) || null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function upsertVisitRecord({ archiveId, record }) {
|
|||
|
|
const db = getDb();
|
|||
|
|
const list = Array.isArray(db.visitRecordsByArchiveId[archiveId]) ? db.visitRecordsByArchiveId[archiveId] : [];
|
|||
|
|
const next = { ...record };
|
|||
|
|
if (!next._id) next._id = uid('mr');
|
|||
|
|
if (!next.sortTime) next.sortTime = Date.now();
|
|||
|
|
if (!next.createTime) next.createTime = Date.now();
|
|||
|
|
|
|||
|
|
const idx = list.findIndex((i) => i._id === next._id);
|
|||
|
|
if (idx >= 0) list[idx] = { ...list[idx], ...next };
|
|||
|
|
else list.unshift(next);
|
|||
|
|
db.visitRecordsByArchiveId[archiveId] = list;
|
|||
|
|
setDb(db);
|
|||
|
|
return next;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function removeVisitRecord({ archiveId, id }) {
|
|||
|
|
const db = getDb();
|
|||
|
|
const list = Array.isArray(db.visitRecordsByArchiveId[archiveId]) ? db.visitRecordsByArchiveId[archiveId] : [];
|
|||
|
|
db.visitRecordsByArchiveId[archiveId] = list.filter((i) => i._id !== id);
|
|||
|
|
setDb(db);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function queryServiceRecords({ archiveId, page = 1, pageSize = 10, eventType = 'ALL', teamId = 'ALL', dateRange = [] }) {
|
|||
|
|
const db = getDb();
|
|||
|
|
const list = Array.isArray(db.serviceRecordsByArchiveId[archiveId]) ? db.serviceRecordsByArchiveId[archiveId] : [];
|
|||
|
|
|
|||
|
|
let filtered = [...list];
|
|||
|
|
if (eventType !== 'ALL') filtered = filtered.filter((i) => i.eventType === eventType);
|
|||
|
|
if (teamId !== 'ALL') filtered = filtered.filter((i) => i.executeTeamId === teamId);
|
|||
|
|
|
|||
|
|
if (Array.isArray(dateRange) && dateRange.length === 2 && dateRange[0] && dateRange[1]) {
|
|||
|
|
filtered = filtered.filter((i) => {
|
|||
|
|
const d = i.executionTime ? dayjs(i.executionTime).format('YYYY-MM-DD') : '';
|
|||
|
|
return d >= dateRange[0] && d <= dateRange[1];
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
filtered.sort((a, b) => (b.executionTime || 0) - (a.executionTime || 0));
|
|||
|
|
const total = filtered.length;
|
|||
|
|
const pages = Math.ceil(total / pageSize) || 1;
|
|||
|
|
const start = (page - 1) * pageSize;
|
|||
|
|
const slice = filtered.slice(start, start + pageSize);
|
|||
|
|
return { list: slice, total, pages };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function getServiceRecord({ archiveId, id }) {
|
|||
|
|
const db = getDb();
|
|||
|
|
const list = Array.isArray(db.serviceRecordsByArchiveId[archiveId]) ? db.serviceRecordsByArchiveId[archiveId] : [];
|
|||
|
|
return list.find((i) => i._id === id) || null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function upsertServiceRecord({ archiveId, record }) {
|
|||
|
|
const db = getDb();
|
|||
|
|
const list = Array.isArray(db.serviceRecordsByArchiveId[archiveId]) ? db.serviceRecordsByArchiveId[archiveId] : [];
|
|||
|
|
const next = { ...record };
|
|||
|
|
if (!next._id) next._id = uid('sr');
|
|||
|
|
if (!next.executionTime) next.executionTime = Date.now();
|
|||
|
|
|
|||
|
|
const idx = list.findIndex((i) => i._id === next._id);
|
|||
|
|
if (idx >= 0) list[idx] = { ...list[idx], ...next };
|
|||
|
|
else list.unshift(next);
|
|||
|
|
db.serviceRecordsByArchiveId[archiveId] = list;
|
|||
|
|
setDb(db);
|
|||
|
|
return next;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function removeServiceRecord({ archiveId, id }) {
|
|||
|
|
const db = getDb();
|
|||
|
|
const list = Array.isArray(db.serviceRecordsByArchiveId[archiveId]) ? db.serviceRecordsByArchiveId[archiveId] : [];
|
|||
|
|
db.serviceRecordsByArchiveId[archiveId] = list.filter((i) => i._id !== id);
|
|||
|
|
setDb(db);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function queryFollowups({ archiveId, page = 1, pageSize = 10, status = 'all', isMy = false, eventTypes = [], teamId = 'ALL', planRange = ['', ''] }) {
|
|||
|
|
const db = getDb();
|
|||
|
|
const list = Array.isArray(db.followupsByArchiveId[archiveId]) ? db.followupsByArchiveId[archiveId] : [];
|
|||
|
|
|
|||
|
|
let filtered = [...list];
|
|||
|
|
if (status !== 'all') filtered = filtered.filter((i) => i.status === status);
|
|||
|
|
if (isMy) filtered = filtered.filter((i) => i.executorName === '李医生');
|
|||
|
|
if (Array.isArray(eventTypes) && eventTypes.length) filtered = filtered.filter((i) => eventTypes.includes(i.eventType));
|
|||
|
|
if (teamId !== 'ALL') filtered = filtered.filter((i) => i.executeTeamId === teamId);
|
|||
|
|
if (planRange && (planRange[0] || planRange[1])) {
|
|||
|
|
if (planRange[0]) filtered = filtered.filter((i) => i.planDate >= planRange[0]);
|
|||
|
|
if (planRange[1]) filtered = filtered.filter((i) => i.planDate <= planRange[1]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
filtered.sort((a, b) => (b.plannedExecutionTime || 0) - (a.plannedExecutionTime || 0));
|
|||
|
|
|
|||
|
|
const total = filtered.length;
|
|||
|
|
const pages = Math.ceil(total / pageSize) || 1;
|
|||
|
|
const start = (page - 1) * pageSize;
|
|||
|
|
const slice = filtered.slice(start, start + pageSize);
|
|||
|
|
return { list: slice, total, pages };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function getFollowup({ archiveId, id }) {
|
|||
|
|
const db = getDb();
|
|||
|
|
const list = Array.isArray(db.followupsByArchiveId[archiveId]) ? db.followupsByArchiveId[archiveId] : [];
|
|||
|
|
return list.find((i) => i._id === id) || null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function upsertFollowup({ archiveId, followup }) {
|
|||
|
|
const db = getDb();
|
|||
|
|
const list = Array.isArray(db.followupsByArchiveId[archiveId]) ? db.followupsByArchiveId[archiveId] : [];
|
|||
|
|
const next = { ...followup };
|
|||
|
|
if (!next._id) next._id = uid('td');
|
|||
|
|
if (!next.plannedExecutionTime) next.plannedExecutionTime = Date.now();
|
|||
|
|
next.planDate = dayjs(next.plannedExecutionTime).format('YYYY-MM-DD');
|
|||
|
|
if (!next.createTime) next.createTime = Date.now();
|
|||
|
|
next.createTimeStr = dayjs(next.createTime).format('YYYY-MM-DD HH:mm');
|
|||
|
|
|
|||
|
|
const idx = list.findIndex((i) => i._id === next._id);
|
|||
|
|
if (idx >= 0) list[idx] = { ...list[idx], ...next };
|
|||
|
|
else list.unshift(next);
|
|||
|
|
|
|||
|
|
db.followupsByArchiveId[archiveId] = list;
|
|||
|
|
setDb(db);
|
|||
|
|
return next;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function removeFollowup({ archiveId, id }) {
|
|||
|
|
const db = getDb();
|
|||
|
|
const list = Array.isArray(db.followupsByArchiveId[archiveId]) ? db.followupsByArchiveId[archiveId] : [];
|
|||
|
|
db.followupsByArchiveId[archiveId] = list.filter((i) => i._id !== id);
|
|||
|
|
setDb(db);
|
|||
|
|
}
|