|
|
@@ -84,12 +84,12 @@
|
|
|
<view class="timeline-item" v-for="(node, index) in timeline" :key="node.key || index">
|
|
|
<view class="timeline-dot"></view>
|
|
|
<view class="timeline-line" v-if="index !== timeline.length - 1"></view>
|
|
|
- <view class="timeline-content">
|
|
|
+ <view class="timeline-content" @tap="openPage(node)">
|
|
|
<view class="timeline-title-row">
|
|
|
- <text class="timeline-title">{{ node.desc }}</text>
|
|
|
+ <text :class="node.desc.indexOf('病历') > -1 ? 'timeline-title blue' : 'timeline-title'">{{ node.desc }}</text>
|
|
|
<text class="timeline-time">{{ node.datetime }}</text>
|
|
|
</view>
|
|
|
- <view class="timeline-tags" v-if="node.oper && node.oper !== '用户152'">
|
|
|
+ <view class="timeline-tags" v-if="node.oper && node.oper.indexOf('用户') < 0">
|
|
|
<text class="timeline-tag">{{ node.oper}}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
@@ -255,11 +255,62 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
</scroll-view>
|
|
|
+
|
|
|
+ <!-- 信息采集单(只读查看,复用 medicalRecord 的信息采集单模块) -->
|
|
|
+ <view class="info-form-mask" v-if="infoFormVisible" @tap="closeInfoForm">
|
|
|
+ <view class="info-form-panel" @tap.stop>
|
|
|
+ <view class="info-form-header">
|
|
|
+ <text class="info-form-title">门诊病历</text>
|
|
|
+ <text class="info-form-close" @tap="closeInfoForm">关闭</text>
|
|
|
+ </view>
|
|
|
+ <scroll-view class="info-form-body" scroll-y>
|
|
|
+ <view class="ph-info-collection" v-if="formData.length > 0">
|
|
|
+ <view class="ph-info-item" v-for="(item, index) in formData" :key="index">
|
|
|
+ <view class="ph-info-label">{{ item.label }}</view>
|
|
|
+ <!-- 图片类型:只读展示 -->
|
|
|
+ <view v-if="item.type === 'casepluginimage'" class="ph-info-image-box">
|
|
|
+ <block v-if="getImageList(item.key).length > 0">
|
|
|
+ <view class="ph-info-image-item" v-for="(imgUrl, imgIdx) in getImageList(item.key)" :key="imgIdx">
|
|
|
+ <image
|
|
|
+ class="ph-info-image"
|
|
|
+ :src="urlImage(imgUrl)"
|
|
|
+ mode="aspectFill"
|
|
|
+ @error="onImageError(item.key, imgIdx)"
|
|
|
+ @tap="previewImage(item.key, imgIdx)"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </block>
|
|
|
+ <view v-else class="ph-info-image-empty">暂无图片</view>
|
|
|
+ </view>
|
|
|
+ <!-- 下拉/单选等带选项类型:只读展示 label -->
|
|
|
+ <view
|
|
|
+ v-else-if="item.type === 'select' || item.type === 'radio' || item.type === 'checkbox'"
|
|
|
+ class="ph-info-value"
|
|
|
+ :class="{ 'ph-info-placeholder': !getDisplayValue(item) }"
|
|
|
+ >
|
|
|
+ {{ getDisplayValue(item) || '暂无' }}
|
|
|
+ </view>
|
|
|
+ <!-- 其他类型(input/date/textarea 等):只读值 -->
|
|
|
+ <view v-else class="ph-info-value" :class="{ 'ph-info-placeholder': !getDisplayValue(item) }">
|
|
|
+ {{ getDisplayValue(item) || '暂无' }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="ph-placeholder-box" v-if="infoFormLoading">
|
|
|
+ <text class="ph-placeholder-text">加载中...</text>
|
|
|
+ </view>
|
|
|
+ <view class="ph-placeholder-box" v-if="!infoFormLoading && formData.length === 0">
|
|
|
+ <text class="ph-placeholder-text">暂无信息采集数据</text>
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import { $http } from '../../../config/https.js';
|
|
|
+import httpConfig from '../../../config/httpConfig.js';
|
|
|
|
|
|
export default {
|
|
|
data() {
|
|
|
@@ -287,7 +338,15 @@ export default {
|
|
|
// 药品信息
|
|
|
drug: [],
|
|
|
// 其他医嘱
|
|
|
- otherOrder: []
|
|
|
+ otherOrder: [],
|
|
|
+ // 信息采集单(只读查看)
|
|
|
+ infoFormVisible: false,
|
|
|
+ infoFormLoading: false,
|
|
|
+ formData: [],
|
|
|
+ dataKeyObj: {},
|
|
|
+ formDataSource: {},
|
|
|
+ imageLoadError: {},
|
|
|
+ TempHtmlStr: ''
|
|
|
};
|
|
|
},
|
|
|
onLoad(options) {
|
|
|
@@ -366,6 +425,114 @@ export default {
|
|
|
urls: urls.length ? urls : [item.picture]
|
|
|
});
|
|
|
},
|
|
|
+ openPage(node) {
|
|
|
+ if (node.desc && node.desc.indexOf('病历') > -1) {
|
|
|
+ // 打开信息采集单(只读查看,不修改不保存)
|
|
|
+ this.loadInfoForm(node.recordID);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 关闭信息采集单弹窗
|
|
|
+ closeInfoForm() {
|
|
|
+ this.infoFormVisible = false;
|
|
|
+ },
|
|
|
+ // 加载信息采集单:拉取模板 + 历史详情回显
|
|
|
+ loadInfoForm(recordID) {
|
|
|
+ if (!recordID) return;
|
|
|
+ this.infoFormVisible = true;
|
|
|
+ this.infoFormLoading = true;
|
|
|
+ this.formData = [];
|
|
|
+ this.dataKeyObj = {};
|
|
|
+ this.formDataSource = {};
|
|
|
+ this.imageLoadError = {};
|
|
|
+ // 1. 获取模板信息(含 templateHtmlUrl,用于确认模板存在)
|
|
|
+ $http.post('', this, {
|
|
|
+ code: '06010115',
|
|
|
+ data: { params: [{ admID: this.admID }] },
|
|
|
+ success: (res) => {
|
|
|
+ let result = res.result || {};
|
|
|
+ this.TempHtmlStr = result.templateHtmlUrl || '';
|
|
|
+ if (!this.TempHtmlStr) {
|
|
|
+ this.infoFormLoading = false;
|
|
|
+ uni.showToast({ title: '未获取到信息采集单模板', icon: 'none' });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 2. 拉取历史病历详情(用于回显)
|
|
|
+ $http.post('', this, {
|
|
|
+ code: '06010117',
|
|
|
+ data: {
|
|
|
+ emrCode: '18060011',
|
|
|
+ params: [{
|
|
|
+ recordID: recordID
|
|
|
+ }]
|
|
|
+ },
|
|
|
+ success: (res) => {
|
|
|
+ let result = res.result || res.data || {};
|
|
|
+ let list = result.data || result.recordDetail || [];
|
|
|
+ // 构建 formData(标签/类型/key)与 formDataSource(值)
|
|
|
+ let formList = [];
|
|
|
+ let sourceMap = {};
|
|
|
+ (list || []).forEach((item) => {
|
|
|
+ let key = item.uniqueCode || item.metaDataCode || '';
|
|
|
+ let type = item.filedType || 'input';
|
|
|
+ if (type === 'image') type = 'casepluginimage';
|
|
|
+ if (!key) return;
|
|
|
+ formList.push({ key: key, label: item.uniqueName || item.metaDataDesc || key, type: type });
|
|
|
+ sourceMap[key] = item.filedText !== undefined ? item.filedText : '';
|
|
|
+ });
|
|
|
+ this.formData = formList;
|
|
|
+ this.formDataSource = sourceMap;
|
|
|
+ this.infoFormLoading = false;
|
|
|
+ },
|
|
|
+ fail: () => {
|
|
|
+ this.infoFormLoading = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 拼接图片地址
|
|
|
+ urlImage(val) {
|
|
|
+ if (!val) return '';
|
|
|
+ if (val.indexOf('http') === 0 || val.indexOf('//') === 0) return val;
|
|
|
+ let base = httpConfig.urlAddress || '';
|
|
|
+ return base + (val.indexOf('/') === 0 ? val : '/' + val);
|
|
|
+ },
|
|
|
+ // 获取某字段的图片地址数组
|
|
|
+ getImageList(key) {
|
|
|
+ let val = this.formDataSource[key];
|
|
|
+ if (!val) return [];
|
|
|
+ let arr = [];
|
|
|
+ if (typeof val === 'string') {
|
|
|
+ arr = val.split(',').filter((s) => s && s.trim());
|
|
|
+ } else if (Array.isArray(val)) {
|
|
|
+ arr = val;
|
|
|
+ } else {
|
|
|
+ arr = [val];
|
|
|
+ }
|
|
|
+ let errs = this.imageLoadError[key] || [];
|
|
|
+ return arr.map((s, idx) => (errs.indexOf(idx) > -1 ? '' : s)).filter(Boolean);
|
|
|
+ },
|
|
|
+ onImageError(key, idx) {
|
|
|
+ if (!this.imageLoadError[key]) {
|
|
|
+ this.$set(this.imageLoadError, key, []);
|
|
|
+ }
|
|
|
+ this.imageLoadError[key].push(idx);
|
|
|
+ },
|
|
|
+ previewImage(key, idx) {
|
|
|
+ const urls = this.getImageList(key);
|
|
|
+ if (!urls.length) return;
|
|
|
+ uni.previewImage({ current: urls[idx], urls: urls });
|
|
|
+ },
|
|
|
+ // 计算只读展示值
|
|
|
+ getDisplayValue(item) {
|
|
|
+ if (!item) return '';
|
|
|
+ let val = this.formDataSource[item.key];
|
|
|
+ if (val === undefined || val === null || val === '') return '';
|
|
|
+ if (item.type === 'casepluginimage') {
|
|
|
+ return this.getImageList(item.key).length > 0 ? '图片' : '';
|
|
|
+ }
|
|
|
+ // 接口已返回中文文本(filedText),直接展示
|
|
|
+ return val;
|
|
|
+ },
|
|
|
// 语音播放
|
|
|
playAudio(e) {
|
|
|
const item = e.currentTarget.dataset.page;
|
|
|
@@ -454,7 +621,8 @@ export default {
|
|
|
// 历程时间线(result.data)
|
|
|
if (Array.isArray(result.data)) {
|
|
|
that.timeline = result.data.map((n) => ({
|
|
|
- key: n.key,
|
|
|
+ key: n.index,
|
|
|
+ recordID: n.key,
|
|
|
desc: n.desc || '',
|
|
|
datetime: n.datetime || '',
|
|
|
oper: n.oper || ''
|
|
|
@@ -822,6 +990,10 @@ export default {
|
|
|
font-weight: 600;
|
|
|
color: #1f2329;
|
|
|
}
|
|
|
+.timeline-title.blue{
|
|
|
+ color: #2B84FF;
|
|
|
+ font-weight: 700;
|
|
|
+}
|
|
|
|
|
|
.timeline-time {
|
|
|
font-size: 24rpx;
|
|
|
@@ -1268,4 +1440,105 @@ export default {
|
|
|
font-size: 24rpx;
|
|
|
color: #4a5160;
|
|
|
}
|
|
|
+
|
|
|
+/* 信息采集单弹窗(只读查看) */
|
|
|
+.info-form-mask {
|
|
|
+ position: fixed;
|
|
|
+ left: 0;
|
|
|
+ top: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ background: rgba(0, 0, 0, 0.5);
|
|
|
+ z-index: 999;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+.info-form-panel {
|
|
|
+ width: 86%;
|
|
|
+ max-height: 80vh;
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.info-form-header {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 28rpx 32rpx;
|
|
|
+ border-bottom: 1rpx solid #eef0f4;
|
|
|
+}
|
|
|
+.info-form-title {
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #222;
|
|
|
+}
|
|
|
+.info-form-close {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #4f7cff;
|
|
|
+}
|
|
|
+.info-form-body {
|
|
|
+ padding: 24rpx 32rpx 40rpx;
|
|
|
+ max-height: 64vh;
|
|
|
+}
|
|
|
+.ph-info-collection {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+.ph-info-item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ padding: 20rpx 0;
|
|
|
+ border-bottom: 1rpx solid #f2f3f6;
|
|
|
+}
|
|
|
+.ph-info-label {
|
|
|
+ width: 220rpx;
|
|
|
+ flex-shrink: 0;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #8a909c;
|
|
|
+}
|
|
|
+.ph-info-value {
|
|
|
+ flex: 1;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #222;
|
|
|
+ word-break: break-all;
|
|
|
+}
|
|
|
+.ph-info-placeholder {
|
|
|
+ color: #b6bac2;
|
|
|
+}
|
|
|
+.ph-info-image-box {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 16rpx;
|
|
|
+}
|
|
|
+.ph-info-image-item {
|
|
|
+ width: 160rpx;
|
|
|
+ height: 160rpx;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ overflow: hidden;
|
|
|
+ background: #f2f3f6;
|
|
|
+}
|
|
|
+.ph-info-image {
|
|
|
+ width: 160rpx;
|
|
|
+ height: 160rpx;
|
|
|
+}
|
|
|
+.ph-info-image-empty {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #b6bac2;
|
|
|
+}
|
|
|
+.ph-placeholder-box {
|
|
|
+ padding: 80rpx 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+.ph-placeholder-text {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #b6bac2;
|
|
|
+}
|
|
|
</style>
|