2026-01-22 15:54:15 +08:00
|
|
|
|
import dayjs from 'dayjs';
|
|
|
|
|
|
|
|
|
|
|
|
const DB_KEY = 'ykt_case_archive_detail_mockdb_v1';
|
|
|
|
|
|
|
|
|
|
|
|
export const VISIT_RECORD_TEMPLATES = [
|
|
|
|
|
|
{
|
|
|
|
|
|
templateType: 'outpatient',
|
|
|
|
|
|
templateName: '门诊记录',
|
|
|
|
|
|
templateList: [
|
2026-01-22 17:39:23 +08:00
|
|
|
|
{ title: 'visitTime', name: '就诊日期', type: 'date', operateType: 'formCell', required: true, format: 'YYYY-MM-DD' },
|
|
|
|
|
|
{ title: 'corpName', name: '就诊机构', type: 'input', operateType: 'formCell', required: false, wordLimit: 30, inputType: 'text' },
|
|
|
|
|
|
{ title: 'deptName', name: '科室', type: 'input', operateType: 'formCell', required: false, wordLimit: 30, inputType: 'text' },
|
|
|
|
|
|
{ title: 'doctor', name: '医生', type: 'input', operateType: 'formCell', required: false, wordLimit: 30, inputType: 'text' },
|
|
|
|
|
|
{ title: 'diagnosisName', name: '门诊诊断', type: 'textarea', operateType: 'formCell', required: false, wordLimit: 200 },
|
|
|
|
|
|
{ title: 'treatmentPlan', name: '治疗方案', type: 'textarea', operateType: 'formCell', required: false, wordLimit: 1000 },
|
|
|
|
|
|
{ title: 'disposePlan', name: '处置计划', type: 'textarea', operateType: 'formCell', required: false, wordLimit: 1000 },
|
|
|
|
|
|
{ title: 'summary', name: '备注/摘要', type: 'textarea', operateType: 'formCell', required: false, wordLimit: 200 },
|
|
|
|
|
|
{ title: 'files', name: '文件上传', type: 'files', required: false },
|
2026-01-22 15:54:15 +08:00
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
templateType: 'inhospital',
|
|
|
|
|
|
templateName: '住院记录',
|
|
|
|
|
|
templateList: [
|
2026-01-22 17:39:23 +08:00
|
|
|
|
{ title: 'inhosDate', name: '入院日期', type: 'date', operateType: 'formCell', required: true, format: 'YYYY-MM-DD' },
|
|
|
|
|
|
{ title: 'corpName', name: '住院机构', type: 'input', operateType: 'formCell', required: false, wordLimit: 30, inputType: 'text' },
|
|
|
|
|
|
{ title: 'diagnosisName', name: '入院诊断', type: 'textarea', operateType: 'formCell', required: false, wordLimit: 200 },
|
|
|
|
|
|
{ title: 'surgeryName', name: '手术名称', type: 'input', operateType: 'formCell', required: false, wordLimit: 50, inputType: 'text' },
|
|
|
|
|
|
{ title: 'summary', name: '摘要', type: 'textarea', operateType: 'formCell', required: false, wordLimit: 200 },
|
|
|
|
|
|
{ title: 'files', name: '文件上传', type: 'files', required: false },
|
|
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
templateType: 'preConsultation',
|
|
|
|
|
|
templateName: '预问诊记录',
|
|
|
|
|
|
templateList: [
|
|
|
|
|
|
{ title: 'consultDate', name: '问诊日期', type: 'date', operateType: 'formCell', required: true, format: 'YYYY-MM-DD' },
|
|
|
|
|
|
{ title: 'chiefComplaint', name: '主诉', type: 'textarea', operateType: 'formCell', required: false, wordLimit: 300 },
|
|
|
|
|
|
{ title: 'presentIllness', name: '现病史', type: 'textarea', operateType: 'formCell', required: false, wordLimit: 800 },
|
|
|
|
|
|
{ title: 'pastHistory', name: '既往史', type: 'textarea', operateType: 'formCell', required: false, wordLimit: 800 },
|
|
|
|
|
|
{ title: 'allergyHistory', name: '过敏史', type: 'textarea', operateType: 'formCell', required: false, wordLimit: 300 },
|
|
|
|
|
|
{ title: 'summary', name: '摘要', type: 'textarea', operateType: 'formCell', required: false, wordLimit: 200 },
|
|
|
|
|
|
{ title: 'files', name: '文件上传', type: 'files', required: false },
|
2026-01-22 15:54:15 +08:00
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
templateType: 'physicalExaminationTemplate',
|
|
|
|
|
|
templateName: '体检记录',
|
|
|
|
|
|
templateList: [
|
2026-01-22 17:39:23 +08:00
|
|
|
|
{ title: 'inspectDate', name: '体检日期', type: 'date', operateType: 'formCell', required: true, format: 'YYYY-MM-DD' },
|
|
|
|
|
|
{ title: 'corpName', name: '体检机构', type: 'input', operateType: 'formCell', required: false, wordLimit: 30, inputType: 'text' },
|
|
|
|
|
|
{ title: 'inspectPakageName', name: '体检套餐', type: 'input', operateType: 'formCell', required: false, wordLimit: 50, inputType: 'text' },
|
|
|
|
|
|
{ title: 'positiveFind', name: '阳性发现', type: 'textarea', operateType: 'formCell', required: false, wordLimit: 300 },
|
|
|
|
|
|
{ title: 'summary', name: '摘要', type: 'textarea', operateType: 'formCell', required: false, wordLimit: 200 },
|
|
|
|
|
|
{ title: 'files', name: '文件上传', type: 'files', required: false },
|
2026-01-22 15:54:15 +08:00
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
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',
|
2026-01-22 17:39:23 +08:00
|
|
|
|
teamId: 'team_1',
|
2026-01-22 15:54:15 +08:00
|
|
|
|
sortTime: now - 1000 * 60 * 60 * 24 * 2,
|
|
|
|
|
|
visitTime: dayjs(now - 1000 * 60 * 60 * 24 * 2).format('YYYY-MM-DD'),
|
|
|
|
|
|
corpName: '某某医院',
|
2026-01-22 17:39:23 +08:00
|
|
|
|
deptName: '呼吸内科',
|
2026-01-22 15:54:15 +08:00
|
|
|
|
doctor: '李医生',
|
2026-01-22 17:39:23 +08:00
|
|
|
|
diagnosisName: '急性上呼吸道感染(mock)',
|
|
|
|
|
|
treatmentPlan: '建议:1)对症处理退热;2)多饮水休息;3)如出现呼吸困难及时就医。',
|
|
|
|
|
|
disposePlan: '建议:1)继续对症治疗;2)监测体温与血压;3)如3天无缓解或加重立即复诊。',
|
|
|
|
|
|
summary: '初诊:对症处理并随访。',
|
|
|
|
|
|
files: [{ url: '/static/tabbar/home.png', name: '示例图片1' }],
|
2026-01-22 15:54:15 +08:00
|
|
|
|
createTime: now - 1000 * 60 * 60 * 24 * 2,
|
2026-01-22 17:39:23 +08:00
|
|
|
|
creatorName: '李珊珊',
|
2026-01-22 15:54:15 +08:00
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
_id: uid('mr'),
|
|
|
|
|
|
medicalType: 'inhospital',
|
|
|
|
|
|
tempName: '住院记录',
|
|
|
|
|
|
templateType: 'inhospital',
|
2026-01-22 17:39:23 +08:00
|
|
|
|
teamId: 'team_2',
|
2026-01-22 15:54:15 +08:00
|
|
|
|
sortTime: now - 1000 * 60 * 60 * 24 * 15,
|
2026-01-22 17:39:23 +08:00
|
|
|
|
inhosDate: dayjs(now - 1000 * 60 * 60 * 24 * 15).format('YYYY-MM-DD'),
|
2026-01-22 15:54:15 +08:00
|
|
|
|
corpName: '某某医院',
|
|
|
|
|
|
diagnosisName: '术后复查(mock)',
|
2026-01-22 17:39:23 +08:00
|
|
|
|
surgeryName: '阑尾切除术',
|
2026-01-22 15:54:15 +08:00
|
|
|
|
summary: '复诊:术后复查,恢复良好。',
|
2026-01-22 17:39:23 +08:00
|
|
|
|
files: [],
|
2026-01-22 15:54:15 +08:00
|
|
|
|
createTime: now - 1000 * 60 * 60 * 24 * 15,
|
|
|
|
|
|
creatorName: '王护士',
|
|
|
|
|
|
},
|
2026-01-22 17:39:23 +08:00
|
|
|
|
{
|
|
|
|
|
|
_id: uid('mr'),
|
|
|
|
|
|
medicalType: 'preConsultation',
|
|
|
|
|
|
tempName: '预问诊记录',
|
|
|
|
|
|
templateType: 'preConsultation',
|
|
|
|
|
|
teamId: 'team_1',
|
|
|
|
|
|
sortTime: now - 1000 * 60 * 60 * 6,
|
|
|
|
|
|
consultDate: dayjs(now - 1000 * 60 * 60 * 6).format('YYYY-MM-DD'),
|
|
|
|
|
|
chiefComplaint: '咽痛、流涕 2 天(mock)',
|
|
|
|
|
|
presentIllness: '近2天受凉后出现咽痛、流涕,体温最高 38.2℃。',
|
|
|
|
|
|
pastHistory: '既往体健。',
|
|
|
|
|
|
allergyHistory: '无明确过敏史。',
|
|
|
|
|
|
summary: '建议对症处理,必要时线下就医。',
|
|
|
|
|
|
files: [],
|
|
|
|
|
|
createTime: now - 1000 * 60 * 60 * 6,
|
|
|
|
|
|
creatorName: '李珊珊',
|
|
|
|
|
|
},
|
2026-01-22 15:54:15 +08:00
|
|
|
|
];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 17:39:23 +08:00
|
|
|
|
export function getCurrentTeamId() {
|
|
|
|
|
|
const v = uni.getStorageSync('ykt_mock_current_team_id');
|
|
|
|
|
|
return v ? String(v) : 'team_1';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getSortTimeTitle(templateType) {
|
|
|
|
|
|
if (templateType === 'outpatient') return 'visitTime';
|
|
|
|
|
|
if (templateType === 'inhospital') return 'inhosDate';
|
|
|
|
|
|
if (templateType === 'preConsultation') return 'consultDate';
|
|
|
|
|
|
if (templateType === 'physicalExaminationTemplate') return 'inspectDate';
|
|
|
|
|
|
return '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function queryVisitRecords({ archiveId, medicalType = 'ALL', timeRange = 'ALL', teamId = '', shareAllTeams = false }) {
|
2026-01-22 15:54:15 +08:00
|
|
|
|
const db = getDb();
|
|
|
|
|
|
const list = Array.isArray(db.visitRecordsByArchiveId[archiveId]) ? db.visitRecordsByArchiveId[archiveId] : [];
|
|
|
|
|
|
|
2026-01-22 17:39:23 +08:00
|
|
|
|
const withDate = list.map((i) => {
|
|
|
|
|
|
const type = i.templateType || i.medicalType || '';
|
|
|
|
|
|
const timeTitle = getSortTimeTitle(type);
|
|
|
|
|
|
const rawDate = timeTitle ? i[timeTitle] : '';
|
|
|
|
|
|
const fallback = i.sortTime ? dayjs(i.sortTime).format('YYYY-MM-DD') : '';
|
|
|
|
|
|
const date = rawDate || fallback;
|
|
|
|
|
|
return {
|
|
|
|
|
|
...i,
|
|
|
|
|
|
dateStr: date ? String(date) : '',
|
|
|
|
|
|
date: date ? String(date) : '',
|
|
|
|
|
|
createDateStr: i.createTime ? dayjs(i.createTime).format('YYYY-MM-DD') : '',
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
let filtered = [...withDate];
|
|
|
|
|
|
if (medicalType !== 'ALL') filtered = filtered.filter((i) => (i.medicalType || i.templateType) === medicalType);
|
|
|
|
|
|
if (!shareAllTeams && teamId) filtered = filtered.filter((i) => !i.teamId || i.teamId === teamId);
|
|
|
|
|
|
|
|
|
|
|
|
if (timeRange && timeRange !== 'ALL') {
|
|
|
|
|
|
const days = timeRange === 'today' ? 0 : timeRange === '7d' ? 7 : timeRange === '30d' ? 30 : null;
|
|
|
|
|
|
if (days !== null) {
|
|
|
|
|
|
const start = days === 0 ? dayjs().startOf('day') : dayjs().subtract(days, 'day').startOf('day');
|
|
|
|
|
|
const startMs = start.valueOf();
|
|
|
|
|
|
filtered = filtered.filter((i) => (i.sortTime || 0) >= startMs);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-22 15:54:15 +08:00
|
|
|
|
|
2026-01-22 17:39:23 +08:00
|
|
|
|
filtered.sort((a, b) => (b.sortTime || 0) - (a.sortTime || 0));
|
|
|
|
|
|
return filtered;
|
2026-01-22 15:54:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
}
|