ykt-wxapp/pages/case/archive-edit.vue

359 lines
11 KiB
Vue
Raw Normal View History

2026-01-22 15:54:15 +08:00
<template>
<view class="page">
<CustomerProfileTab
:data="archive"
:baseItems="baseItems"
:internalItems="internalItems"
:floatingBottom="16"
@save="savePatch"
/>
2026-01-22 15:54:15 +08:00
</view>
</template>
<script setup>
import { ref } from 'vue';
import { onLoad, onShow } from '@dcloudio/uni-app';
import { storeToRefs } from 'pinia';
2026-01-22 15:54:15 +08:00
import CustomerProfileTab from '@/components/archive-detail/customer-profile-tab.vue';
import api from '@/utils/api';
import useAccountStore from '@/store/account';
import { hideLoading, loading, toast } from '@/utils/widget';
2026-01-22 15:54:15 +08:00
const STORAGE_KEY = 'ykt_case_archive_detail';
const CURRENT_TEAM_STORAGE_KEY = 'ykt_case_current_team';
const NEED_RELOAD_STORAGE_KEY = 'ykt_case_need_reload';
2026-01-22 15:54:15 +08:00
const archiveId = ref('');
const archive = ref({
name: '',
sex: '',
age: '',
avatar: '',
mobile: '',
outpatientNo: '',
inpatientNo: '',
medicalRecordNo: '',
createTime: '',
creator: '',
createdByDoctor: true,
hasBindWechat: false,
notes: '',
groups: [],
groupOptions: [],
});
const baseItems = ref([]);
const internalItems = ref([]);
const accountStore = useAccountStore();
const { account, doctorInfo } = storeToRefs(accountStore);
const { getDoctorInfo } = accountStore;
function normalizeOptions(options) {
if (!Array.isArray(options)) return [];
if (!options.length) return [];
if (typeof options[0] === 'string') return options.filter((i) => typeof i === 'string');
if (typeof options[0] === 'object') {
return options
.map((i) => {
const label = i?.label ?? i?.name ?? i?.text ?? i?.title ?? '';
const value = i?.value ?? i?.id ?? i?.key ?? label;
if (!label && (value === undefined || value === null || value === '')) return null;
return { label: String(label || value), value: String(value) };
})
.filter(Boolean);
}
return [];
}
function normalizeTemplateItem(item) {
const next = { ...(item || {}) };
if (next.operateType === 'custom') next.operateType = 'formCell';
const originalType = next.type;
const customTypeMap = {
customerSource: 'select',
customerStage: 'select',
2026-01-29 13:36:43 +08:00
tag: 'tagPicker',
reference: 'input',
selectWwuser: 'select',
files: 'files',
corpProject: 'select',
diagnosis: 'textarea',
BMI: 'input',
bloodPressure: 'textarea',
selfMultipleDiseases: 'textarea',
};
if (originalType && customTypeMap[originalType]) {
next.__originType = originalType;
next.type = customTypeMap[originalType];
}
const aliasTypeMap = {
text: 'input',
string: 'input',
number: 'input',
integer: 'input',
int: 'input',
};
if (next.type && aliasTypeMap[next.type]) {
next.type = aliasTypeMap[next.type];
if (!next.inputType && (originalType === 'number' || originalType === 'integer' || originalType === 'int')) next.inputType = 'number';
}
const rawRange = next.range || next.options || next.optionList || next.values || [];
const range = normalizeOptions(rawRange);
if (next.type === 'select' || next.type === 'selectAndOther' || next.type === 'selectAndImage') {
next.range = range;
} else if (next.type === 'radio') {
if (range.length && typeof range[0] === 'object') {
next.type = 'select';
next.range = range;
} else {
next.range = Array.isArray(rawRange) ? rawRange : [];
}
}
if (!next.operateType) next.operateType = 'formCell';
next.required = Boolean(next.required);
if (next.type === 'input' && (next.wordLimit === undefined || next.wordLimit === null || next.wordLimit === '')) next.wordLimit = 20;
if (next.type === 'textarea' && (next.wordLimit === undefined || next.wordLimit === null || next.wordLimit === '')) next.wordLimit = 200;
return next;
}
2026-01-29 13:36:43 +08:00
function unwrapTemplate(res) {
const d = res?.data;
if (d && typeof d === 'object') {
if (d.data && typeof d.data === 'object') return d.data;
return d;
}
return res && typeof res === 'object' ? res : {};
}
function unwrapListPayload(res) {
const root = res && typeof res === 'object' ? res : {};
const d = root.data && typeof root.data === 'object' ? root.data : root;
if (!d) return [];
if (Array.isArray(d)) return d;
if (Array.isArray(d.data)) return d.data;
if (Array.isArray(d.list)) return d.list;
if (d.data && typeof d.data === 'object') {
if (Array.isArray(d.data.data)) return d.data.data;
if (Array.isArray(d.data.list)) return d.data.list;
}
return [];
}
function parseCustomerStageOptions(res) {
const list = unwrapListPayload(res);
return list
.map((i) => {
if (typeof i === 'string') return { label: i, value: i };
const label = i?.name ?? i?.label ?? '';
const value = i?.type ?? i?.value ?? i?.id ?? i?.key ?? label;
if (!label && (value === undefined || value === null || value === '')) return null;
return { label: String(label || value), value: String(value) };
})
.filter(Boolean);
}
function parseTagOptions(res) {
const list = unwrapListPayload(res);
let flat = [];
if (list.length && typeof list[0] === 'object' && Array.isArray(list[0]?.tag)) {
flat = list.reduce((acc, g) => {
if (Array.isArray(g?.tag)) acc.push(...g.tag);
return acc;
}, []);
} else {
flat = list;
}
const options = flat
.map((i) => {
if (typeof i === 'string') return { label: i, value: i };
const label = i?.name ?? i?.label ?? i?.text ?? '';
const value = i?.id ?? i?.value ?? i?.key ?? label;
if (!label && (value === undefined || value === null || value === '')) return null;
return { label: String(label || value), value: String(value) };
})
.filter(Boolean);
const seen = new Set();
return options.filter((i) => {
if (!i?.value) return false;
if (seen.has(i.value)) return false;
seen.add(i.value);
return true;
});
}
function isStageItem(i) {
const title = String(i?.title || '');
const type = String(i?.type || '');
const name = String(i?.name || '');
return title === 'customerStage' || type === 'customerStage' || name.includes('阶段');
}
function isTagItem(i) {
const title = String(i?.title || '');
const type = String(i?.type || '');
const name = String(i?.name || '');
return title === 'tagIds' || title === 'tag' || type === 'tag' || name.includes('标签');
}
function getUserId() {
const d = doctorInfo.value || {};
const a = account.value || {};
return String(d.userid || d.userId || d.corpUserId || a.userid || a.userId || '') || '';
}
function getCorpId() {
const d = doctorInfo.value || {};
const a = account.value || {};
const team = uni.getStorageSync(CURRENT_TEAM_STORAGE_KEY) || {};
return String(d.corpId || a.corpId || team.corpId || '') || '';
}
async function ensureDoctor() {
if (doctorInfo.value) return;
if (!account.value?.openid) return;
try {
await getDoctorInfo();
} catch (e) {
// ignore
}
}
2026-01-22 15:54:15 +08:00
function loadFromStorage() {
const cached = uni.getStorageSync(STORAGE_KEY);
if (cached && typeof cached === 'object') {
archive.value = {
...archive.value,
...cached,
groups: Array.isArray(cached.groups) ? cached.groups : archive.value.groups,
groupOptions: Array.isArray(cached.groupOptions) ? cached.groupOptions : archive.value.groupOptions,
};
}
}
async function loadTemplates() {
const corpId = getCorpId();
if (!corpId) return;
2026-01-29 13:36:43 +08:00
const [baseRes, internalRes, stageRes, tagRes] = await Promise.all([
api('getCurrentTemplate', { corpId, templateType: 'baseTemplate' }),
api('getCurrentTemplate', { corpId, templateType: 'internalTemplate' }),
2026-01-29 13:36:43 +08:00
api('getCustomerType', { corpId }),
api('getCorpTags', { corpId }),
]);
2026-01-29 13:36:43 +08:00
const stageOptions = parseCustomerStageOptions(stageRes);
const tagOptions = parseTagOptions(tagRes);
if (baseRes?.success) {
2026-01-29 13:36:43 +08:00
const temp = unwrapTemplate(baseRes);
const list = Array.isArray(temp.templateList) ? temp.templateList : [];
baseItems.value = list
.filter((i) => i && i.fieldStatus !== 'disable')
.filter((i) => i.operateType !== 'onlyRead')
.map(normalizeTemplateItem);
}
if (internalRes?.success) {
2026-01-29 13:36:43 +08:00
const temp = unwrapTemplate(internalRes);
const list = (Array.isArray(temp.templateList) ? temp.templateList : []).map((i) => {
const item = { ...(i || {}) };
if (isStageItem(item) && (!Array.isArray(item.range) || item.range.length === 0)) item.range = stageOptions;
if (isTagItem(item) && (!Array.isArray(item.range) || item.range.length === 0)) item.range = tagOptions;
if (isTagItem(item) && item.title === 'tag') item.title = 'tagIds';
return item;
});
internalItems.value = list
.filter((i) => i && i.fieldStatus !== 'disable')
.filter((i) => i.operateType !== 'onlyRead')
.map(normalizeTemplateItem);
2026-01-22 15:54:15 +08:00
}
}
async function loadArchiveFromApi() {
if (!archiveId.value) return;
loading('加载中...');
try {
const res = await api('getCustomerByCustomerId', { customerId: archiveId.value });
if (!res?.success) {
toast(res?.message || '获取档案失败');
return;
}
archive.value = { ...archive.value, ...(res.data && typeof res.data === 'object' ? res.data : {}) };
uni.setStorageSync(STORAGE_KEY, { ...archive.value });
} catch (e) {
toast('获取档案失败');
} finally {
hideLoading();
}
}
async function savePatch(patch) {
const p = patch && typeof patch === 'object' ? patch : {};
const params = Object.keys(p).reduce((acc, k) => {
const v = p[k];
if (v !== undefined) acc[k] = v;
return acc;
}, {});
if (Object.keys(params).length === 0) return;
await ensureDoctor();
const userId = getUserId();
const corpId = getCorpId();
const team = uni.getStorageSync(CURRENT_TEAM_STORAGE_KEY) || {};
const createTeamId = team?.teamId ? String(team.teamId) : '';
const createTeamName = team?.name ? String(team.name) : '';
if (!archiveId.value || !userId || !corpId) {
toast('缺少用户/团队信息,请先完成登录与个人信息');
return;
}
loading('保存中...');
try {
const res = await api('updateCustomer', {
id: archiveId.value,
params,
userId,
corpId,
createTeamId,
createTeamName,
});
if (!res?.success) {
toast(res?.message || '保存失败');
return;
}
toast('保存成功');
uni.setStorageSync(NEED_RELOAD_STORAGE_KEY, 1);
await loadArchiveFromApi();
} catch (e) {
toast('保存失败');
} finally {
hideLoading();
}
2026-01-22 15:54:15 +08:00
}
onLoad((options) => {
archiveId.value = options?.archiveId ? String(options.archiveId) : '';
loadFromStorage();
ensureDoctor().then(async () => {
await Promise.all([loadTemplates(), loadArchiveFromApi()]);
});
2026-01-22 15:54:15 +08:00
});
onShow(() => {
loadFromStorage();
loadArchiveFromApi();
});
2026-01-22 15:54:15 +08:00
</script>
<style scoped>
.page {
min-height: 100vh;
background: #f5f6f8;
}
</style>