Merge branch 'dev-wdb' of http://175.27.226.205:3000/huxuejian/ykt-wxapp into dev-wdb
This commit is contained in:
commit
9cfa5a362a
@ -1,214 +1,48 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="medical-case-form">
|
<view class="medical-case-form">
|
||||||
<view class="form-container">
|
<view class="form-container">
|
||||||
<!-- 门诊病历 -->
|
<!-- 动态渲染表单字段 -->
|
||||||
<template v-if="caseType === 'outpatient'">
|
<view
|
||||||
<view class="form-item required">
|
v-for="field in currentFields"
|
||||||
<view class="item-label">就诊机构</view>
|
:key="field.key"
|
||||||
<input
|
class="form-item"
|
||||||
class="item-input"
|
:class="{ required: field.required }"
|
||||||
v-model="formData.hospital"
|
>
|
||||||
placeholder="暂无"
|
<view class="item-label">{{ field.label }}</view>
|
||||||
:disabled="!isEditing"
|
|
||||||
/>
|
<!-- 日期选择器 -->
|
||||||
</view>
|
<picker
|
||||||
|
v-if="field.type === 'date'"
|
||||||
<view class="form-item required">
|
mode="date"
|
||||||
<view class="item-label">就诊日期</view>
|
:value="formData[field.key]"
|
||||||
<picker
|
@change="onDateChange(field.key, $event)"
|
||||||
mode="date"
|
:disabled="!isEditing"
|
||||||
:value="formData.visitTime"
|
>
|
||||||
@change="onDateChange('visitTime', $event)"
|
<view class="picker-value">
|
||||||
:disabled="!isEditing"
|
{{ formData[field.key] || "暂无" }}
|
||||||
>
|
</view>
|
||||||
<view class="picker-value">
|
</picker>
|
||||||
{{ formData.visitTime || '暂无' }}
|
|
||||||
</view>
|
<!-- 多行文本 -->
|
||||||
</picker>
|
<textarea
|
||||||
</view>
|
v-else-if="field.type === 'textarea'"
|
||||||
|
class="item-textarea"
|
||||||
<view class="form-item required">
|
v-model="formData[field.key]"
|
||||||
<view class="item-label">门诊诊断</view>
|
placeholder="请输入"
|
||||||
<textarea
|
:disabled="!isEditing"
|
||||||
class="item-textarea"
|
/>
|
||||||
v-model="formData.diagnosisName"
|
|
||||||
placeholder="请输入"
|
<!-- 单行文本 -->
|
||||||
:disabled="!isEditing"
|
<input
|
||||||
/>
|
v-else
|
||||||
</view>
|
class="item-input"
|
||||||
|
v-model="formData[field.key]"
|
||||||
<view class="form-item">
|
placeholder="暂无"
|
||||||
<view class="item-label">治疗方案</view>
|
:disabled="!isEditing"
|
||||||
<textarea
|
/>
|
||||||
class="item-textarea"
|
|
||||||
v-model="formData.treatmentPlan"
|
|
||||||
placeholder="请输入"
|
|
||||||
:disabled="!isEditing"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 住院病历 -->
|
|
||||||
<template v-if="caseType === 'inpatient'">
|
|
||||||
<view class="form-item required">
|
|
||||||
<view class="item-label">就诊机构</view>
|
|
||||||
<input
|
|
||||||
class="item-input"
|
|
||||||
v-model="formData.hospital"
|
|
||||||
placeholder="暂无"
|
|
||||||
:disabled="!isEditing"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="form-item required">
|
|
||||||
<view class="item-label">入院日期</view>
|
|
||||||
<picker
|
|
||||||
mode="date"
|
|
||||||
:value="formData.inhosDate"
|
|
||||||
@change="onDateChange('inhosDate', $event)"
|
|
||||||
:disabled="!isEditing"
|
|
||||||
>
|
|
||||||
<view class="picker-value">
|
|
||||||
{{ formData.inhosDate || '暂无' }}
|
|
||||||
</view>
|
|
||||||
</picker>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="form-item required">
|
|
||||||
<view class="item-label">住院主诊断</view>
|
|
||||||
<textarea
|
|
||||||
class="item-textarea"
|
|
||||||
v-model="formData.diagnosisName"
|
|
||||||
placeholder="请输入"
|
|
||||||
:disabled="!isEditing"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="form-item">
|
|
||||||
<view class="item-label">手术名称</view>
|
|
||||||
<textarea
|
|
||||||
class="item-textarea"
|
|
||||||
v-model="formData.operation"
|
|
||||||
placeholder="请输入"
|
|
||||||
:disabled="!isEditing"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="form-item">
|
|
||||||
<view class="item-label">手术日期</view>
|
|
||||||
<picker
|
|
||||||
mode="date"
|
|
||||||
:value="formData.operationDate"
|
|
||||||
@change="onDateChange('operationDate', $event)"
|
|
||||||
:disabled="!isEditing"
|
|
||||||
>
|
|
||||||
<view class="picker-value">
|
|
||||||
{{ formData.operationDate || '暂无' }}
|
|
||||||
</view>
|
|
||||||
</picker>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="form-item">
|
|
||||||
<view class="item-label">治疗方案</view>
|
|
||||||
<textarea
|
|
||||||
class="item-textarea"
|
|
||||||
v-model="formData.treatmentPlan"
|
|
||||||
placeholder="请输入"
|
|
||||||
:disabled="!isEditing"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 体检记录 -->
|
|
||||||
<template v-if="caseType === 'physicalExam'">
|
|
||||||
<view class="form-item required">
|
|
||||||
<view class="item-label">就诊机构</view>
|
|
||||||
<input
|
|
||||||
class="item-input"
|
|
||||||
v-model="formData.hospital"
|
|
||||||
placeholder="暂无"
|
|
||||||
:disabled="!isEditing"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="form-item required">
|
|
||||||
<view class="item-label">体检日期</view>
|
|
||||||
<picker
|
|
||||||
mode="date"
|
|
||||||
:value="formData.inspectTime"
|
|
||||||
@change="onDateChange('inspectTime', $event)"
|
|
||||||
:disabled="!isEditing"
|
|
||||||
>
|
|
||||||
<view class="picker-value">
|
|
||||||
{{ formData.inspectTime || '暂无' }}
|
|
||||||
</view>
|
|
||||||
</picker>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="form-item">
|
|
||||||
<view class="item-label">体检小结</view>
|
|
||||||
<textarea
|
|
||||||
class="item-textarea"
|
|
||||||
v-model="formData.inspectSummary"
|
|
||||||
placeholder="请输入"
|
|
||||||
:disabled="!isEditing"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="form-item">
|
|
||||||
<view class="item-label">阳性发现及处理意见</view>
|
|
||||||
<textarea
|
|
||||||
class="item-textarea"
|
|
||||||
v-model="formData.positiveFind"
|
|
||||||
placeholder="请输入"
|
|
||||||
:disabled="!isEditing"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 预问诊记录 -->
|
|
||||||
<template v-if="caseType === 'preConsultation'">
|
|
||||||
<view class="form-item">
|
|
||||||
<view class="item-label">主诉</view>
|
|
||||||
<textarea
|
|
||||||
class="item-textarea"
|
|
||||||
v-model="formData.chiefComplaint"
|
|
||||||
placeholder="请输入"
|
|
||||||
:disabled="!isEditing"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="form-item">
|
|
||||||
<view class="item-label">现病史</view>
|
|
||||||
<textarea
|
|
||||||
class="item-textarea"
|
|
||||||
v-model="formData.presentIllnessHistory"
|
|
||||||
placeholder="请输入"
|
|
||||||
:disabled="!isEditing"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="form-item">
|
|
||||||
<view class="item-label">既往史</view>
|
|
||||||
<textarea
|
|
||||||
class="item-textarea"
|
|
||||||
v-model="formData.pastMedicalHistory"
|
|
||||||
placeholder="请输入"
|
|
||||||
:disabled="!isEditing"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<view class="tips-box">
|
|
||||||
<text class="tips-text">
|
|
||||||
1、门诊、住院病历记录生成,生成后支持医生在线编辑,并保存至档案,或者重新生成;
|
|
||||||
</text>
|
|
||||||
<text class="tips-text">
|
|
||||||
2、若未来集到有效信息则以模板字段中默认项写无内容生成,医生可以直接在存字段上进行编辑。
|
|
||||||
</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="footer-buttons">
|
<view class="footer-buttons">
|
||||||
<view class="btn-regenerate" @click="handleRegenerate">
|
<view class="btn-regenerate" @click="handleRegenerate">
|
||||||
<text class="btn-text">重新生成</text>
|
<text class="btn-text">重新生成</text>
|
||||||
@ -221,42 +55,212 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, computed, onMounted } from "vue";
|
||||||
|
import { storeToRefs } from "pinia";
|
||||||
const caseType = ref('');
|
import useAccountStore from "@/store/account";
|
||||||
|
import api from "@/utils/api.js";
|
||||||
|
const caseType = ref("");
|
||||||
const formData = ref({});
|
const formData = ref({});
|
||||||
const isEditing = ref(true);
|
const isEditing = ref(true);
|
||||||
const customerId = ref('');
|
const customerId = ref("");
|
||||||
const groupId = ref('');
|
const groupId = ref("");
|
||||||
|
const accountStore = useAccountStore();
|
||||||
|
const { doctorInfo } = storeToRefs(accountStore);
|
||||||
|
// 病历类型名称
|
||||||
|
const CASE_TYPE_NAMES = {
|
||||||
|
outpatient: "门诊病历",
|
||||||
|
inhospital: "住院病历",
|
||||||
|
physicalExaminationTemplate: "体检记录",
|
||||||
|
preConsultation: "预问诊记录",
|
||||||
|
};
|
||||||
|
|
||||||
|
// 字段标签
|
||||||
|
const FIELD_LABELS = {
|
||||||
|
// 门诊病历
|
||||||
|
visitTime: "就诊日期",
|
||||||
|
chiefComplaint: "主诉",
|
||||||
|
medicalHistorySummary: "病史概要",
|
||||||
|
examination: "检查",
|
||||||
|
diagnosisName: "门诊诊断",
|
||||||
|
// 住院病历
|
||||||
|
inhosDate: "入院日期",
|
||||||
|
operation: "手术记录",
|
||||||
|
operationDate: "手术日期",
|
||||||
|
treatmentPlan: "治疗方案",
|
||||||
|
// 体检记录
|
||||||
|
inspectTime: "体检日期",
|
||||||
|
inspectSummary: "体检小结",
|
||||||
|
positiveFind: "阳性发现及处理意见",
|
||||||
|
// 预问诊记录
|
||||||
|
presentIllnessHistory: "现病史",
|
||||||
|
pastMedicalHistory: "既往史",
|
||||||
|
};
|
||||||
|
|
||||||
|
// 字段配置:根据病历类型定义字段
|
||||||
|
const FIELD_CONFIG = {
|
||||||
|
outpatient: [
|
||||||
|
{
|
||||||
|
key: "visitTime",
|
||||||
|
label: FIELD_LABELS.visitTime,
|
||||||
|
type: "date",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "diagnosisName",
|
||||||
|
label: FIELD_LABELS.diagnosisName,
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "chiefComplaint",
|
||||||
|
label: FIELD_LABELS.chiefComplaint,
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "medicalHistorySummary",
|
||||||
|
label: FIELD_LABELS.medicalHistorySummary,
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "examination",
|
||||||
|
label: FIELD_LABELS.examination,
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "treatmentPlan",
|
||||||
|
label: "治疗方案",
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
inhospital: [
|
||||||
|
{
|
||||||
|
key: "inhosDate",
|
||||||
|
label: FIELD_LABELS.inhosDate,
|
||||||
|
type: "date",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "diagnosisName",
|
||||||
|
label: "住院主诊断",
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "operation",
|
||||||
|
label: FIELD_LABELS.operation,
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "operationDate",
|
||||||
|
label: FIELD_LABELS.operationDate,
|
||||||
|
type: "date",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "treatmentPlan",
|
||||||
|
label: FIELD_LABELS.treatmentPlan,
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "chiefComplaint",
|
||||||
|
label: FIELD_LABELS.chiefComplaint,
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "medicalHistorySummary",
|
||||||
|
label: FIELD_LABELS.medicalHistorySummary,
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "examination",
|
||||||
|
label: FIELD_LABELS.examination,
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "treatmentPlan",
|
||||||
|
label: "治疗方案",
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
physicalExaminationTemplate: [
|
||||||
|
{
|
||||||
|
key: "inspectTime",
|
||||||
|
label: FIELD_LABELS.inspectTime,
|
||||||
|
type: "date",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "inspectSummary",
|
||||||
|
label: FIELD_LABELS.inspectSummary,
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "positiveFind",
|
||||||
|
label: FIELD_LABELS.positiveFind,
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
preConsultation: [
|
||||||
|
{
|
||||||
|
key: "chiefComplaint",
|
||||||
|
label: FIELD_LABELS.chiefComplaint,
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "presentIllnessHistory",
|
||||||
|
label: FIELD_LABELS.presentIllnessHistory,
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "pastMedicalHistory",
|
||||||
|
label: FIELD_LABELS.pastMedicalHistory,
|
||||||
|
type: "textarea",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
// 当前病历类型的字段配置
|
||||||
|
const currentFields = computed(() => {
|
||||||
|
return FIELD_CONFIG[caseType.value] || [];
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const pages = getCurrentPages();
|
const pages = getCurrentPages();
|
||||||
const currentPage = pages[pages.length - 1];
|
const currentPage = pages[pages.length - 1];
|
||||||
const options = currentPage.options;
|
const options = currentPage.options;
|
||||||
|
|
||||||
caseType.value = options.caseType || '';
|
caseType.value = options.caseType || "";
|
||||||
customerId.value = options.customerId || '';
|
customerId.value = options.patientId || "";
|
||||||
groupId.value = options.groupId || '';
|
groupId.value = options.groupId || "";
|
||||||
|
|
||||||
// 从 options 中解析表单数据
|
// 从 options 中解析表单数据
|
||||||
if (options.formData) {
|
if (options.formData) {
|
||||||
try {
|
try {
|
||||||
formData.value = JSON.parse(decodeURIComponent(options.formData));
|
formData.value = JSON.parse(decodeURIComponent(options.formData));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('解析表单数据失败:', e);
|
console.error("解析表单数据失败:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置页面标题
|
// 设置页面标题
|
||||||
const titles = {
|
const title = CASE_TYPE_NAMES[caseType.value]
|
||||||
outpatient: '添加门诊病历',
|
? `添加${CASE_TYPE_NAMES[caseType.value]}`
|
||||||
inpatient: '添加住院病历',
|
: "添加病历";
|
||||||
physicalExam: '添加体检记录',
|
uni.setNavigationBarTitle({ title });
|
||||||
preConsultation: '添加预问诊记录'
|
|
||||||
};
|
|
||||||
uni.setNavigationBarTitle({
|
|
||||||
title: titles[caseType.value] || '添加病历'
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const onDateChange = (field, event) => {
|
const onDateChange = (field, event) => {
|
||||||
@ -265,96 +269,78 @@ const onDateChange = (field, event) => {
|
|||||||
|
|
||||||
const handleRegenerate = () => {
|
const handleRegenerate = () => {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: '提示',
|
title: "提示",
|
||||||
content: '确定要重新生成吗?当前编辑的内容将被覆盖',
|
content: "确定要重新生成吗?当前编辑的内容将被覆盖",
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
// 返回上一页并触发重新生成
|
// 返回上一页并触发重新生成
|
||||||
uni.navigateBack({
|
uni.navigateBack({
|
||||||
success: () => {
|
success: () => {
|
||||||
uni.$emit('regenerateMedicalCase', {
|
uni.$emit("regenerateMedicalCase", {
|
||||||
caseType: caseType.value,
|
caseType: caseType.value,
|
||||||
customerId: customerId.value,
|
customerId: customerId.value,
|
||||||
groupId: groupId.value
|
groupId: groupId.value,
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
// 验证必填项
|
// 验证必填项
|
||||||
const requiredFields = getRequiredFields();
|
const requiredFields = getRequiredFields();
|
||||||
const missingFields = requiredFields.filter(field => !formData.value[field.key]);
|
const missingFields = requiredFields.filter(
|
||||||
|
(field) => !formData.value[field.key]
|
||||||
|
);
|
||||||
|
|
||||||
if (missingFields.length > 0) {
|
if (missingFields.length > 0) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: `请填写${missingFields[0].label}`,
|
title: `请填写${missingFields[0].label}`,
|
||||||
icon: 'none'
|
icon: "none",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
uni.showLoading({ title: '保存中...' });
|
uni.showLoading({ title: "保存中..." });
|
||||||
|
const result = await api("addMedicalRecord", {
|
||||||
// 调用保存接口
|
medicalType: caseType.value,
|
||||||
const api = (await import('@/utils/api.js')).default;
|
memberId: customerId.value,
|
||||||
const result = await api('addMedicalRecord', {
|
creator: doctorInfo.value.userid,
|
||||||
customerId: customerId.value,
|
...formData.value,
|
||||||
caseType: caseType.value,
|
|
||||||
...formData.value
|
|
||||||
});
|
});
|
||||||
|
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '保存成功',
|
title: "保存成功",
|
||||||
icon: 'success'
|
icon: "success",
|
||||||
});
|
});
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.navigateBack();
|
uni.navigateBack();
|
||||||
}, 1500);
|
}, 1500);
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: result.message || '保存失败',
|
title: result.message || "保存失败",
|
||||||
icon: 'none'
|
icon: "none",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
console.error('保存病历失败:', error);
|
console.error("保存病历失败:", error);
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '保存失败,请重试',
|
title: "保存失败,请重试",
|
||||||
icon: 'none'
|
icon: "none",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getRequiredFields = () => {
|
const getRequiredFields = () => {
|
||||||
const fieldsMap = {
|
return currentFields.value.filter((field) => field.required);
|
||||||
outpatient: [
|
|
||||||
{ key: 'hospital', label: '就诊机构' },
|
|
||||||
{ key: 'visitTime', label: '就诊日期' },
|
|
||||||
{ key: 'diagnosisName', label: '门诊诊断' }
|
|
||||||
],
|
|
||||||
inpatient: [
|
|
||||||
{ key: 'hospital', label: '就诊机构' },
|
|
||||||
{ key: 'inhosDate', label: '入院日期' },
|
|
||||||
{ key: 'diagnosisName', label: '住院主诊断' }
|
|
||||||
],
|
|
||||||
physicalExam: [
|
|
||||||
{ key: 'hospital', label: '就诊机构' },
|
|
||||||
{ key: 'inspectTime', label: '体检日期' }
|
|
||||||
],
|
|
||||||
preConsultation: []
|
|
||||||
};
|
|
||||||
|
|
||||||
return fieldsMap[caseType.value] || [];
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -363,26 +349,26 @@ const getRequiredFields = () => {
|
|||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
padding-bottom: 120rpx;
|
padding-bottom: 120rpx;
|
||||||
|
|
||||||
.form-container {
|
.form-container {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
padding: 32rpx;
|
padding: 32rpx;
|
||||||
|
|
||||||
.form-item {
|
.form-item {
|
||||||
margin-bottom: 32rpx;
|
margin-bottom: 32rpx;
|
||||||
|
|
||||||
&.required .item-label::before {
|
&.required .item-label::before {
|
||||||
content: '*';
|
content: "*";
|
||||||
color: #ff4d4f;
|
color: #ff4d4f;
|
||||||
margin-right: 8rpx;
|
margin-right: 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-label {
|
.item-label {
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #333333;
|
color: #333333;
|
||||||
margin-bottom: 16rpx;
|
margin-bottom: 16rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-input,
|
.item-input,
|
||||||
.picker-value {
|
.picker-value {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -392,64 +378,65 @@ const getRequiredFields = () => {
|
|||||||
border-radius: 8rpx;
|
border-radius: 8rpx;
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #333333;
|
color: #333333;
|
||||||
|
|
||||||
&[disabled] {
|
&[disabled] {
|
||||||
color: #999999;
|
color: #999999;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.picker-value {
|
.picker-value {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: #999999;
|
color: #999999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-textarea {
|
.item-textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 160rpx;
|
min-height: 100rpx;
|
||||||
padding: 20rpx 24rpx;
|
padding: 20rpx 24rpx;
|
||||||
background-color: #f8f9fa;
|
background-color: #f8f9fa;
|
||||||
border-radius: 8rpx;
|
border-radius: 8rpx;
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #333333;
|
color: #333333;
|
||||||
|
height: 100px;
|
||||||
&[disabled] {
|
&[disabled] {
|
||||||
color: #999999;
|
color: #999999;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tips-box {
|
.tips-box {
|
||||||
margin-top: 32rpx;
|
margin-top: 32rpx;
|
||||||
padding: 24rpx;
|
padding: 24rpx;
|
||||||
background-color: #fffbe6;
|
background-color: #fffbe6;
|
||||||
border-radius: 8rpx;
|
border-radius: 8rpx;
|
||||||
|
|
||||||
.tips-text {
|
.tips-text {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #666666;
|
color: #666666;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
margin-bottom: 8rpx;
|
margin-bottom: 8rpx;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-buttons {
|
.footer-buttons {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
z-index: 100;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 24rpx;
|
gap: 24rpx;
|
||||||
padding: 24rpx 32rpx;
|
padding: 24rpx 32rpx;
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.08);
|
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.08);
|
||||||
|
|
||||||
.btn-regenerate,
|
.btn-regenerate,
|
||||||
.btn-save {
|
.btn-save {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@ -458,25 +445,25 @@ const getRequiredFields = () => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-radius: 44rpx;
|
border-radius: 44rpx;
|
||||||
|
|
||||||
.btn-text {
|
.btn-text {
|
||||||
font-size: 32rpx;
|
font-size: 32rpx;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-regenerate {
|
.btn-regenerate {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border: 2rpx solid #1890ff;
|
border: 2rpx solid #1890ff;
|
||||||
|
|
||||||
.btn-text {
|
.btn-text {
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-save {
|
.btn-save {
|
||||||
background-color: #1890ff;
|
background-color: #1890ff;
|
||||||
|
|
||||||
.btn-text {
|
.btn-text {
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,6 +44,10 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
default: "",
|
default: "",
|
||||||
},
|
},
|
||||||
|
patientId: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
corpId: {
|
corpId: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "",
|
default: "",
|
||||||
@ -333,12 +337,15 @@ const handleRegenerateFromProgress = (data) => {
|
|||||||
|
|
||||||
// 处理从进度弹窗点击下一步
|
// 处理从进度弹窗点击下一步
|
||||||
const handleNextFromProgress = (data) => {
|
const handleNextFromProgress = (data) => {
|
||||||
|
// 根据病历类型动态构建表单数据
|
||||||
|
const extractedData = data.data?.extractedData || {};
|
||||||
|
|
||||||
// 跳转到病历填写页面
|
// 跳转到病历填写页面
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/case/medical-case-form?caseType=${data.caseType}&customerId=${
|
url: `/pages/case/medical-case-form?caseType=${data.caseType}&patientId=${
|
||||||
props.customerId || props.patientAccountId
|
props.patientId
|
||||||
}&groupId=${props.groupId}&formData=${encodeURIComponent(
|
}&groupId=${props.groupId}&formData=${encodeURIComponent(
|
||||||
JSON.stringify(data.data?.extractedData || {})
|
JSON.stringify(extractedData)
|
||||||
)}`,
|
)}`,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,29 +4,32 @@
|
|||||||
<view class="close-btn" @click="close">
|
<view class="close-btn" @click="close">
|
||||||
<text class="close-icon">✕</text>
|
<text class="close-icon">✕</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="progress-content">
|
<view class="progress-content">
|
||||||
<view class="progress-title">{{ progressTitle }}</view>
|
<view class="progress-title">{{ progressTitle }}</view>
|
||||||
|
|
||||||
<view class="progress-bar-wrapper">
|
<view class="progress-bar-wrapper">
|
||||||
<view class="progress-bar">
|
<view class="progress-bar">
|
||||||
<view class="progress-fill" :style="{ width: progress + '%' }"></view>
|
<view
|
||||||
|
class="progress-fill"
|
||||||
|
:style="{ width: progress + '%' }"
|
||||||
|
></view>
|
||||||
</view>
|
</view>
|
||||||
<text class="progress-text">{{ progress }}%</text>
|
<text class="progress-text">{{ progress }}%</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="detected-info">
|
<view class="detected-info">
|
||||||
<text class="detected-title">检测到以下{{ caseTypeName }}信息:</text>
|
<text class="detected-title">检测到以下{{ caseTypeName }}信息:</text>
|
||||||
<view class="info-list">
|
<view class="info-list">
|
||||||
<view
|
<view
|
||||||
v-for="(item, index) in detectedInfo"
|
v-for="(item, index) in detectedInfo"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="info-item"
|
class="info-item"
|
||||||
:class="{ 'fade-in': item.animated }"
|
:class="{ 'fade-in': item.animated }"
|
||||||
>
|
>
|
||||||
<text class="check-icon">✓</text>
|
<text class="check-icon">✓</text>
|
||||||
<text
|
<text
|
||||||
class="info-text"
|
class="info-text"
|
||||||
:class="{ 'empty-value': item.value === '暂无' }"
|
:class="{ 'empty-value': item.value === '暂无' }"
|
||||||
>
|
>
|
||||||
{{ item.label }}:{{ item.value }}
|
{{ item.label }}:{{ item.value }}
|
||||||
@ -34,11 +37,11 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view v-if="isGenerating" class="generating-text">
|
<view v-if="isGenerating" class="generating-text">
|
||||||
<text class="dot-animation">正在生成结构化{{ caseTypeName }}</text>
|
<text class="dot-animation">正在生成结构化{{ caseTypeName }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 完成后的操作按钮 -->
|
<!-- 完成后的操作按钮 -->
|
||||||
<view v-if="isCompleted" class="action-buttons">
|
<view v-if="isCompleted" class="action-buttons">
|
||||||
<view class="action-button secondary" @click="handleRegenerate">
|
<view class="action-button secondary" @click="handleRegenerate">
|
||||||
@ -54,48 +57,47 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from "vue";
|
||||||
|
|
||||||
const emit = defineEmits(['regenerate', 'next']);
|
const emit = defineEmits(["regenerate", "next"]);
|
||||||
|
|
||||||
const popup = ref(null);
|
const popup = ref(null);
|
||||||
const progress = ref(0);
|
const progress = ref(0);
|
||||||
const detectedInfo = ref([]);
|
const detectedInfo = ref([]);
|
||||||
const isGenerating = ref(false);
|
const isGenerating = ref(false);
|
||||||
const isCompleted = ref(false);
|
const isCompleted = ref(false);
|
||||||
const caseType = ref('');
|
const caseType = ref("");
|
||||||
const finalData = ref(null);
|
const finalData = ref(null);
|
||||||
|
|
||||||
const CASE_TYPE_NAMES = {
|
const CASE_TYPE_NAMES = {
|
||||||
outpatient: '门诊病历',
|
outpatient: "门诊病历",
|
||||||
inpatient: '住院病历',
|
inhospital: "住院病历",
|
||||||
physicalExam: '体检记录',
|
physicalExaminationTemplate: "体检记录",
|
||||||
preConsultation: '预问诊记录'
|
preConsultation: "预问诊记录",
|
||||||
};
|
};
|
||||||
|
|
||||||
const FIELD_LABELS = {
|
const FIELD_LABELS = {
|
||||||
// 门诊病历
|
// 门诊病历
|
||||||
visitTime: '就诊日期',
|
visitTime: "就诊日期",
|
||||||
chiefComplaint: '主诉',
|
chiefComplaint: "主诉",
|
||||||
medicalHistorySummary: '病史概要',
|
medicalHistorySummary: "病史概要",
|
||||||
examination: '检查',
|
examination: "检查",
|
||||||
diagnosisName: '门诊诊断',
|
diagnosisName: "门诊诊断",
|
||||||
// 住院病历
|
// 住院病历
|
||||||
inhosDate: '入院日期',
|
inhosDate: "入院日期",
|
||||||
operation: '手术记录',
|
operation: "手术名称",
|
||||||
operationDate: '手术日期',
|
operationDate: "手术日期",
|
||||||
treatmentPlan: '术后病程',
|
treatmentPlan: "治疗方案",
|
||||||
outhosAdvice: '出院医嘱',
|
|
||||||
// 体检记录
|
// 体检记录
|
||||||
inspectTime: '体检日期',
|
inspectTime: "体检日期",
|
||||||
inspectSummary: '体检小结',
|
inspectSummary: "体检小结",
|
||||||
positiveFind: '阳性发现及处理意见',
|
positiveFind: "阳性发现及处理意见",
|
||||||
// 预问诊记录
|
// 预问诊记录
|
||||||
presentIllnessHistory: '现病史',
|
presentIllnessHistory: "现病史",
|
||||||
pastMedicalHistory: '既往史'
|
pastMedicalHistory: "既往史",
|
||||||
};
|
};
|
||||||
|
|
||||||
const caseTypeName = computed(() => CASE_TYPE_NAMES[caseType.value] || '病历');
|
const caseTypeName = computed(() => CASE_TYPE_NAMES[caseType.value] || "病历");
|
||||||
|
|
||||||
const progressTitle = computed(() => {
|
const progressTitle = computed(() => {
|
||||||
if (progress.value < 100) {
|
if (progress.value < 100) {
|
||||||
@ -125,11 +127,11 @@ const updateProgress = (value) => {
|
|||||||
const addDetectedInfo = (fieldKey, fieldValue) => {
|
const addDetectedInfo = (fieldKey, fieldValue) => {
|
||||||
const label = FIELD_LABELS[fieldKey] || fieldKey;
|
const label = FIELD_LABELS[fieldKey] || fieldKey;
|
||||||
// 如果字段值为空,显示"暂无"
|
// 如果字段值为空,显示"暂无"
|
||||||
const displayValue = (fieldValue && fieldValue.trim()) ? fieldValue : '暂无';
|
const displayValue = fieldValue && fieldValue.trim() ? fieldValue : "暂无";
|
||||||
detectedInfo.value.push({
|
detectedInfo.value.push({
|
||||||
label,
|
label,
|
||||||
value: displayValue,
|
value: displayValue,
|
||||||
animated: true
|
animated: true,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -151,14 +153,14 @@ const reset = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRegenerate = () => {
|
const handleRegenerate = () => {
|
||||||
emit('regenerate', { caseType: caseType.value });
|
emit("regenerate", { caseType: caseType.value });
|
||||||
close();
|
close();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleNext = () => {
|
const handleNext = () => {
|
||||||
emit('next', {
|
emit("next", {
|
||||||
caseType: caseType.value,
|
caseType: caseType.value,
|
||||||
data: finalData.value
|
data: finalData.value,
|
||||||
});
|
});
|
||||||
close();
|
close();
|
||||||
};
|
};
|
||||||
@ -170,7 +172,7 @@ defineExpose({
|
|||||||
addDetectedInfo,
|
addDetectedInfo,
|
||||||
setGenerating,
|
setGenerating,
|
||||||
setCompleted,
|
setCompleted,
|
||||||
reset
|
reset,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -183,7 +185,7 @@ defineExpose({
|
|||||||
position: relative;
|
position: relative;
|
||||||
max-height: 80vh;
|
max-height: 80vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
.close-btn {
|
.close-btn {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 20rpx;
|
top: 20rpx;
|
||||||
@ -194,13 +196,13 @@ defineExpose({
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
|
||||||
.close-icon {
|
.close-icon {
|
||||||
font-size: 40rpx;
|
font-size: 40rpx;
|
||||||
color: #999999;
|
color: #999999;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-content {
|
.progress-content {
|
||||||
.progress-title {
|
.progress-title {
|
||||||
font-size: 32rpx;
|
font-size: 32rpx;
|
||||||
@ -209,27 +211,27 @@ defineExpose({
|
|||||||
margin-bottom: 32rpx;
|
margin-bottom: 32rpx;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-bar-wrapper {
|
.progress-bar-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 16rpx;
|
gap: 16rpx;
|
||||||
margin-bottom: 32rpx;
|
margin-bottom: 32rpx;
|
||||||
|
|
||||||
.progress-bar {
|
.progress-bar {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 16rpx;
|
height: 16rpx;
|
||||||
background-color: #e5e5e5;
|
background-color: #e5e5e5;
|
||||||
border-radius: 8rpx;
|
border-radius: 8rpx;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.progress-fill {
|
.progress-fill {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: linear-gradient(90deg, #1890ff 0%, #40a9ff 100%);
|
background: linear-gradient(90deg, #1890ff 0%, #40a9ff 100%);
|
||||||
transition: width 0.5s ease;
|
transition: width 0.5s ease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-text {
|
.progress-text {
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
@ -238,21 +240,21 @@ defineExpose({
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.detected-info {
|
.detected-info {
|
||||||
margin-bottom: 24rpx;
|
margin-bottom: 24rpx;
|
||||||
|
|
||||||
.detected-title {
|
.detected-title {
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #666666;
|
color: #666666;
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 16rpx;
|
margin-bottom: 16rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-list {
|
.info-list {
|
||||||
max-height: 400rpx;
|
max-height: 400rpx;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
.info-item {
|
.info-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@ -260,25 +262,25 @@ defineExpose({
|
|||||||
margin-bottom: 12rpx;
|
margin-bottom: 12rpx;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(-20rpx);
|
transform: translateX(-20rpx);
|
||||||
|
|
||||||
&.fade-in {
|
&.fade-in {
|
||||||
animation: fadeInSlide 0.4s ease forwards;
|
animation: fadeInSlide 0.4s ease forwards;
|
||||||
}
|
}
|
||||||
|
|
||||||
.check-icon {
|
.check-icon {
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #52c41a;
|
color: #52c41a;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-top: 2rpx;
|
margin-top: 2rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-text {
|
.info-text {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
color: #333333;
|
color: #333333;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
|
|
||||||
// 暂无数据的样式
|
// 暂无数据的样式
|
||||||
&.empty-value {
|
&.empty-value {
|
||||||
color: #999999;
|
color: #999999;
|
||||||
@ -287,24 +289,24 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.generating-text {
|
.generating-text {
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 16rpx 0;
|
padding: 16rpx 0;
|
||||||
|
|
||||||
.dot-animation::after {
|
.dot-animation::after {
|
||||||
content: '...';
|
content: "...";
|
||||||
animation: dots 1.5s steps(4, end) infinite;
|
animation: dots 1.5s steps(4, end) infinite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-buttons {
|
.action-buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 16rpx;
|
gap: 16rpx;
|
||||||
margin-top: 32rpx;
|
margin-top: 32rpx;
|
||||||
|
|
||||||
.action-button {
|
.action-button {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 80rpx;
|
height: 80rpx;
|
||||||
@ -313,34 +315,34 @@ defineExpose({
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
&.primary {
|
&.primary {
|
||||||
background: linear-gradient(90deg, #1890ff 0%, #40a9ff 100%);
|
background: linear-gradient(90deg, #1890ff 0%, #40a9ff 100%);
|
||||||
|
|
||||||
.button-text {
|
.button-text {
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
transform: scale(0.98);
|
transform: scale(0.98);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.secondary {
|
&.secondary {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border: 2rpx solid #d9d9d9;
|
border: 2rpx solid #d9d9d9;
|
||||||
|
|
||||||
.button-text {
|
.button-text {
|
||||||
color: #666666;
|
color: #666666;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
transform: scale(0.98);
|
transform: scale(0.98);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-text {
|
.button-text {
|
||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@ -358,17 +360,19 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes dots {
|
@keyframes dots {
|
||||||
0%, 20% {
|
0%,
|
||||||
content: '';
|
20% {
|
||||||
|
content: "";
|
||||||
}
|
}
|
||||||
40% {
|
40% {
|
||||||
content: '.';
|
content: ".";
|
||||||
}
|
}
|
||||||
60% {
|
60% {
|
||||||
content: '..';
|
content: "..";
|
||||||
}
|
}
|
||||||
80%, 100% {
|
80%,
|
||||||
content: '...';
|
100% {
|
||||||
|
content: "...";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<text class="close-icon">✕</text>
|
<text class="close-icon">✕</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="case-type-grid">
|
<view class="case-type-grid">
|
||||||
<view
|
<view
|
||||||
v-for="type in caseTypes"
|
v-for="type in caseTypes"
|
||||||
@ -23,29 +23,29 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from "vue";
|
||||||
|
|
||||||
const emit = defineEmits(['select']);
|
const emit = defineEmits(["select"]);
|
||||||
|
|
||||||
const popup = ref(null);
|
const popup = ref(null);
|
||||||
|
|
||||||
const caseTypes = [
|
const caseTypes = [
|
||||||
{
|
{
|
||||||
id: 'outpatient',
|
id: "outpatient",
|
||||||
name: '门诊病历'
|
name: "门诊病历",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'inpatient',
|
id: "inhospital",
|
||||||
name: '住院病历'
|
name: "住院病历",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'physicalExam',
|
id: "physicalExaminationTemplate",
|
||||||
name: '体检记录'
|
name: "体检记录",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'preConsultation',
|
id: "preConsultation",
|
||||||
name: '预问诊记录'
|
name: "预问诊记录",
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const open = () => {
|
const open = () => {
|
||||||
@ -57,13 +57,13 @@ const close = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const selectType = (type) => {
|
const selectType = (type) => {
|
||||||
emit('select', type);
|
emit("select", type);
|
||||||
close();
|
close();
|
||||||
};
|
};
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
open,
|
open,
|
||||||
close
|
close,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -73,38 +73,38 @@ defineExpose({
|
|||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border-radius: 24rpx;
|
border-radius: 24rpx;
|
||||||
padding: 40rpx;
|
padding: 40rpx;
|
||||||
|
|
||||||
.selector-header {
|
.selector-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 40rpx;
|
margin-bottom: 40rpx;
|
||||||
|
|
||||||
.header-title {
|
.header-title {
|
||||||
font-size: 36rpx;
|
font-size: 36rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #333333;
|
color: #333333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.close-btn {
|
.close-btn {
|
||||||
width: 48rpx;
|
width: 48rpx;
|
||||||
height: 48rpx;
|
height: 48rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
.close-icon {
|
.close-icon {
|
||||||
font-size: 40rpx;
|
font-size: 40rpx;
|
||||||
color: #999999;
|
color: #999999;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.case-type-grid {
|
.case-type-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
gap: 24rpx;
|
gap: 24rpx;
|
||||||
|
|
||||||
.case-type-item {
|
.case-type-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -115,13 +115,13 @@ defineExpose({
|
|||||||
border: 2rpx solid #e5e5e5;
|
border: 2rpx solid #e5e5e5;
|
||||||
border-radius: 16rpx;
|
border-radius: 16rpx;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
background-color: #e8f4ff;
|
background-color: #e8f4ff;
|
||||||
border-color: #1890ff;
|
border-color: #1890ff;
|
||||||
transform: scale(0.98);
|
transform: scale(0.98);
|
||||||
}
|
}
|
||||||
|
|
||||||
.type-name {
|
.type-name {
|
||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
color: #333333;
|
color: #333333;
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { onShow, onUnload } from '@dcloudio/uni-app'
|
import { onShow, onUnload } from '@dcloudio/uni-app'
|
||||||
|
import api from '@/utils/api.js'
|
||||||
|
import useTeamStore from '@/store/team.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 简单的群聊hook
|
* 简单的群聊hook
|
||||||
@ -8,6 +10,9 @@ import { onShow, onUnload } from '@dcloudio/uni-app'
|
|||||||
export default function useGroupChat(groupID) {
|
export default function useGroupChat(groupID) {
|
||||||
const groupInfo = ref({})
|
const groupInfo = ref({})
|
||||||
const members = ref([])
|
const members = ref([])
|
||||||
|
const teamMemberIds = ref([]) // 存储团队成员的userId列表
|
||||||
|
const patientId = ref('') // 存储患者ID
|
||||||
|
const teamStore = useTeamStore()
|
||||||
|
|
||||||
// 群聊成员映射
|
// 群聊成员映射
|
||||||
const chatMember = computed(() => {
|
const chatMember = computed(() => {
|
||||||
@ -15,30 +20,79 @@ export default function useGroupChat(groupID) {
|
|||||||
members.value.forEach(member => {
|
members.value.forEach(member => {
|
||||||
res[member.id] = {
|
res[member.id] = {
|
||||||
name: member.name,
|
name: member.name,
|
||||||
avatar: member.avatar || '/static/default-avatar.png'
|
avatar: member.avatar,
|
||||||
|
isTeamMember: member.isTeamMember // 标记是否为团队成员
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return res
|
return res
|
||||||
})
|
})
|
||||||
|
|
||||||
// 获取群聊信息
|
// 判断某个userId是否为团队成员
|
||||||
|
const isTeamMember = (userId) => {
|
||||||
|
return teamMemberIds.value.includes(userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户头像(根据是否为团队成员返回不同的默认头像)
|
||||||
|
const getUserAvatar = (userId) => {
|
||||||
|
const member = chatMember.value[userId]
|
||||||
|
if (!member) {
|
||||||
|
// 如果找不到成员信息,根据是否为团队成员返回默认头像
|
||||||
|
return isTeamMember(userId) ? '/static/home/avatar.svg' : '/static/default-patient-avatar.png'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有头像且不为空字符串,返回头像
|
||||||
|
if (member.avatar && member.avatar.trim() !== '') {
|
||||||
|
return member.avatar
|
||||||
|
}
|
||||||
|
|
||||||
|
// 否则根据是否为团队成员返回默认头像
|
||||||
|
return member.isTeamMember ? '/static/home/avatar.svg' : '/static/default-patient-avatar.png'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取群聊信息和成员头像
|
||||||
async function getGroupInfo() {
|
async function getGroupInfo() {
|
||||||
const gid = typeof groupID === 'string' ? groupID : groupID.value
|
const gid = typeof groupID === 'string' ? groupID : groupID.value
|
||||||
if (!gid) return
|
if (!gid) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 这里可以调用API获取群聊信息
|
// 1. 获取群聊基本信息
|
||||||
// const res = await getGroupDetail(gid)
|
const groupResult = await api('getGroupListByGroupId', { groupId: gid })
|
||||||
// if (res && res.success) {
|
|
||||||
// groupInfo.value = res.data
|
|
||||||
// members.value = res.data.members || []
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 暂时使用本地数据
|
if (groupResult && groupResult.success && groupResult.data) {
|
||||||
groupInfo.value = {
|
groupInfo.value = {
|
||||||
groupID: gid,
|
groupID: gid,
|
||||||
name: '群聊',
|
name: groupResult.data.team?.name || '群聊',
|
||||||
status: 'active'
|
status: groupResult.data.orderStatus || 'active',
|
||||||
|
teamId: groupResult.data.teamId
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 如果有teamId,获取团队成员头像
|
||||||
|
if (groupResult.data.teamId) {
|
||||||
|
const avatarMap = await teamStore.getTeamMemberAvatars(groupResult.data.teamId)
|
||||||
|
|
||||||
|
// 3. 存储团队成员ID列表
|
||||||
|
teamMemberIds.value = Object.keys(avatarMap)
|
||||||
|
|
||||||
|
// 4. 构建团队成员列表
|
||||||
|
members.value = teamMemberIds.value.map(userId => ({
|
||||||
|
id: userId,
|
||||||
|
name: userId, // 这里可以从其他地方获取真实姓名
|
||||||
|
avatar: avatarMap[userId] || '',
|
||||||
|
isTeamMember: true
|
||||||
|
}))
|
||||||
|
|
||||||
|
// 5. 添加患者信息(使用默认患者头像)
|
||||||
|
if (groupResult.data.patient) {
|
||||||
|
const pid = groupResult.data.patientId?.toString() || ''
|
||||||
|
patientId.value = pid
|
||||||
|
members.value.push({
|
||||||
|
id: pid,
|
||||||
|
name: groupResult.data.patient.name || '患者',
|
||||||
|
avatar: '', // 患者不设置头像,使用默认
|
||||||
|
isTeamMember: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取群聊信息失败:', error)
|
console.error('获取群聊信息失败:', error)
|
||||||
@ -57,6 +111,8 @@ export default function useGroupChat(groupID) {
|
|||||||
groupInfo,
|
groupInfo,
|
||||||
members,
|
members,
|
||||||
chatMember,
|
chatMember,
|
||||||
getGroupInfo
|
getGroupInfo,
|
||||||
|
isTeamMember,
|
||||||
|
getUserAvatar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,23 +65,16 @@
|
|||||||
|
|
||||||
<!-- 消息内容 -->
|
<!-- 消息内容 -->
|
||||||
<view v-else class="message-content">
|
<view v-else class="message-content">
|
||||||
<!-- 医生头像(左侧) -->
|
|
||||||
<image
|
<image
|
||||||
v-if="message.flow === 'in'"
|
v-if="message.flow === 'in'"
|
||||||
class="doctor-msg-avatar"
|
class="doctor-msg-avatar"
|
||||||
:src="
|
:src="getUserAvatar(message.from)"
|
||||||
chatMember[message.from]?.avatar || '/static/default-avatar.png'
|
|
||||||
"
|
|
||||||
mode="aspectFill"
|
mode="aspectFill"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 患者头像(右侧) -->
|
|
||||||
<image
|
<image
|
||||||
v-if="message.flow === 'out'"
|
v-if="message.flow === 'out'"
|
||||||
class="user-msg-avatar"
|
class="user-msg-avatar"
|
||||||
:src="
|
:src="getUserAvatar(message.from)"
|
||||||
chatMember[message.from]?.avatar || '/static/home/avatar.svg'
|
|
||||||
"
|
|
||||||
mode="aspectFill"
|
mode="aspectFill"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -149,6 +142,7 @@
|
|||||||
"
|
"
|
||||||
:groupId="groupId"
|
:groupId="groupId"
|
||||||
:patientAccountId="chatInfo.userID || ''"
|
:patientAccountId="chatInfo.userID || ''"
|
||||||
|
:patientId="patientId"
|
||||||
:corpId="corpId"
|
:corpId="corpId"
|
||||||
@streamText="handleStreamText"
|
@streamText="handleStreamText"
|
||||||
@clearInput="handleClearInput"
|
@clearInput="handleClearInput"
|
||||||
@ -221,7 +215,7 @@ const { initIMAfterLogin } = useAccountStore();
|
|||||||
const chatInputRef = ref(null);
|
const chatInputRef = ref(null);
|
||||||
|
|
||||||
const groupId = ref("");
|
const groupId = ref("");
|
||||||
const { chatMember, getGroupInfo } = useGroupChat(groupId);
|
const { chatMember, getGroupInfo, getUserAvatar } = useGroupChat(groupId);
|
||||||
|
|
||||||
// 动态设置导航栏标题
|
// 动态设置导航栏标题
|
||||||
const updateNavigationTitle = (title = "群聊") => {
|
const updateNavigationTitle = (title = "群聊") => {
|
||||||
@ -1048,4 +1042,4 @@ uni.$on("sendSurvey", async (data) => {
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "./chat.scss";
|
@import "./chat.scss";
|
||||||
</style>
|
</style>
|
||||||
@ -2,23 +2,59 @@
|
|||||||
<full-page>
|
<full-page>
|
||||||
<view class="p-15">
|
<view class="p-15">
|
||||||
<view class="bg-white px-10 mb-10 rounded">
|
<view class="bg-white px-10 mb-10 rounded">
|
||||||
<form-input :form="formData" :required="rule.anotherName.required" wordLimit="10" title="anotherName"
|
<form-input
|
||||||
:name="rule.anotherName.name" @change="onChange($event)" />
|
:form="formData"
|
||||||
|
:required="rule.anotherName.required"
|
||||||
|
wordLimit="10"
|
||||||
|
title="anotherName"
|
||||||
|
:name="rule.anotherName.name"
|
||||||
|
@change="onChange($event)"
|
||||||
|
/>
|
||||||
<common-cell title="avatar" name="头像">
|
<common-cell title="avatar" name="头像">
|
||||||
<view class="flex-grow flex items-center justify-end" @click="chooseAvatar()">
|
<view
|
||||||
<image v-if="formData.avatar" class="avatar mr-5 rounded-full" :src="formData.avatar" />
|
class="flex-grow flex items-center justify-end"
|
||||||
<image v-else class="avatar mr-5 rounded-full" src="/static/default-avatar.png" />
|
@click="chooseAvatar()"
|
||||||
|
>
|
||||||
|
<image
|
||||||
|
v-if="formData.avatar"
|
||||||
|
class="avatar mr-5 rounded-full"
|
||||||
|
:src="formData.avatar"
|
||||||
|
/>
|
||||||
|
<image
|
||||||
|
v-else
|
||||||
|
class="avatar mr-5 rounded-full"
|
||||||
|
src="/static/home/avatar.svg"
|
||||||
|
/>
|
||||||
<uni-icons color="#999" type="right" size="16" />
|
<uni-icons color="#999" type="right" size="16" />
|
||||||
</view>
|
</view>
|
||||||
</common-cell>
|
</common-cell>
|
||||||
<form-select :form="formData" name="性别" title="gender" :range="genderOptions" @change="onChange($event)" />
|
<form-select
|
||||||
<form-input :form="formData" disableChange wordLimit="11" title="mobile" name="手机号 (不可修改)" />
|
:form="formData"
|
||||||
|
name="性别"
|
||||||
|
title="gender"
|
||||||
|
:range="genderOptions"
|
||||||
|
@change="onChange($event)"
|
||||||
|
/>
|
||||||
|
<form-input
|
||||||
|
:form="formData"
|
||||||
|
disableChange
|
||||||
|
wordLimit="11"
|
||||||
|
title="mobile"
|
||||||
|
name="手机号 (不可修改)"
|
||||||
|
/>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="bg-white px-10 mb-10 rounded">
|
<view class="bg-white px-10 mb-10 rounded">
|
||||||
<!-- 填写认证资料的时候岗位必填 -->
|
<!-- 填写认证资料的时候岗位必填 -->
|
||||||
<common-cell :required="type === 'cert'" title="job" :name="rule.job.name">
|
<common-cell
|
||||||
<view class="flex-grow flex items-center justify-end" @click="selectJob()">
|
:required="type === 'cert'"
|
||||||
|
title="job"
|
||||||
|
:name="rule.job.name"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
class="flex-grow flex items-center justify-end"
|
||||||
|
@click="selectJob()"
|
||||||
|
>
|
||||||
<view v-if="jobStr" class="text-base text-base">{{ jobStr }}</view>
|
<view v-if="jobStr" class="text-base text-base">{{ jobStr }}</view>
|
||||||
<!-- <view class="mr-5 rounded-full" style="width: 64rpx;height: 64rpx;background: red;"></view> -->
|
<!-- <view class="mr-5 rounded-full" style="width: 64rpx;height: 64rpx;background: red;"></view> -->
|
||||||
<uni-icons color="#999" type="right" size="16" />
|
<uni-icons color="#999" type="right" size="16" />
|
||||||
@ -39,12 +75,24 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="bg-white rounded">
|
<view class="bg-white rounded">
|
||||||
<form-textarea autoHeight :border="false" :form="formData" title="intro" name="个人介绍" :wordLimit="300"
|
<form-textarea
|
||||||
@change="onChange($event)" />
|
autoHeight
|
||||||
|
:border="false"
|
||||||
|
:form="formData"
|
||||||
|
title="intro"
|
||||||
|
name="个人介绍"
|
||||||
|
:wordLimit="300"
|
||||||
|
@change="onChange($event)"
|
||||||
|
/>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<button-footer :cancelText="cancelText" :confirmText="confirmText" @confirm="save()" @cancel="back()" />
|
<button-footer
|
||||||
|
:cancelText="cancelText"
|
||||||
|
:confirmText="confirmText"
|
||||||
|
@confirm="save()"
|
||||||
|
@cancel="back()"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</full-page>
|
</full-page>
|
||||||
</template>
|
</template>
|
||||||
@ -58,46 +106,56 @@ import api from "@/utils/api.js";
|
|||||||
import { upload } from "@/utils/http.js";
|
import { upload } from "@/utils/http.js";
|
||||||
import { toast } from "@/utils/widget";
|
import { toast } from "@/utils/widget";
|
||||||
|
|
||||||
import buttonFooter from '@/components/button-footer.vue';
|
import buttonFooter from "@/components/button-footer.vue";
|
||||||
import commonCell from "@/components/form-template/common-cell.vue";
|
import commonCell from "@/components/form-template/common-cell.vue";
|
||||||
import FormInput from "@/components/form-template/form-cell/form-input.vue";
|
import FormInput from "@/components/form-template/form-cell/form-input.vue";
|
||||||
import FormSelect from "@/components/form-template/form-cell/form-select.vue";
|
import FormSelect from "@/components/form-template/form-cell/form-select.vue";
|
||||||
import FormTextarea from "@/components/form-template/form-cell/form-textarea.vue";
|
import FormTextarea from "@/components/form-template/form-cell/form-textarea.vue";
|
||||||
import fullPage from '@/components/full-page.vue';
|
import fullPage from "@/components/full-page.vue";
|
||||||
|
|
||||||
const { account, doctorInfo } = storeToRefs(useAccountStore());
|
const { account, doctorInfo } = storeToRefs(useAccountStore());
|
||||||
const { useLoad, useShow } = useGuard();
|
const { useLoad, useShow } = useGuard();
|
||||||
const { getDoctorInfo } = useAccountStore();
|
const { getDoctorInfo } = useAccountStore();
|
||||||
|
|
||||||
const job = { assistant: '医生助理', doctor: '医生' };
|
const job = { assistant: "医生助理", doctor: "医生" };
|
||||||
|
|
||||||
const form = ref({});
|
const form = ref({});
|
||||||
const inviteTeamId = ref('')
|
const inviteTeamId = ref("");
|
||||||
const type = ref('');
|
const type = ref("");
|
||||||
|
|
||||||
const formData = computed(() => ({ ...(doctorInfo.value || {}), ...form.value, mobile: account.value?.mobile }));
|
const formData = computed(() => ({
|
||||||
const cancelText = computed(() => doctorInfo.value ? '取消' : '暂不填写');
|
...(doctorInfo.value || {}),
|
||||||
const confirmText = computed(() => type.value === 'cert' ? '下一步' : '保存');
|
...form.value,
|
||||||
|
mobile: account.value?.mobile,
|
||||||
|
}));
|
||||||
|
const cancelText = computed(() => (doctorInfo.value ? "取消" : "暂不填写"));
|
||||||
|
const confirmText = computed(() => (type.value === "cert" ? "下一步" : "保存"));
|
||||||
const jobStr = computed(() => {
|
const jobStr = computed(() => {
|
||||||
const jobs = formData.value && Array.isArray(formData.value.job) ? formData.value.job.filter(i => i === 'assistant' || i === 'doctor') : [];
|
const jobs =
|
||||||
return jobs[0] && job[jobs[0]] ? job[jobs[0]] : '';
|
formData.value && Array.isArray(formData.value.job)
|
||||||
})
|
? formData.value.job.filter((i) => i === "assistant" || i === "doctor")
|
||||||
|
: [];
|
||||||
|
return jobs[0] && job[jobs[0]] ? job[jobs[0]] : "";
|
||||||
|
});
|
||||||
const rule = computed(() => {
|
const rule = computed(() => {
|
||||||
if (doctorInfo.value && ['verified', 'verifying'].includes(doctorInfo.value.verifyStatus)) {
|
if (
|
||||||
|
doctorInfo.value &&
|
||||||
|
["verified", "verifying"].includes(doctorInfo.value.verifyStatus)
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
anotherName: { name: '姓名 (不可修改)', required: false, disabled: true },
|
anotherName: { name: "姓名 (不可修改)", required: false, disabled: true },
|
||||||
job: { name: '岗位 (不可修改)', disabled: true },
|
job: { name: "岗位 (不可修改)", disabled: true },
|
||||||
title: { name: '职称 (不可修改)', disabled: true },
|
title: { name: "职称 (不可修改)", disabled: true },
|
||||||
dept: { name: '科室 (不可修改)', disabled: true },
|
dept: { name: "科室 (不可修改)", disabled: true },
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
anotherName: { name: '姓名', required: true, disabled: false },
|
anotherName: { name: "姓名", required: true, disabled: false },
|
||||||
job: { name: '岗位', disabled: false },
|
job: { name: "岗位", disabled: false },
|
||||||
title: { name: '职称', disabled: false },
|
title: { name: "职称", disabled: false },
|
||||||
dept: { name: '科室', disabled: false },
|
dept: { name: "科室", disabled: false },
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
|
|
||||||
// 选项数据
|
// 选项数据
|
||||||
const genderOptions = [
|
const genderOptions = [
|
||||||
@ -139,55 +197,60 @@ function chooseAvatar() {
|
|||||||
if (url) {
|
if (url) {
|
||||||
form.value.avatar = url;
|
form.value.avatar = url;
|
||||||
} else {
|
} else {
|
||||||
toast('上传失败')
|
toast("上传失败");
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onChange({ title, value }) {
|
function onChange({ title, value }) {
|
||||||
form.value[title] = value
|
form.value[title] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectJob() {
|
function selectJob() {
|
||||||
if (rule.value.job.disabled) return;
|
if (rule.value.job.disabled) return;
|
||||||
uni.showActionSheet({
|
uni.showActionSheet({
|
||||||
itemList: ['医生', '医生助理', '无'],
|
itemList: ["医生", "医生助理", "无"],
|
||||||
success: ({ tapIndex }) => {
|
success: ({ tapIndex }) => {
|
||||||
const job = ['doctor', 'assistant',][tapIndex];
|
const job = ["doctor", "assistant"][tapIndex];
|
||||||
form.value.job = job ? [job] : [];
|
form.value.job = job ? [job] : [];
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function toCert() {
|
function toCert() {
|
||||||
if (jobStr.value === '医生') {
|
if (jobStr.value === "医生") {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/work/verify/doctor'
|
url: "/pages/work/verify/doctor",
|
||||||
})
|
});
|
||||||
} else if (jobStr.value === '医生助理') {
|
} else if (jobStr.value === "医生助理") {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/work/verify/assistant'
|
url: "/pages/work/verify/assistant",
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
toast('请选择岗位信息')
|
toast("请选择岗位信息");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function save() {
|
async function save() {
|
||||||
if (typeof formData.value.anotherName !== 'string' || !formData.value.anotherName.trim()) {
|
if (
|
||||||
return toast('请输入姓名')
|
typeof formData.value.anotherName !== "string" ||
|
||||||
|
!formData.value.anotherName.trim()
|
||||||
|
) {
|
||||||
|
return toast("请输入姓名");
|
||||||
}
|
}
|
||||||
if (type.value === 'cert' && !jobStr.value) {
|
if (type.value === "cert" && !jobStr.value) {
|
||||||
return toast('请选择岗位信息')
|
return toast("请选择岗位信息");
|
||||||
}
|
}
|
||||||
const apiName = doctorInfo.value ? 'updateCorpMemberFromWxapp' : 'addCorpMemberFromWxapp';
|
const apiName = doctorInfo.value
|
||||||
|
? "updateCorpMemberFromWxapp"
|
||||||
|
: "addCorpMemberFromWxapp";
|
||||||
const data = {
|
const data = {
|
||||||
...form.value,
|
...form.value,
|
||||||
weChatOpenId: account.value.openid,
|
weChatOpenId: account.value.openid,
|
||||||
mobile: account.value.mobile,
|
mobile: account.value.mobile,
|
||||||
corpId: account.value.corpId,
|
corpId: account.value.corpId,
|
||||||
}
|
};
|
||||||
if (doctorInfo.value) {
|
if (doctorInfo.value) {
|
||||||
data.id = doctorInfo.value._id;
|
data.id = doctorInfo.value._id;
|
||||||
}
|
}
|
||||||
@ -196,30 +259,29 @@ async function save() {
|
|||||||
}
|
}
|
||||||
const res = await api(apiName, data);
|
const res = await api(apiName, data);
|
||||||
if (res && res.success) {
|
if (res && res.success) {
|
||||||
await getDoctorInfo()
|
await getDoctorInfo();
|
||||||
form.value = {};
|
form.value = {};
|
||||||
if (type.value === 'cert') {
|
if (type.value === "cert") {
|
||||||
toCert()
|
toCert();
|
||||||
} else {
|
} else {
|
||||||
await toast('保存成功');
|
await toast("保存成功");
|
||||||
back()
|
back();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await toast(res?.message || '保存失败');
|
await toast(res?.message || "保存失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useLoad(opts => {
|
useLoad((opts) => {
|
||||||
type.value = opts?.type;
|
type.value = opts?.type;
|
||||||
if (type.value === 'joinTeam' && opts.teamId) {
|
if (type.value === "joinTeam" && opts.teamId) {
|
||||||
inviteTeamId.value = opts.teamId
|
inviteTeamId.value = opts.teamId;
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
useShow(() => {
|
|
||||||
getDoctorInfo()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useShow(() => {
|
||||||
|
getDoctorInfo();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<view class="relative user-avatar mr-10" @click="editProfile()">
|
<view class="relative user-avatar mr-10" @click="editProfile()">
|
||||||
<image v-if="doctorInfo && doctorInfo.avatar" class="avatar-img rounded-full overflow-hidden"
|
<image v-if="doctorInfo && doctorInfo.avatar" class="avatar-img rounded-full overflow-hidden"
|
||||||
:src="doctorInfo.avatar" mode="aspectFill" />
|
:src="doctorInfo.avatar" mode="aspectFill" />
|
||||||
<image v-else class="avatar-img rounded-full overflow-hidden" src="/static/default-avatar.png"
|
<image v-else class="avatar-img rounded-full overflow-hidden" src="/static/home/avatar.svg"
|
||||||
mode="aspectFill" />
|
mode="aspectFill" />
|
||||||
<view v-if="doctorInfo" class="edit-sub flex items-center justify-center rounded-full bg-primary">
|
<view v-if="doctorInfo" class="edit-sub flex items-center justify-center rounded-full bg-primary">
|
||||||
<image class="edit-icon" src="/static/work/pen.svg" mode="aspectFill" />
|
<image class="edit-icon" src="/static/work/pen.svg" mode="aspectFill" />
|
||||||
|
|||||||
BIN
static/default-patient-avatar.png
Normal file
BIN
static/default-patient-avatar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
@ -34,5 +34,18 @@ export default defineStore("teamStore", () => {
|
|||||||
teams.value = res && Array.isArray(res.data) ? res.data : [];
|
teams.value = res && Array.isArray(res.data) ? res.data : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return { teams, chargeTeams, getTeam, getTeams }
|
// 获取团队成员头像映射
|
||||||
|
async function getTeamMemberAvatars(teamId) {
|
||||||
|
if (!teamId || !account.value?.corpId) return {};
|
||||||
|
const res = await api('getTeamMemberAvatars', {
|
||||||
|
teamId,
|
||||||
|
corpId: account.value.corpId
|
||||||
|
});
|
||||||
|
if (res && res.success && res.data) {
|
||||||
|
return res.data; // 返回 { userId: avatar } 的映射对象
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return { teams, chargeTeams, getTeam, getTeams, getTeamMemberAvatars }
|
||||||
})
|
})
|
||||||
@ -25,7 +25,8 @@ const urlsConfig = {
|
|||||||
createOwnTeam: 'createOwnTeam',
|
createOwnTeam: 'createOwnTeam',
|
||||||
removeTeammate: "removeTeammate",
|
removeTeammate: "removeTeammate",
|
||||||
toggleTeamLeaderRole: "toggleTeamLeaderRole",
|
toggleTeamLeaderRole: "toggleTeamLeaderRole",
|
||||||
joinTheInvitedTeam: 'joinTheInvitedTeam'
|
joinTheInvitedTeam: 'joinTheInvitedTeam',
|
||||||
|
getTeamMemberAvatars: 'getTeamMemberAvatars'
|
||||||
},
|
},
|
||||||
|
|
||||||
knowledgeBase: {
|
knowledgeBase: {
|
||||||
|
|||||||
@ -60,7 +60,7 @@ export async function mergeConversationWithGroupDetails(conversationList, option
|
|||||||
const formattedList = mergedList
|
const formattedList = mergedList
|
||||||
.map((group) => ({
|
.map((group) => ({
|
||||||
conversationID: group.conversationID || `GROUP${group.groupID}`,
|
conversationID: group.conversationID || `GROUP${group.groupID}`,
|
||||||
avatar: group.avatar || "/static/default-avatar.png",
|
avatar: group.avatar || "/static/default-patient-avatar.png",
|
||||||
lastMessage: group.lastMessage || "暂无消息",
|
lastMessage: group.lastMessage || "暂无消息",
|
||||||
lastMessageTime: group.lastMessageTime || Date.now(),
|
lastMessageTime: group.lastMessageTime || Date.now(),
|
||||||
groupID: group.groupID,
|
groupID: group.groupID,
|
||||||
@ -150,7 +150,7 @@ function mergeConversationData(conversation, groupDetailsMap) {
|
|||||||
name: formatConversationName(groupDetail),
|
name: formatConversationName(groupDetail),
|
||||||
|
|
||||||
// 更新头像(优先使用已有头像,避免闪动)
|
// 更新头像(优先使用已有头像,避免闪动)
|
||||||
avatar: conversation.avatar || groupDetail.patient?.avatar || '/static/default-avatar.png'
|
avatar: conversation.avatar || groupDetail.patient?.avatar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1086,7 +1086,7 @@ class TimChatManager {
|
|||||||
const groupInfo = {
|
const groupInfo = {
|
||||||
groupID: groupID,
|
groupID: groupID,
|
||||||
name: group?.name || '问诊群聊',
|
name: group?.name || '问诊群聊',
|
||||||
avatar: '/static/home/avatar.svg',
|
// avatar: '/static/home/avatar.svg',
|
||||||
memberCount: group?.memberCount || 0
|
memberCount: group?.memberCount || 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1172,7 +1172,7 @@ class TimChatManager {
|
|||||||
name: conversation.groupProfile?.name || '问诊群聊',
|
name: conversation.groupProfile?.name || '问诊群聊',
|
||||||
doctorId: '',
|
doctorId: '',
|
||||||
patientName: '',
|
patientName: '',
|
||||||
avatar: '/static/home/avatar.svg',
|
// avatar: '/static/home/avatar.svg',
|
||||||
lastMessage: '获取失败',
|
lastMessage: '获取失败',
|
||||||
lastMessageTime: Date.now(),
|
lastMessageTime: Date.now(),
|
||||||
unreadCount: conversation.unreadCount || 0,
|
unreadCount: conversation.unreadCount || 0,
|
||||||
@ -1573,7 +1573,6 @@ class TimChatManager {
|
|||||||
} else if (dbMsg.createdAt) {
|
} else if (dbMsg.createdAt) {
|
||||||
lastTime = new Date(dbMsg.createdAt).getTime()
|
lastTime = new Date(dbMsg.createdAt).getTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建基础消息对象
|
// 构建基础消息对象
|
||||||
const message = {
|
const message = {
|
||||||
ID: dbMsg.MsgSeq || dbMsg._id || `db_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
ID: dbMsg.MsgSeq || dbMsg._id || `db_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
||||||
@ -2520,8 +2519,8 @@ class TimChatManager {
|
|||||||
return '[自定义消息]'
|
return '[自定义消息]'
|
||||||
}
|
}
|
||||||
|
|
||||||
const customData = typeof payload.data === 'string'
|
const customData = typeof payload.data === 'string'
|
||||||
? JSON.parse(payload.data)
|
? JSON.parse(payload.data)
|
||||||
: payload.data
|
: payload.data
|
||||||
|
|
||||||
const messageType = customData.messageType || customData.type
|
const messageType = customData.messageType || customData.type
|
||||||
@ -2569,7 +2568,6 @@ class TimChatManager {
|
|||||||
conversationID,
|
conversationID,
|
||||||
groupID,
|
groupID,
|
||||||
name: patientName ? `${patientName}的问诊` : groupName || '问诊群聊',
|
name: patientName ? `${patientName}的问诊` : groupName || '问诊群聊',
|
||||||
avatar: '/static/default-avatar.png',
|
|
||||||
lastMessage,
|
lastMessage,
|
||||||
lastMessageTime,
|
lastMessageTime,
|
||||||
unreadCount: conversation.unreadCount || 0,
|
unreadCount: conversation.unreadCount || 0,
|
||||||
@ -2582,7 +2580,6 @@ class TimChatManager {
|
|||||||
conversationID: conversation.conversationID,
|
conversationID: conversation.conversationID,
|
||||||
groupID: conversation.conversationID?.replace('GROUP', '') || '',
|
groupID: conversation.conversationID?.replace('GROUP', '') || '',
|
||||||
name: '问诊群聊',
|
name: '问诊群聊',
|
||||||
avatar: '/static/default-avatar.png',
|
|
||||||
lastMessage: '暂无消息',
|
lastMessage: '暂无消息',
|
||||||
lastMessageTime: Date.now(),
|
lastMessageTime: Date.now(),
|
||||||
unreadCount: 0,
|
unreadCount: 0,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user