sop 档案模版升级

This commit is contained in:
wangdongbo 2026-06-03 18:47:12 +08:00
parent 3696a8cf84
commit 9299bbac15
6 changed files with 229 additions and 67 deletions

View File

@ -2,15 +2,18 @@
import dbStore from "@/store/db";
import accountStore from "@/store/account";
import { globalUnreadListenerManager } from "@/utils/global-unread-listener.js";
import { initApiContextFromAppOptions } from "@/utils/api-base-config";
export default {
async onLaunch() {
async onLaunch(options) {
initApiContextFromAppOptions(options);
console.log("App Launch: ");
// openId IM
// await this.initIMOnLaunch();
},
onShow: function () {
onShow: function (options) {
initApiContextFromAppOptions(options);
const db = dbStore();
if (db && typeof db.getJobs === "function") {
db.getJobs();

View File

@ -8,7 +8,7 @@
<view class="flex items-center py-12 px-15">
<view class="min-w-90 flex items-center bg-white rounded-sm px-10 mr-5" @click="selectType()">
<view class="leading-normal text-base py-5 px-10 text-dark mr-5">
{{ tempType[type] || '全部' }}
{{ selectedTypeLabel }}
</view>
<uni-icons type="down" size="16" color="#666" />
</view>
@ -36,12 +36,11 @@
<view class="text-lg font-semibold text-dark mr-5">
{{ i.date }}
</view>
<view v-if="i.medicalType === 'outpatient'"
class="mr-5 px-10 leading-normal text-white text-base bg-warning rounded-full">门诊信息</view>
<view v-else-if="i.medicalType === 'inhospital'"
class="mr-5 px-10 leading-normal text-white text-base bg-success rounded-full">住院信息</view>
<view v-if="i.medicalType === 'physicalExaminationTemplate'"
class="mr-5 px-10 leading-normal text-white text-base bg-danger rounded-full">体检报告</view>
<view v-if="getTemplateLabel(i.medicalType)"
class="mr-5 px-10 leading-normal text-white text-base rounded-full"
:class="getTemplateTagClass(i.medicalType)">
{{ getTemplateLabel(i.medicalType) }}
</view>
<view v-if="i.corp === '其他'" class="px-10 leading-normal text-white text-base bg-danger rounded-full">
外院
</view>
@ -81,9 +80,25 @@
</view>
</view>
<template #footer>
<button-footer v-if="healthTempList.length" confirmText="+新增健康档案" :showCancel="false" @confirm="addArchive()" />
<button-footer v-if="enabledTemplateCount" confirmText="+新增健康档案" :showCancel="false" @confirm="addArchive()" />
</template>
</full-page>
<uni-popup ref="templatePopup" type="bottom" :safe-area="false">
<view class="template-popup">
<view class="template-popup-header">
<view class="template-popup-title">{{ templateSelectorTitle }}</view>
<view class="template-popup-close" @click="closeTemplateSelector()">取消</view>
</view>
<scroll-view scroll-y="true" class="template-popup-list">
<view v-for="item in templateSelectorItems" :key="item.value" class="template-popup-item"
@click="selectTemplateItem(item)">
<view class="template-popup-item-label">{{ item.label }}</view>
<uni-icons v-if="templateSelectorMode === 'filter' && type === item.value" type="checkmarkempty" size="18"
color="#0074ff" />
</view>
</scroll-view>
</view>
</uni-popup>
</template>
<script setup>
import { computed, ref, watch } from 'vue';
@ -96,11 +111,7 @@ import EmptyData from '@/components/empty-data.vue';
import FullPage from '@/components/full-page.vue';
import { toast } from '../../utils/widget';
const tempType = {
outpatient: '门诊信息',
inhospital: '住院信息',
physicalExaminationTemplate: '体检报告'
}
const templateTagClasses = ['bg-warning', 'bg-success', 'bg-danger', 'bg-primary'];
const empty = ref(false)
const { useLoad, useShow } = useGuard();
const corpId = ref('');
@ -108,43 +119,94 @@ const customerId = ref('');
const dates = ref([])
const list = ref([]);
const name = ref('');
const team = ref(null);
const type = ref('all');
const teamId = ref('');
const page = ref(1);
const more = ref(false)
const loading = ref(false);
const qrcode = computed(() => team.value && Array.isArray(team.value.qrcodes) ? team.value.qrcodes[0] : null)
const healthTempList = computed(() => qrcode.value && Array.isArray(qrcode.value.healthTempList) ? qrcode.value.healthTempList.map(i => ({ enable: i.enable, label: tempType[i.templateType], value: i.templateType })).filter(i => i.label && i.enable) : [])
const tempShowField = ref(null);
const config = {
outpatient: ["corp", "deptName", "doctor", "diagnosisName", "files"],
inhospital: ["corp", "diagnosisName", "operation", "operationDate", "outhosDate", "files"],
physicalExaminationTemplate: ['inspectPakageName']
};
function addArchive() {
if (healthTempList.value.length > 1) {
uni.showActionSheet({
title: '选择新增档案类型',
itemList: healthTempList.value.map(i => i.label),
success: function (res) {
toRecord(healthTempList.value[res.tapIndex].value)
const teamHealthTemplates = ref([]);
const templatePopup = ref(null);
const templateSelectorItems = ref([]);
const templateSelectorMode = ref('add');
const healthTempList = computed(() => {
return teamHealthTemplates.value
.map(i => {
const value = typeof i.templateType === 'string' ? i.templateType.trim() : '';
return {
...i,
value,
label: getTemplateLabel(value, i),
}
});
} else {
toRecord(healthTempList.value[0].value)
})
.filter(i => i.value && i.enable && i.label);
})
const enabledTemplateCount = computed(() => teamHealthTemplates.value.filter(i => i && i.enable && i.templateType).length);
const selectedTypeLabel = computed(() => type.value === 'all' ? '全部' : getTemplateLabel(type.value) || '全部');
const templateSelectorTitle = computed(() => templateSelectorMode.value === 'filter' ? '选择档案类型' : '选择新增档案类型');
const tempShowField = ref(null);
const tempMeta = ref({});
function getTemplateLabel(templateType, config = {}) {
if (!templateType) return '';
const meta = tempMeta.value && tempMeta.value[templateType] ? tempMeta.value[templateType] : {};
return config.name || config.templateName || config.templateTypeName || config.label || meta.name || '';
}
function getTemplateTagClass(templateType) {
const index = healthTempList.value.findIndex(i => i.value === templateType);
return templateTagClasses[index >= 0 ? index % templateTagClasses.length : templateTagClasses.length - 1];
}
function getTemplateTitleList(templateType, data) {
const template = healthTempList.value.find(i => i.value === templateType);
const titleList = template && Array.isArray(template.titleList) ? template.titleList.filter(Boolean) : [];
if (data.corp === '其他') {
return ['corpName', ...titleList.filter(i => i !== 'corp' && i !== 'corpName')];
}
return titleList;
}
async function addArchive() {
if (!teamHealthTemplates.value.length) {
await getTeamHealthTemps();
}
const templates = healthTempList.value;
if (!templates.length) {
toast('未查询到启用的健康档案模板名称');
return;
}
if (templates.length === 1) {
toRecord(templates[0].value)
return;
}
openTemplateSelector('add', templates);
}
function openTemplateSelector(mode, items) {
templateSelectorMode.value = mode;
templateSelectorItems.value = items;
templatePopup.value && templatePopup.value.open();
}
function closeTemplateSelector() {
templatePopup.value && templatePopup.value.close();
}
function selectTemplateItem(item) {
closeTemplateSelector();
if (templateSelectorMode.value === 'add') {
toRecord(item.value);
return;
}
type.value = item.value;
page.value = 1;
getList();
}
function getTempRows(type, data) {
if (config[type] && tempShowField.value && tempShowField.value[type]) {
if (tempShowField.value && tempShowField.value[type]) {
const list = [];
let titles = config[type];
if (data.corp === '其他') {
titles = ['corpName', 'diagnosisName', 'files']
}
const titles = getTemplateTitleList(type, data);
titles.forEach(i => {
if (tempShowField.value[type][i]) {
list.push({ title: i, label: tempShowField.value[type][i], value: data[i], key: `${i}_${data._id}` })
@ -169,26 +231,12 @@ function preview(file) {
}
}
function selectType() {
const itemList = [{ label: '全部', value: 'all' }, ...healthTempList.value]
uni.showActionSheet({
title: '选择新增档案类型',
itemList: itemList.map(i => i.label),
success: function (res) {
type.value = itemList[res.tapIndex].value;
page.value = 1;
getList()
}
});
}
async function getTeam() {
const res = await api('getTeamData', { teamId: teamId.value, corpId: corpId.value });
if (res && res.data) {
team.value = res.data;
} else {
toast(res?.message || '获取团队信息失败')
async function selectType() {
if (!teamHealthTemplates.value.length) {
await getTeamHealthTemps();
}
const itemList = [{ label: '全部', value: 'all' }, ...healthTempList.value]
openTemplateSelector('filter', itemList);
}
async function getList() {
@ -196,12 +244,20 @@ async function getList() {
await getTeamHealthTemps()
}
if (loading.value) return;
const medicalTypes = teamHealthTemplates.value
.map(i => typeof i.templateType === 'string' ? i.templateType.trim() : '')
.filter(Boolean);
if (!medicalTypes.length) {
list.value = [];
more.value = false;
return;
}
const params = {
corpId: corpId.value,
memberId: customerId.value,
page: page.value,
pageSize: 20,
medicalType: Object.keys(tempType)
medicalType: medicalTypes
}
if (type.value !== 'all') {
params.medicalType = [type.value]
@ -228,6 +284,11 @@ async function getTeamHealthTemps() {
const res = await api('getTeamHealthTemps', { teamId: teamId.value, corpId: corpId.value });
if (res && res.success) {
const arr = res && Array.isArray(res.data) ? res.data : [];
teamHealthTemplates.value = arr;
tempMeta.value = arr.reduce((m, item) => {
m[item.templateType] = { name: item.name || '', service: item.service || {} };
return m
}, {});
tempShowField.value = arr.reduce((m, item) => {
const templateList = Array.isArray(item.templateList) ? item.templateList : [];
const data = {}
@ -246,7 +307,6 @@ useLoad(options => {
teamId.value = options.teamId;
corpId.value = options.corpId;
customerId.value = options.id || '';
getTeam()
// getTeamHealthTemps();
})
@ -283,4 +343,51 @@ watch(dates, n => {
width: 80rpx;
height: 80rpx;
}
.template-popup {
background: #fff;
border-radius: 24rpx 24rpx 0 0;
overflow: hidden;
}
.template-popup-header {
display: flex;
align-items: center;
padding: 28rpx 30rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.template-popup-title {
flex: 1;
text-align: center;
font-size: 32rpx;
font-weight: 600;
color: #222;
}
.template-popup-close {
position: absolute;
right: 30rpx;
font-size: 28rpx;
color: #666;
}
.template-popup-list {
max-height: 640rpx;
padding-bottom: env(safe-area-inset-bottom);
}
.template-popup-item {
display: flex;
align-items: center;
min-height: 96rpx;
padding: 0 32rpx;
border-bottom: 1rpx solid #f5f5f5;
}
.template-popup-item-label {
flex: 1;
font-size: 30rpx;
color: #222;
}
</style>

View File

@ -45,6 +45,7 @@ const timeTitle = ref('');
const canEdit = ref(false)
const nextTypes = ref([]);
const source = ref('');
const templateName = ref('');
const formData = computed(() => ({ ...record.value, ...form.value }));
const displayFormItems = computed(() => {
@ -84,7 +85,8 @@ async function addHealthRecord() {
// teamId: teamId.value,
dataSource: 'customerReport',
miniAppId: account.value.openid,
medicalType: type.value
medicalType: type.value,
medicalTypeName: templateName.value
}
if (timeTitle.value) {
data.sortTime = data[timeTitle.value] && dayjs(data[timeTitle.value]).isValid() ? dayjs(data[timeTitle.value]).valueOf() : dayjs().valueOf();
@ -128,7 +130,8 @@ async function updateHealthRecord() {
corpId: corpId.value,
memberId: customerId.value,
miniAppId: account.value.openid,
medicalType: type.value
medicalType: type.value,
medicalTypeName: templateName.value
}
if (timeTitle.value) {
data.sortTime = formData.value[timeTitle.value] && dayjs(formData.value[timeTitle.value]).isValid() ? dayjs(formData.value[timeTitle.value]).valueOf() : dayjs().valueOf();
@ -156,12 +159,19 @@ async function getBaseForm() {
if (res && res.success) {
formItems.value = Array.isArray(res.data) ? res.data : [];
timeTitle.value = typeof res.timeTitle === 'string' ? res.timeTitle : '';
templateName.value = typeof res.templateName === 'string' ? res.templateName : '';
setPageTitle();
} else {
toast(res?.message || '查询失败');
return Promise.reject()
}
}
function setPageTitle() {
const action = id.value ? '编辑' : '新增';
uni.setNavigationBarTitle({ title: `${action}${templateName.value || '健康档案'}` })
}
async function getRecord() {
const res = await api('getMedicalRecordById', {
corpId: corpId.value,
@ -186,7 +196,7 @@ onLoad(options => {
source.value = options.source || '';
const nextTypeStr = typeof options.nextTypes === 'string' ? options.nextTypes : '';
nextTypes.value = nextTypeStr.split(',');
uni.setNavigationBarTitle({ title: id.value ? '编辑健康档案' : '新增健康档案' })
setPageTitle();
})
useLoad(options => {
init();

View File

@ -140,7 +140,7 @@ onLoad((options) => {
if (options.q) {
opts.value = JSON.stringify(options)
changeTeam(parseInviteOptions(options));
} else if (options.type === 'archive') {
} else if (options.type === 'archive' || (options.teamId && options.corpId)) {
changeTeam(options);
}

View File

@ -96,6 +96,7 @@ const teammate = computed(() => {
const friendlyMember = computed(() => {
const friendlyMembers = team.value && Array.isArray(team.value.friendlyMembers) ? team.value.friendlyMembers : [];
debugger
return friendlyMembers.reduce((data, item) => {
data[item] = true;
return data

View File

@ -51,6 +51,47 @@ function createContext(corpId, baseUrl) {
};
}
function safeDecode(value) {
try {
return decodeURIComponent(value);
} catch (error) {
return value;
}
}
function parseQueryString(queryString) {
return String(queryString || "")
.replace(/^[^?]*\?/, "")
.split("&")
.reduce((acc, item) => {
if (!item) return acc;
const [key, ...valueParts] = item.split("=");
if (!key) return acc;
acc[safeDecode(key)] = safeDecode(valueParts.join("=") || "");
return acc;
}, {});
}
export function getCorpIdFromAppOptions(options = {}) {
const query = options.query || options || {};
const corpId = query.corpId || query.corpid || query.corp_id;
if (corpId) return String(corpId).trim();
if (typeof query.q === "string") {
const qParams = parseQueryString(safeDecode(query.q));
const qCorpId = qParams.corpId || qParams.corpid || qParams.corp_id;
if (qCorpId) return String(qCorpId).trim();
}
return "";
}
export function initApiContextFromAppOptions(options = {}) {
const corpId = getCorpIdFromAppOptions(options);
if (!corpId) return null;
return resolveApiContext(corpId);
}
export function resolveApiContext(corpId) {
const normalizedCorpId = String(corpId || "").trim();