1
This commit is contained in:
@@ -0,0 +1,356 @@
|
||||
<template>
|
||||
<hr-page page-bg="#F3F4F6" status-bg="#FFFFFF" nav-title="批量转运" @right-click="onHistory">
|
||||
<template v-slot:right>
|
||||
<text class="op-nav-act">历史</text>
|
||||
</template>
|
||||
|
||||
<view class="op-page">
|
||||
|
||||
<!-- ① 顶部:连续扫码 -->
|
||||
<hr-scan-cam :count="list.length" @scan="onScan" @manual="onManual"></hr-scan-cam>
|
||||
|
||||
<!-- ② 中部:伤员记录(唯一滚动区;死亡伤员不参与转运,故未列入) -->
|
||||
<hr-rec-list :list="list" @remove="onRemove" @clear="onClear"></hr-rec-list>
|
||||
|
||||
<!-- ③ 底部:转运表单 + 右下角悬浮提交 -->
|
||||
<view class="op-form">
|
||||
<text class="op-lb">接收医院</text>
|
||||
<view class="op-pick" @click="openHos">
|
||||
<text class="op-pick-n">{{ hospitalList[hosIdx] }}</text>
|
||||
<text :class="hospitalAvail[hosIdx] ? 'op-pick-b' : 'op-pick-b op-pick-b-no'">{{ hospitalBed[hosIdx] }}</text>
|
||||
<x-icon name="arrow-down-s-line" color="#9CA3AF" font-size="14"></x-icon>
|
||||
</view>
|
||||
|
||||
<text class="op-lb op-lb-gap">转运方式</text>
|
||||
<view class="hr-seg">
|
||||
<view v-for="(m, i) in modes" :key="i"
|
||||
:class="i == modeIdx ? 'hr-seg-i hr-seg-i-on' : 'hr-seg-i'" @click="modeIdx = i">
|
||||
<text :class="i == modeIdx ? 'op-seg-t op-seg-t-on' : 'op-seg-t'">{{ m }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<text class="op-lb op-lb-gap">随车联系人</text>
|
||||
<view class="op-foot">
|
||||
<view class="op-foot-col">
|
||||
<view class="hr-field">
|
||||
<text class="hr-field-label">姓名</text>
|
||||
<input class="hr-field-input" type="text" v-model="contactName" placeholder-style="color:#9CA3AF" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="op-foot-col op-foot-col-last">
|
||||
<view class="hr-field">
|
||||
<text class="hr-field-label">联系电话</text>
|
||||
<input class="hr-field-input" type="number" v-model="contactPhone" placeholder-style="color:#9CA3AF" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="op-send" @click="onSubmit">
|
||||
<x-icon name="check-line" color="#FFFFFF" font-size="24"></x-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 接收医院选择:hr-sheet 底部弹层(点击上方「接收医院」整行唤起) -->
|
||||
<template v-slot:overlay>
|
||||
<view v-if="hosSheet" class="hr-mask" @click="closeHos">
|
||||
<view class="hr-sheet" @click="stop">
|
||||
<view class="hr-sheet-h">
|
||||
<text class="hr-sheet-h-b">选择接收医院</text>
|
||||
<view class="hr-sheet-h-x" @click="closeHos">
|
||||
<x-icon name="close-line" color="#9CA3AF" font-size="18"></x-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view v-for="(h, i) in hospitalList" :key="i" :class="hosOptClass(i)" @click="pickHospital(i)">
|
||||
<view class="os-txt">
|
||||
<text :class="hosNameClass(i)">{{ h }}</text>
|
||||
<text class="os-meta">{{ hospitalMeta[i] }}</text>
|
||||
</view>
|
||||
<text :class="hospitalAvail[i] ? 'op-pick-b' : 'op-pick-b op-pick-b-no'">{{ hospitalBed[i] }}</text>
|
||||
<x-icon v-if="i == hosIdx" name="check-line" color="#2563EB" font-size="17"></x-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</hr-page>
|
||||
</template>
|
||||
|
||||
<script lang="uts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { scanVictims, hospitalList, hospitalMeta, hospitalBed, hospitalAvail } from '@/mock/index.uts'
|
||||
import { HrVictim } from '@/mock/types.uts'
|
||||
import { navTo } from '@/utils/nav.uts'
|
||||
|
||||
/**
|
||||
* s44 批量转运(扫腕带 · 三段式作业页)
|
||||
* 与批量处置同构:顶部相机(点击开启)/ 中部记录列表 / 底部表单;
|
||||
* 底部换成 接收医院(hr-sheet 弹层选择)/ 转运方式 / 随车联系人。
|
||||
*/
|
||||
const modes : string[] = ['救护车 🚑', '直升机 🚁']
|
||||
const modeIdx = ref(0)
|
||||
const hosIdx = ref(0)
|
||||
const hosSheet = ref(false)
|
||||
const contactName = ref('刘伟')
|
||||
const contactPhone = ref('13800006621')
|
||||
|
||||
const list = ref<HrVictim[]>([
|
||||
scanVictims[0], scanVictims[1], scanVictims[2], scanVictims[3]
|
||||
])
|
||||
|
||||
/* ⚠ UTS 不提升函数声明,被调用的函数一律写在调用点之前 */
|
||||
|
||||
/** 把新伤员追加进列表(uvue 原地改数组不刷新,必须重建数组) */
|
||||
function push(v : HrVictim) : void {
|
||||
const arr : HrVictim[] = []
|
||||
for (let i = 0; i < list.value.length; i++) { arr.push(list.value[i]) }
|
||||
arr.push(v)
|
||||
list.value = arr
|
||||
}
|
||||
|
||||
function addByCode(code : string) : void {
|
||||
for (let i = 0; i < list.value.length; i++) {
|
||||
if (list.value[i].code == code) {
|
||||
uni.showToast({ title: '该伤员已在列表中', icon: 'none' })
|
||||
return
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < scanVictims.length; i++) {
|
||||
const v = scanVictims[i]
|
||||
if (v.code == code) {
|
||||
if (v.level == 4) {
|
||||
uni.showToast({ title: '死亡伤员不参与转运', icon: 'none' })
|
||||
return
|
||||
}
|
||||
push(v)
|
||||
uni.showToast({ title: '已加入 ' + v.name, icon: 'success' })
|
||||
return
|
||||
}
|
||||
}
|
||||
push({
|
||||
id: 'tmp_' + code, name: '未登记伤员', gender: '未知', age: 0, code: code, level: 3,
|
||||
injury: '待现场检伤补录', status: '', statusTheme: '', createdAt: ''
|
||||
} as HrVictim)
|
||||
uni.showToast({ title: '未登记腕带,已临时加入', icon: 'none' })
|
||||
}
|
||||
|
||||
function onScan(code : string) : void {
|
||||
addByCode(code)
|
||||
}
|
||||
|
||||
function onRemove(i : number) : void {
|
||||
const arr : HrVictim[] = []
|
||||
for (let k = 0; k < list.value.length; k++) {
|
||||
if (k != i) { arr.push(list.value[k]) }
|
||||
}
|
||||
list.value = arr
|
||||
}
|
||||
|
||||
function onClear() : void {
|
||||
uni.showModal({
|
||||
title: '清空列表',
|
||||
content: '将移除当前已识别的全部伤员记录,确认清空?',
|
||||
success: (res) => {
|
||||
if (res.confirm) { list.value = [] as HrVictim[] }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function onManual() : void {
|
||||
uni.showModal({
|
||||
title: '手动输入腕带编号',
|
||||
editable: true,
|
||||
placeholderText: '如 TRIAGE-20260922-0006',
|
||||
success: (res) => {
|
||||
if (!res.confirm) { return }
|
||||
const code = res.content
|
||||
if (code == null || code == '') { return }
|
||||
addByCode(code as string)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/* ---------- 接收医院:hr-sheet 底部弹层 ---------- */
|
||||
|
||||
function openHos() : void {
|
||||
hosSheet.value = true
|
||||
}
|
||||
|
||||
function closeHos() : void {
|
||||
hosSheet.value = false
|
||||
}
|
||||
|
||||
/** 点击弹层面板本身时阻止冒泡,避免误关闭 */
|
||||
function stop() : void {
|
||||
}
|
||||
|
||||
function hosOptClass(i : number) : string {
|
||||
if (i == hospitalList.length - 1) { return 'hr-sheet-opt hr-sheet-opt-last' }
|
||||
return 'hr-sheet-opt'
|
||||
}
|
||||
|
||||
/** 弹层选项:医院名(两行式第一行,选中蓝 / 满员置灰) */
|
||||
function hosNameClass(i : number) : string {
|
||||
if (!hospitalAvail[i]) { return 'os-name os-name-dim' }
|
||||
if (i == hosIdx.value) { return 'os-name os-name-on' }
|
||||
return 'os-name'
|
||||
}
|
||||
|
||||
function pickHospital(i : number) : void {
|
||||
if (!hospitalAvail[i]) {
|
||||
uni.showToast({ title: '该医院急诊已满员,不可选择', icon: 'none' })
|
||||
return
|
||||
}
|
||||
hosIdx.value = i
|
||||
hosSheet.value = false
|
||||
}
|
||||
|
||||
function onSubmit() : void {
|
||||
if (list.value.length == 0) {
|
||||
uni.showToast({ title: '请先扫码添加伤员', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (contactName.value == '' || contactPhone.value == '') {
|
||||
uni.showToast({ title: '请填写随车联系人', icon: 'none' })
|
||||
return
|
||||
}
|
||||
uni.showLoading({ title: '提交中' })
|
||||
setTimeout(() => {
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: '已转运登记 ' + list.value.length + ' 人', icon: 'success' })
|
||||
setTimeout(() => {
|
||||
navTo('/pages/triage/transfer')
|
||||
}, 700)
|
||||
}, 700)
|
||||
}
|
||||
|
||||
function onHistory() : void {
|
||||
navTo('/pages/triage/treat-records')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.op-page {
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.op-nav-act {
|
||||
font-size: 29.2rpx;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.op-form {
|
||||
background-color: #FFFFFF;
|
||||
border-top: 2rpx solid #E5E7EB;
|
||||
border-radius: 32rpx 32rpx 0rpx 0rpx;
|
||||
padding: 22rpx 32rpx 28rpx 32rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.op-lb {
|
||||
font-size: 25.8rpx;
|
||||
font-weight: bold;
|
||||
color: #6B7280;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.op-lb-gap {
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
|
||||
/* 接收医院:折叠字段(点击整行唤起 hr-sheet 弹层) */
|
||||
.op-pick {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
background-color: #F9FAFB;
|
||||
border: 2rpx solid #E5E7EB;
|
||||
border-radius: 20rpx;
|
||||
padding: 20rpx 24rpx 20rpx 24rpx;
|
||||
}
|
||||
|
||||
.op-pick-n {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
.op-pick-b {
|
||||
font-size: 22.4rpx;
|
||||
font-weight: bold;
|
||||
color: #059669;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.op-pick-b-no {
|
||||
color: #DC2626;
|
||||
}
|
||||
|
||||
/* 弹层选项:左侧「医院名 + 距离/预计时间」两行 */
|
||||
.os-txt {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.os-name {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
.os-name-on {
|
||||
color: #2563EB;
|
||||
}
|
||||
|
||||
.os-name-dim {
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.os-meta {
|
||||
font-size: 22.4rpx;
|
||||
color: #9CA3AF;
|
||||
margin-top: 6rpx;
|
||||
}
|
||||
|
||||
.op-seg-t {
|
||||
font-size: 29.2rpx;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.op-seg-t-on {
|
||||
color: #2563EB;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.op-foot {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding-right: 140rpx;
|
||||
}
|
||||
|
||||
.op-foot-col {
|
||||
flex: 1;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.op-foot-col-last {
|
||||
margin-right: 0rpx;
|
||||
}
|
||||
|
||||
.op-send {
|
||||
position: absolute;
|
||||
right: 32rpx;
|
||||
bottom: 32rpx;
|
||||
width: 112rpx;
|
||||
height: 112rpx;
|
||||
border-radius: 56rpx;
|
||||
background-image: linear-gradient(to bottom right, #2563EB, #1D4ED8);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 12rpx 36rpx rgba(37, 99, 235, 0.42);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,247 @@
|
||||
<template>
|
||||
<hr-page page-bg="#F3F4F6" status-bg="#FFFFFF" nav-title="批量处置" @right-click="onHistory">
|
||||
<template v-slot:right>
|
||||
<text class="op-nav-act">历史</text>
|
||||
</template>
|
||||
|
||||
<view class="op-page">
|
||||
|
||||
<!-- ① 顶部:连续扫码 -->
|
||||
<hr-scan-cam :count="list.length" @scan="onScan" @manual="onManual"></hr-scan-cam>
|
||||
|
||||
<!-- ② 中部:伤员记录(唯一滚动区) -->
|
||||
<hr-rec-list :list="list" @remove="onRemove" @clear="onClear"></hr-rec-list>
|
||||
|
||||
<!-- ③ 底部:处置表单 + 右下角悬浮提交 -->
|
||||
<view class="op-form">
|
||||
<text class="op-lb">处置类型</text>
|
||||
<view class="op-chips">
|
||||
<view v-for="(t, i) in types" :key="i" :class="i == typeIdx ? 'op-chip op-chip-on' : 'op-chip'"
|
||||
@click="typeIdx = i">
|
||||
<text :class="i == typeIdx ? 'op-chip-t op-chip-t-on' : 'op-chip-t'">{{ t }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<text class="op-lb op-lb-gap">处置内容</text>
|
||||
<textarea class="op-ta" v-model="content" placeholder="记录处置措施、用药与伤情变化…"
|
||||
placeholder-style="color:#9CA3AF" />
|
||||
<text class="op-note">提交后同时写入 {{ list.length }} 名伤员的处置记录</text>
|
||||
|
||||
<view class="op-send" @click="onSubmit">
|
||||
<x-icon name="check-line" color="#FFFFFF" font-size="24"></x-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</hr-page>
|
||||
</template>
|
||||
|
||||
<script lang="uts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { scanVictims, treatTypes } from '@/mock/index.uts'
|
||||
import { HrVictim } from '@/mock/types.uts'
|
||||
import { navTo } from '@/utils/nav.uts'
|
||||
|
||||
/**
|
||||
* s43 批量处置(扫腕带 · 三段式作业页)
|
||||
* 顶部相机(点击取景区才开启)→ 中部伤员记录滚动列表 → 底部处置表单 + 右下角悬浮提交。
|
||||
*/
|
||||
const types : string[] = treatTypes
|
||||
const typeIdx = ref(0)
|
||||
const content = ref('现场统一止血包扎,右前臂夹板固定,建立静脉通路并给氧。')
|
||||
|
||||
const list = ref<HrVictim[]>([
|
||||
scanVictims[0], scanVictims[1], scanVictims[2], scanVictims[3], scanVictims[4]
|
||||
])
|
||||
|
||||
/* ⚠ UTS 不提升函数声明,被调用的函数一律写在调用点之前 */
|
||||
|
||||
/** 把新伤员追加进列表(uvue 原地改数组不刷新,必须重建数组) */
|
||||
function push(v : HrVictim) : void {
|
||||
const arr : HrVictim[] = []
|
||||
for (let i = 0; i < list.value.length; i++) { arr.push(list.value[i]) }
|
||||
arr.push(v)
|
||||
list.value = arr
|
||||
}
|
||||
|
||||
function addByCode(code : string) : void {
|
||||
for (let i = 0; i < list.value.length; i++) {
|
||||
if (list.value[i].code == code) {
|
||||
uni.showToast({ title: '该伤员已在列表中', icon: 'none' })
|
||||
return
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < scanVictims.length; i++) {
|
||||
if (scanVictims[i].code == code) {
|
||||
push(scanVictims[i])
|
||||
uni.showToast({ title: '已加入 ' + scanVictims[i].name, icon: 'success' })
|
||||
return
|
||||
}
|
||||
}
|
||||
// 未登记腕带:兜底创建临时记录
|
||||
push({
|
||||
id: 'tmp_' + code, name: '未登记伤员', gender: '未知', age: 0, code: code, level: 3,
|
||||
injury: '待现场检伤补录', status: '', statusTheme: '', createdAt: ''
|
||||
} as HrVictim)
|
||||
uni.showToast({ title: '未登记腕带,已临时加入', icon: 'none' })
|
||||
}
|
||||
|
||||
/** 扫码结果处理:按腕带编码匹配伤员并加入列表 */
|
||||
function onScan(code : string) : void {
|
||||
addByCode(code)
|
||||
}
|
||||
|
||||
function onRemove(i : number) : void {
|
||||
const arr : HrVictim[] = []
|
||||
for (let k = 0; k < list.value.length; k++) {
|
||||
if (k != i) { arr.push(list.value[k]) }
|
||||
}
|
||||
list.value = arr
|
||||
}
|
||||
|
||||
function onClear() : void {
|
||||
uni.showModal({
|
||||
title: '清空列表',
|
||||
content: '将移除当前已识别的全部伤员记录,确认清空?',
|
||||
success: (res) => {
|
||||
if (res.confirm) { list.value = [] as HrVictim[] }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function onManual() : void {
|
||||
uni.showModal({
|
||||
title: '手动输入腕带编号',
|
||||
editable: true,
|
||||
placeholderText: '如 TRIAGE-20260922-0006',
|
||||
success: (res) => {
|
||||
if (!res.confirm) { return }
|
||||
const code = res.content
|
||||
if (code == null || code == '') { return }
|
||||
addByCode(code as string)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function onSubmit() : void {
|
||||
if (list.value.length == 0) {
|
||||
uni.showToast({ title: '请先扫码添加伤员', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (content.value == '') {
|
||||
uni.showToast({ title: '请填写处置内容', icon: 'none' })
|
||||
return
|
||||
}
|
||||
uni.showLoading({ title: '提交中' })
|
||||
setTimeout(() => {
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: '已写入 ' + list.value.length + ' 名伤员', icon: 'success' })
|
||||
setTimeout(() => {
|
||||
navTo('/pages/triage/treat-records')
|
||||
}, 700)
|
||||
}, 700)
|
||||
}
|
||||
|
||||
function onHistory() : void {
|
||||
navTo('/pages/triage/treat-records')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.op-page {
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.op-nav-act {
|
||||
font-size: 29.2rpx;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
/* ---------- 底部表单 ---------- */
|
||||
.op-form {
|
||||
background-color: #FFFFFF;
|
||||
border-top: 2rpx solid #E5E7EB;
|
||||
border-radius: 32rpx 32rpx 0rpx 0rpx;
|
||||
padding: 22rpx 32rpx 28rpx 32rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.op-lb {
|
||||
font-size: 25.8rpx;
|
||||
font-weight: bold;
|
||||
color: #6B7280;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.op-lb-gap {
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
|
||||
.op-chips {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.op-chip {
|
||||
height: 80rpx;
|
||||
border-radius: 20rpx;
|
||||
padding: 0rpx 26rpx 0rpx 26rpx;
|
||||
background-color: #FFFFFF;
|
||||
border: 2rpx solid #E5E7EB;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-right: 14rpx;
|
||||
margin-bottom: 14rpx;
|
||||
}
|
||||
|
||||
.op-chip-on {
|
||||
background-color: #2563EB;
|
||||
border: 2rpx solid #2563EB;
|
||||
}
|
||||
|
||||
.op-chip-t {
|
||||
font-size: 26.8rpx;
|
||||
font-weight: bold;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.op-chip-t-on {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.op-ta {
|
||||
width: 100%;
|
||||
background-color: #F9FAFB;
|
||||
border: 2rpx solid #E5E7EB;
|
||||
border-radius: 22rpx;
|
||||
padding: 20rpx 20rpx 20rpx 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #1F2937;
|
||||
height: 192rpx;
|
||||
}
|
||||
|
||||
.op-note {
|
||||
font-size: 23.6rpx;
|
||||
color: #9CA3AF;
|
||||
text-align: right;
|
||||
margin-top: 14rpx;
|
||||
padding-right: 140rpx;
|
||||
}
|
||||
|
||||
.op-send {
|
||||
position: absolute;
|
||||
right: 32rpx;
|
||||
bottom: 32rpx;
|
||||
width: 112rpx;
|
||||
height: 112rpx;
|
||||
border-radius: 56rpx;
|
||||
background-image: linear-gradient(to bottom right, #2563EB, #1D4ED8);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 12rpx 36rpx rgba(37, 99, 235, 0.42);
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,693 @@
|
||||
<template>
|
||||
<view class="hr-page" style="background-color:#F3F4F6">
|
||||
|
||||
<hr-statusbar bg="#FFFFFF"></hr-statusbar>
|
||||
|
||||
<!-- ============ 顶部伤情头信息 ============ -->
|
||||
<view class="dh">
|
||||
<view class="dh-c1"></view>
|
||||
<view class="dh-top">
|
||||
<view class="dh-back" @click="onBack">
|
||||
<x-icon name="arrow-left-s-line" color="#FFFFFF" font-size="20"></x-icon>
|
||||
</view>
|
||||
<text class="dh-title">伤员详情</text>
|
||||
<view class="hr-flex1"></view>
|
||||
<text class="dh-state">⌖ 转运中</text>
|
||||
</view>
|
||||
|
||||
<text class="dh-w">{{ victim.code }}</text>
|
||||
|
||||
<view class="dh-n">
|
||||
<text class="dh-name">{{ victim.name }}</text>
|
||||
<text class="dh-age">{{ victim.gender }} · {{ victim.age }} 岁</text>
|
||||
<view class="hr-flex1"></view>
|
||||
<view class="dh-level">
|
||||
<text class="dh-level-t">{{ levelLabel }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="dh-ch">
|
||||
<view class="dh-chip">
|
||||
<text class="dh-chip-t">⚑ 事件 EVT-20260922-014</text>
|
||||
</view>
|
||||
<view class="dh-chip">
|
||||
<text class="dh-chip-t">⌖ 转运中</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<text class="dh-foot">建档 14:23 · 操作人 张明 · 现场检伤组 3 组</text>
|
||||
</view>
|
||||
|
||||
<!-- ============ 快捷操作 ============ -->
|
||||
<view class="dh-acts">
|
||||
<view v-for="(a, i) in acts" :key="i" :class="i == 0 ? 'dha' : 'dha dha-sep'" @click="onAct(i)">
|
||||
<view class="dha-ic" :style="{ backgroundColor: a.bg }">
|
||||
<x-icon :name="a.icon" :color="a.color" font-size="32rpx"></x-icon>
|
||||
</view>
|
||||
<text class="dha-t" :style="{ color: a.color }">{{ a.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- ============ 分页 Tab(基本信息 / 伤情 / 转运 / 处置) ============ -->
|
||||
<x-tabs :list="tabList" :model-value="activeId" item-width="25%" height="84rpx" font-size="27rpx"
|
||||
active-font-size="27rpx" title-color="#6B7280" active-title-color="#2563EB" line-color="#2563EB"
|
||||
title-padding="0" :is-item-center="true" @change="onTabChange"></x-tabs>
|
||||
|
||||
<scroll-view class="hr-scroll" :scroll-y="true" :show-scrollbar="false">
|
||||
<view class="hr-body">
|
||||
|
||||
<!-- ---------- 基本信息 ---------- -->
|
||||
<view v-if="tab == 0">
|
||||
<hr-sec title="基本信息" more="编辑 ›" :first="true"></hr-sec>
|
||||
<view class="ig">
|
||||
<view class="ig-row">
|
||||
<view class="ig-it">
|
||||
<text class="ig-l">身份证号</text>
|
||||
<text class="ig-b">4406041991••••1234</text>
|
||||
</view>
|
||||
<view class="ig-it ig-it-r">
|
||||
<text class="ig-l">联系电话</text>
|
||||
<text class="ig-b">138••••6621</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="ig-row">
|
||||
<view class="ig-it">
|
||||
<text class="ig-l">送诊时间</text>
|
||||
<text class="ig-b">2026-09-22 14:35</text>
|
||||
</view>
|
||||
<view class="ig-it ig-it-r">
|
||||
<text class="ig-l">事件来源</text>
|
||||
<text class="ig-b">建筑坍塌 · 现场检伤</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="ig-row ig-row-last">
|
||||
<view class="ig-it">
|
||||
<text class="ig-l">检伤分级</text>
|
||||
<text class="ig-b" style="color:#B45309">{{ levelLabel }}</text>
|
||||
</view>
|
||||
<view class="ig-it ig-it-r">
|
||||
<text class="ig-l">检伤状态</text>
|
||||
<text class="ig-b">已检伤 · 转运中</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<hr-sec title="生命体征(最近一次 14:35)" more="趋势 ›"></hr-sec>
|
||||
<hr-card>
|
||||
<view class="vs5">
|
||||
<view v-for="(v, i) in vitals" :key="i"
|
||||
:class="v.abnormal ? 'vc vc-warn' : 'vc'">
|
||||
<text :class="v.abnormal ? 'vc-b vc-b-warn' : 'vc-b'">{{ v.value }}</text>
|
||||
<text :class="v.abnormal ? 'vc-s vc-s-warn' : 'vc-s'">{{ v.unit }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="dh-warn">
|
||||
<x-icon name="alert-line" color="#DC2626" font-size="14"></x-icon>
|
||||
<text class="dh-warn-t">脉搏偏快 · 血压偏低 · 血氧 88% 低于阈值,建议优先处置</text>
|
||||
</view>
|
||||
</hr-card>
|
||||
</view>
|
||||
|
||||
<!-- ---------- 伤情 ---------- -->
|
||||
<view v-if="tab == 1">
|
||||
<hr-sec title="伤情标记" more="查看人体图 ›" :first="true"></hr-sec>
|
||||
<hr-card>
|
||||
<view class="dh-mks">
|
||||
<view v-for="(m, i) in marks" :key="i" class="dh-mk">
|
||||
<view class="dh-mk-no" :style="{ backgroundColor: m.theme == 'red' ? '#DC2626' : '#F59E0B' }">
|
||||
<text class="dh-mk-no-t">{{ m.no }}</text>
|
||||
</view>
|
||||
<view class="hr-flex1">
|
||||
<text class="dh-mk-t">{{ m.title }}</text>
|
||||
<text class="dh-mk-s">{{ m.sub }}</text>
|
||||
</view>
|
||||
<text class="dh-mk-time">14:2{{ i + 3 }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</hr-card>
|
||||
|
||||
<hr-sec title="多模态记录" more="+ 添加 ›"></hr-sec>
|
||||
<hr-card>
|
||||
<text class="dh-desc">{{ victim.injury }}。14:23 于坍塌现场 B 区发现,俯卧位,呼之可睁眼。移除压覆物后前臂出现活动性出血,已加压包扎。</text>
|
||||
<view class="dh-upls">
|
||||
<view class="dh-upl">
|
||||
<x-icon name="image-line" color="#9CA3AF" font-size="19"></x-icon>
|
||||
<text class="dh-upl-t">现场照片</text>
|
||||
<view class="dh-upl-tag">
|
||||
<text class="dh-upl-tag-t">图片 · 1.2 MB</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="dh-upl">
|
||||
<x-icon name="music-2-line" color="#9CA3AF" font-size="19"></x-icon>
|
||||
<text class="dh-upl-t">现场录音</text>
|
||||
<view class="dh-upl-tag">
|
||||
<text class="dh-upl-tag-t">音频 · 0:42</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="dh-upl">
|
||||
<x-icon name="video-line" color="#9CA3AF" font-size="19"></x-icon>
|
||||
<text class="dh-upl-t">处置视频</text>
|
||||
<view class="dh-upl-tag">
|
||||
<text class="dh-upl-tag-t">视频 · 0:18</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</hr-card>
|
||||
</view>
|
||||
|
||||
<!-- ---------- 转运 ---------- -->
|
||||
<view v-if="tab == 2">
|
||||
<hr-sec title="转运信息" more="重新登记 ›" :first="true" @more-click="goTransfer"></hr-sec>
|
||||
<view class="ig">
|
||||
<view class="ig-row">
|
||||
<view class="ig-it">
|
||||
<text class="ig-l">接收医院</text>
|
||||
<text class="ig-b">协和医院 · 急诊创伤中心</text>
|
||||
</view>
|
||||
<view class="ig-it ig-it-r">
|
||||
<text class="ig-l">转运方式</text>
|
||||
<text class="ig-b">救护车 🚑</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="ig-row ig-row-last">
|
||||
<view class="ig-it">
|
||||
<text class="ig-l">转出方</text>
|
||||
<text class="ig-b">张明(急救中心)</text>
|
||||
</view>
|
||||
<view class="ig-it ig-it-r">
|
||||
<text class="ig-l">接收方</text>
|
||||
<text class="ig-b">刘伟(急诊创伤中心)</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<hr-sec title="流转时间线" more="全部 4 条"></hr-sec>
|
||||
<hr-card>
|
||||
<hr-timeline :nodes="timeline"></hr-timeline>
|
||||
</hr-card>
|
||||
</view>
|
||||
|
||||
<!-- ---------- 处置 ---------- -->
|
||||
<view v-if="tab == 3">
|
||||
<hr-sec title="处置记录" more="全部记录 ›" :first="true" @more-click="goRecords"></hr-sec>
|
||||
<hr-card>
|
||||
<hr-timeline :nodes="treatNodes"></hr-timeline>
|
||||
</hr-card>
|
||||
<view class="hr-btn hr-btn-soft" style="margin-top:12px" @click="goRecords">
|
||||
<x-icon name="add-line" color="#2563EB" font-size="16"></x-icon>
|
||||
<text class="dh-add-t">新增处置记录</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view style="height:14px"></view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="uts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { victimList, vitalSigns, injuryMarks, victimTimeline, treatRecords } from '@/mock/index.uts'
|
||||
import { HrVictim, HrVital, HrInjuryMark, HrTimelineNode } from '@/mock/types.uts'
|
||||
import { navTo, navBack } from '@/utils/nav.uts'
|
||||
import { TABS_ITEM_INFO, TABS_ITEM } from '@/uni_modules/tmx-ui/interface.uts'
|
||||
|
||||
/**
|
||||
* s21 伤员详情
|
||||
* 顶部伤情头信息 + 3 个快捷操作 + 4 个分页(基本信息 / 伤情 / 转运 / 处置,xTabs 驱动)。
|
||||
*/
|
||||
type QuickAct = { icon : string, name : string, color : string, bg : string }
|
||||
|
||||
const tabList : TABS_ITEM_INFO[] = [
|
||||
{ title: '基本信息', id: '0' } as TABS_ITEM_INFO,
|
||||
{ title: '伤情', id: '1' } as TABS_ITEM_INFO,
|
||||
{ title: '转运', id: '2' } as TABS_ITEM_INFO,
|
||||
{ title: '处置', id: '3' } as TABS_ITEM_INFO
|
||||
]
|
||||
const activeId = ref('0')
|
||||
|
||||
const tab = computed(() : number => {
|
||||
const i = parseInt(activeId.value)
|
||||
return isNaN(i) ? 0 : i
|
||||
})
|
||||
|
||||
const victim = ref<HrVictim>(victimList[1])
|
||||
const vitals = ref<HrVital[]>(vitalSigns)
|
||||
const marks = ref<HrInjuryMark[]>(injuryMarks)
|
||||
const timeline = ref<HrTimelineNode[]>(victimTimeline)
|
||||
const treatNodes = ref<HrTimelineNode[]>(treatRecords)
|
||||
|
||||
const acts : QuickAct[] = [
|
||||
{ icon: 'arrow-left-right-line', name: '调整分级', color: '#B45309', bg: '#FFFBEB' } as QuickAct,
|
||||
{ icon: 'route-line', name: '转运登记', color: '#2563EB', bg: '#EFF6FF' } as QuickAct,
|
||||
{ icon: 'phone-line', name: '联系家属', color: '#6B7280', bg: '#F3F4F6' } as QuickAct
|
||||
]
|
||||
|
||||
// ⚠ x-tabs 的 change 下发的是 TABS_ITEM(不是 TABS_ITEM_INFO),形参类型必须一致
|
||||
function onTabChange(item : TABS_ITEM, index : number) : void {
|
||||
activeId.value = item.id == '' ? index.toString() : item.id
|
||||
}
|
||||
|
||||
const levelLabel = computed(() : string => {
|
||||
const l = victim.value.level
|
||||
if (l == 1) { return '危重' }
|
||||
if (l == 2) { return '重伤' }
|
||||
if (l == 3) { return '轻伤' }
|
||||
return '死亡'
|
||||
})
|
||||
|
||||
onLoad((opt) => {
|
||||
const raw = opt['id']
|
||||
if (raw != null) {
|
||||
const id = raw as string
|
||||
for (let i = 0; i < victimList.length; i++) {
|
||||
if (victimList[i].id == id) {
|
||||
victim.value = victimList[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function onBack() : void {
|
||||
navBack()
|
||||
}
|
||||
|
||||
// ⚠ UTS 不提升函数声明:goTransfer 必须写在调用它的 onAct 之前
|
||||
function goTransfer() : void {
|
||||
navTo('/pages/triage/transfer')
|
||||
}
|
||||
|
||||
function onAct(i : number) : void {
|
||||
if (i == 0) {
|
||||
uni.showModal({
|
||||
title: '调整检伤分级',
|
||||
content: '当前分级:' + levelLabel.value + '\n调整后需现场检伤组复核。',
|
||||
cancelText: '取消',
|
||||
confirmText: '去调整',
|
||||
success: (res) => {
|
||||
if (res.confirm) { navTo('/pages/triage/create') }
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
if (i == 1) { goTransfer(); return }
|
||||
uni.showToast({ title: '正在呼叫登记的联系电话', icon: 'none' })
|
||||
}
|
||||
|
||||
function goRecords() : void {
|
||||
navTo('/pages/triage/treat-records')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.dh {
|
||||
background-image: linear-gradient(to bottom right, #F59E0B, #D97706);
|
||||
padding: 0rpx 28rpx 32rpx 28rpx;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dh-c1 {
|
||||
position: absolute;
|
||||
right: -80rpx;
|
||||
top: -100rpx;
|
||||
width: 300rpx;
|
||||
height: 300rpx;
|
||||
border-radius: 150rpx;
|
||||
background-color: rgba(255, 255, 255, 0.10);
|
||||
}
|
||||
|
||||
.dh-top {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding-top: 12rpx;
|
||||
}
|
||||
|
||||
.dh-back {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.dh-title {
|
||||
font-size: 31.4rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
margin-left: 4rpx;
|
||||
}
|
||||
|
||||
.dh-state {
|
||||
font-size: 26.8rpx;
|
||||
color: rgba(255, 255, 255, 0.92);
|
||||
}
|
||||
|
||||
.dh-w {
|
||||
font-size: 35.8rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
margin-top: 24rpx;
|
||||
letter-spacing: 0.8rpx;
|
||||
}
|
||||
|
||||
.dh-n {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
|
||||
.dh-name {
|
||||
font-size: 33.6rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.dh-age {
|
||||
font-size: 29.2rpx;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.dh-level {
|
||||
background-color: #FFFFFF;
|
||||
border-radius: 40rpx;
|
||||
padding: 4rpx 20rpx 4rpx 20rpx;
|
||||
}
|
||||
|
||||
.dh-level-t {
|
||||
font-size: 24.6rpx;
|
||||
font-weight: bold;
|
||||
color: #B45309;
|
||||
}
|
||||
|
||||
.dh-ch {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
|
||||
.dh-chip {
|
||||
background-color: rgba(255, 255, 255, 0.22);
|
||||
border: 2rpx solid rgba(255, 255, 255, 0.38);
|
||||
border-radius: 40rpx;
|
||||
padding: 4rpx 18rpx 4rpx 18rpx;
|
||||
margin-right: 12rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.dh-chip-t {
|
||||
font-size: 23.6rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.dh-foot {
|
||||
font-size: 24.6rpx;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
/* ---------- 快捷操作 ---------- */
|
||||
.dh-acts {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #FFFFFF;
|
||||
border-bottom: 2rpx solid #E5E7EB;
|
||||
}
|
||||
|
||||
.dha {
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 22rpx 8rpx 20rpx 8rpx;
|
||||
}
|
||||
|
||||
.dha-sep {
|
||||
border-left: 2rpx solid #E5E7EB;
|
||||
}
|
||||
|
||||
.dha-ic {
|
||||
width: 68rpx;
|
||||
height: 68rpx;
|
||||
border-radius: 22rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.dha-ic-t {
|
||||
font-size: 35.8rpx;
|
||||
}
|
||||
|
||||
.dha-t {
|
||||
font-size: 25.8rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* ---------- 分页 Tab ---------- */
|
||||
.tabs2 {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #FFFFFF;
|
||||
border-bottom: 2rpx solid #E5E7EB;
|
||||
padding: 0rpx 8rpx 0rpx 8rpx;
|
||||
}
|
||||
|
||||
.tabs2-tb {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-top: 20rpx;
|
||||
padding-bottom: 18rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tabs2-t {
|
||||
font-size: 28rpx;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.tabs2-t-on {
|
||||
color: #2563EB;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tabs2-bar {
|
||||
position: absolute;
|
||||
bottom: 0rpx;
|
||||
width: 52rpx;
|
||||
height: 5rpx;
|
||||
border-radius: 4rpx;
|
||||
background-color: #2563EB;
|
||||
}
|
||||
|
||||
/* ---------- 信息栅格 ---------- */
|
||||
.ig {
|
||||
border: 2rpx solid #E5E7EB;
|
||||
border-radius: 24rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ig-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
border-bottom: 2rpx solid #E5E7EB;
|
||||
}
|
||||
|
||||
.ig-row-last {
|
||||
border-bottom-width: 0rpx;
|
||||
}
|
||||
|
||||
.ig-it {
|
||||
flex: 1;
|
||||
background-color: #FFFFFF;
|
||||
padding: 18rpx 20rpx 18rpx 20rpx;
|
||||
}
|
||||
|
||||
.ig-it-r {
|
||||
border-left: 2rpx solid #E5E7EB;
|
||||
}
|
||||
|
||||
.ig-l {
|
||||
font-size: 23.6rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
.ig-b {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
margin-top: 6rpx;
|
||||
}
|
||||
|
||||
/* ---------- 生命体征 ---------- */
|
||||
.vs5 {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.vc {
|
||||
flex: 1;
|
||||
background-color: #F9FAFB;
|
||||
border: 2rpx solid #E5E7EB;
|
||||
border-radius: 18rpx;
|
||||
padding: 16rpx 2rpx 16rpx 2rpx;
|
||||
align-items: center;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.vc-warn {
|
||||
background-color: #FEF2F2;
|
||||
border: 2rpx solid #FECACA;
|
||||
}
|
||||
|
||||
.vc-b {
|
||||
font-size: 30.2rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
.vc-b-warn {
|
||||
color: #DC2626;
|
||||
}
|
||||
|
||||
.vc-s {
|
||||
font-size: 20.2rpx;
|
||||
color: #9CA3AF;
|
||||
margin-top: 6rpx;
|
||||
}
|
||||
|
||||
.vc-s-warn {
|
||||
color: #B91C1C;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.dh-warn {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.dh-warn-t {
|
||||
flex: 1;
|
||||
font-size: 24.6rpx;
|
||||
color: #DC2626;
|
||||
margin-left: 12rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* ---------- 伤情标记 ---------- */
|
||||
.dh-mks {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.dh-mk {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
background-color: #F9FAFB;
|
||||
border: 2rpx solid #E5E7EB;
|
||||
border-radius: 22rpx;
|
||||
padding: 20rpx 24rpx 20rpx 24rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.dh-mk-no {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
border-radius: 22rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.dh-mk-no-t {
|
||||
font-size: 24.6rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.dh-mk-t {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
.dh-mk-s {
|
||||
font-size: 23.6rpx;
|
||||
color: #9CA3AF;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.dh-mk-time {
|
||||
font-size: 23.6rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
/* ---------- 多模态 ---------- */
|
||||
.dh-desc {
|
||||
font-size: 26.8rpx;
|
||||
color: #6B7280;
|
||||
line-height: 1.65;
|
||||
}
|
||||
|
||||
.dh-upls {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.dh-upl {
|
||||
width: 31%;
|
||||
height: 168rpx;
|
||||
border-radius: 22rpx;
|
||||
background-color: #F9FAFB;
|
||||
border: 2rpx solid #E5E7EB;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 2.5%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dh-upl-t {
|
||||
font-size: 23.6rpx;
|
||||
color: #9CA3AF;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.dh-upl-tag {
|
||||
position: absolute;
|
||||
left: 0rpx;
|
||||
right: 0rpx;
|
||||
bottom: 0rpx;
|
||||
background-color: rgba(17, 24, 39, 0.62);
|
||||
padding: 4rpx 0rpx 4rpx 0rpx;
|
||||
}
|
||||
|
||||
.dh-upl-tag-t {
|
||||
font-size: 21.2rpx;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dh-add-t {
|
||||
font-size: 31.4rpx;
|
||||
font-weight: bold;
|
||||
color: #2563EB;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<hr-page page-bg="#F3F4F6" status-bg="#FFFFFF" nav-title="离线同步" :xloading="true" @right-click="onSort">
|
||||
<template v-slot:right>
|
||||
<x-icon name="arrow-up-down-line" color="#6B7280" font-size="17"></x-icon>
|
||||
</template>
|
||||
|
||||
<view class="hr-body">
|
||||
|
||||
<view class="os-box">
|
||||
<x-icon name="cloud-off-line" color="#92400E" font-size="15"></x-icon>
|
||||
<text class="os-box-t">当前网络不可用,以下记录已暂存本机</text>
|
||||
<view class="hr-offbar-cnt">
|
||||
<text class="os-box-c">{{ pendingCount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<hr-sec title="待上传队列" :more="'共 ' + tasks.length + ' 条'"></hr-sec>
|
||||
<hr-card variant="list">
|
||||
<hr-lrow v-for="(t, i) in tasks" :key="i" :icon="t.icon" :theme="t.theme" :title="t.title"
|
||||
:sub="t.sub" :value="t.status" :value-bold="true" :is-last="i == tasks.length - 1"
|
||||
@click="onTaskClick(t)"></hr-lrow>
|
||||
</hr-card>
|
||||
|
||||
<hr-tip style="margin-top:14px" theme="info" icon="ℹ"
|
||||
text="提交失败的记录会自动进入本队列;网络恢复后按时间顺序自动重传,无需手动操作。"></hr-tip>
|
||||
|
||||
<view v-if="syncing" class="os-progress">
|
||||
<view class="hr-row-between" style="margin-bottom:9px">
|
||||
<text class="os-p-t">正在重传…</text>
|
||||
<text class="os-p-v">{{ progress }}%</text>
|
||||
</view>
|
||||
<hr-progress :percent="progress"></hr-progress>
|
||||
</view>
|
||||
|
||||
<view style="height:14px"></view>
|
||||
</view>
|
||||
|
||||
<template v-slot:footer>
|
||||
<view class="hr-fixedbar">
|
||||
<view :class="syncing ? 'hr-btn hr-btn-disabled' : 'hr-btn hr-btn-primary'" style="flex:1"
|
||||
@click="onRetryAll">
|
||||
<text class="os-foot-t">{{ syncing ? '正在重传…' : '立即重试全部上传' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</hr-page>
|
||||
</template>
|
||||
|
||||
<script lang="uts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { offlineTasks } from '@/mock/index.uts'
|
||||
import { HrOfflineTask } from '@/mock/types.uts'
|
||||
|
||||
/**
|
||||
* s19 离线同步
|
||||
* 提交失败就地拦截 + 进离线队列;网络恢复后按时间顺序自动重传。
|
||||
*/
|
||||
const tasks = ref<HrOfflineTask[]>(offlineTasks)
|
||||
const syncing = ref(false)
|
||||
const progress = ref(0)
|
||||
let timer : number = 0
|
||||
|
||||
const pendingCount = computed(() : number => {
|
||||
return tasks.value.length
|
||||
})
|
||||
|
||||
function onTaskClick(t : HrOfflineTask) : void {
|
||||
uni.showModal({ title: t.title, content: t.sub, showCancel: false })
|
||||
}
|
||||
|
||||
function onRetryAll() : void {
|
||||
if (syncing.value) { return }
|
||||
syncing.value = true
|
||||
progress.value = 0
|
||||
timer = setInterval(() => {
|
||||
progress.value = progress.value + 10
|
||||
if (progress.value >= 100) {
|
||||
clearInterval(timer)
|
||||
timer = 0
|
||||
syncing.value = false
|
||||
tasks.value = [] as HrOfflineTask[]
|
||||
uni.showToast({ title: '全部同步完成', icon: 'success' })
|
||||
}
|
||||
}, 260)
|
||||
}
|
||||
|
||||
function onSort() : void {
|
||||
uni.showToast({ title: '按暂存时间排序', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.os-box {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
background-color: #FFFBEB;
|
||||
border: 2rpx solid #FDE68A;
|
||||
border-radius: 24rpx;
|
||||
padding: 18rpx 32rpx 18rpx 32rpx;
|
||||
}
|
||||
|
||||
.os-box-t {
|
||||
flex: 1;
|
||||
font-size: 26.8rpx;
|
||||
font-weight: bold;
|
||||
color: #92400E;
|
||||
margin-left: 18rpx;
|
||||
}
|
||||
|
||||
.os-box-c {
|
||||
font-size: 22.4rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.os-progress {
|
||||
margin-top: 28rpx;
|
||||
}
|
||||
|
||||
.os-p-t {
|
||||
font-size: 26.8rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
.os-p-v {
|
||||
font-size: 25.8rpx;
|
||||
font-weight: bold;
|
||||
color: #2563EB;
|
||||
}
|
||||
|
||||
.os-foot-t {
|
||||
font-size: 32.4rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,246 @@
|
||||
<template>
|
||||
<hr-page page-bg="#F3F4F6" status-bg="#FFFFFF" nav-title="转运登记" @right-click="onMore">
|
||||
<template v-slot:right>
|
||||
<x-icon name="more-fill" color="#6B7280" font-size="18"></x-icon>
|
||||
</template>
|
||||
|
||||
<view class="hr-body">
|
||||
|
||||
<!-- ============ 伤员摘要 ============ -->
|
||||
<hr-card>
|
||||
<view class="hr-row">
|
||||
<view class="tr-bar"></view>
|
||||
<view class="hr-flex1">
|
||||
<view class="hr-row">
|
||||
<text class="tr-name">李华</text>
|
||||
<text class="tr-sub">男 · 35 岁</text>
|
||||
<view class="hr-flex1"></view>
|
||||
<hr-wb :level="2"></hr-wb>
|
||||
</view>
|
||||
<text class="tr-inj">头部开放性外伤 · 右前臂骨折 · 已夹板固定</text>
|
||||
</view>
|
||||
</view>
|
||||
</hr-card>
|
||||
|
||||
<!-- ============ 接收医院(床位实时查询) ============ -->
|
||||
<hr-sec title="接收医院" more="🔍 搜索" @more-click="onSearchHos"></hr-sec>
|
||||
<hr-card variant="list">
|
||||
<view v-for="(h, i) in hospitalList" :key="i" :class="hosClass(i)" @click="pickHospital(i)">
|
||||
<view :class="i == hosIdx ? 'tr-radio tr-radio-on' : 'tr-radio'"></view>
|
||||
<view class="hr-flex1">
|
||||
<text class="tr-hos-n">{{ h }}</text>
|
||||
<text class="tr-hos-s">{{ hospitalMeta[i] }}</text>
|
||||
</view>
|
||||
<text :class="hospitalAvail[i] ? 'tr-hos-b' : 'tr-hos-b tr-hos-b-no'">{{ hospitalBed[i] }}</text>
|
||||
</view>
|
||||
</hr-card>
|
||||
|
||||
<hr-tip style="margin-top:10px" theme="warn" icon="⚠"
|
||||
text="同仁医院急诊床位已满,不可选择。若接收医院拒绝接收,系统将自动回到本页提示重派。"></hr-tip>
|
||||
|
||||
<!-- ============ 转运方式 ============ -->
|
||||
<hr-sec title="转运方式" :first="false"></hr-sec>
|
||||
<view class="hr-seg">
|
||||
<view v-for="(m, i) in modes" :key="i" :class="i == modeIdx ? 'hr-seg-i hr-seg-i-on' : 'hr-seg-i'"
|
||||
@click="modeIdx = i">
|
||||
<text :class="i == modeIdx ? 'tr-seg-t tr-seg-t-on' : 'tr-seg-t'">{{ m }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- ============ 随车联系人 ============ -->
|
||||
<hr-sec title="随车联系人"></hr-sec>
|
||||
<view class="hr-field">
|
||||
<text class="hr-field-label">接收方联系人</text>
|
||||
<input class="hr-field-input" type="text" v-model="contact" placeholder-style="color:#9CA3AF" />
|
||||
</view>
|
||||
<view class="hr-field" style="margin-top:9px">
|
||||
<text class="hr-field-label">联系电话</text>
|
||||
<input class="hr-field-input hr-mono" type="number" v-model="phone" placeholder-style="color:#9CA3AF" />
|
||||
</view>
|
||||
|
||||
<view style="height:14px"></view>
|
||||
</view>
|
||||
|
||||
<template v-slot:footer>
|
||||
<view class="hr-fixedbar">
|
||||
<view class="hr-btn hr-btn-ghost tr-foot-cancel" @click="onCancel">
|
||||
<text class="tr-foot-t">取消</text>
|
||||
</view>
|
||||
<view class="hr-btn hr-btn-primary" style="flex:1" @click="onSubmit">
|
||||
<text class="tr-foot-t2">转运登记</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</hr-page>
|
||||
</template>
|
||||
|
||||
<script lang="uts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { hospitalList, hospitalMeta, hospitalBed, hospitalAvail } from '@/mock/index.uts'
|
||||
import { navBack } from '@/utils/nav.uts'
|
||||
|
||||
/**
|
||||
* s14 转运登记
|
||||
* 接收医院床位实时查询,满员自动拦截并提示重派。
|
||||
*/
|
||||
const modes : string[] = ['救护车 🚑', '直升机 🚁']
|
||||
const modeIdx = ref(0)
|
||||
const hosIdx = ref(0)
|
||||
const contact = ref('刘主任(急诊)')
|
||||
const phone = ref('13800006621')
|
||||
|
||||
function hosClass(i : number) : string {
|
||||
if (i == 0) {
|
||||
return i == hosIdx.value ? 'tr-hos tr-hos-on' : 'tr-hos'
|
||||
}
|
||||
if (i == 2) { return 'tr-hos tr-hos-dim' }
|
||||
return i == hosIdx.value ? 'tr-hos tr-hos-on' : 'tr-hos'
|
||||
}
|
||||
|
||||
function pickHospital(i : number) : void {
|
||||
if (!hospitalAvail[i]) {
|
||||
uni.showModal({
|
||||
title: '无法选择',
|
||||
content: '同仁医院急诊床位已满,请改选其他接收医院。',
|
||||
showCancel: false
|
||||
})
|
||||
return
|
||||
}
|
||||
hosIdx.value = i
|
||||
}
|
||||
|
||||
function onSearchHos() : void {
|
||||
uni.showToast({ title: '搜索附近的接收医院', icon: 'none' })
|
||||
}
|
||||
|
||||
function onSubmit() : void {
|
||||
if (contact.value == '' || phone.value == '') {
|
||||
uni.showToast({ title: '请填写随车联系人', icon: 'none' })
|
||||
return
|
||||
}
|
||||
uni.showLoading({ title: '登记中' })
|
||||
setTimeout(() => {
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: '转运登记成功', icon: 'success' })
|
||||
setTimeout(() => {
|
||||
navBack()
|
||||
}, 700)
|
||||
}, 700)
|
||||
}
|
||||
|
||||
function onCancel() : void {
|
||||
navBack()
|
||||
}
|
||||
|
||||
function onMore() : void {
|
||||
uni.showToast({ title: '转运单 / 取消转运', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.tr-bar {
|
||||
width: 12rpx;
|
||||
height: 76rpx;
|
||||
border-radius: 6rpx;
|
||||
background-color: #F59E0B;
|
||||
margin-right: 22rpx;
|
||||
}
|
||||
|
||||
.tr-name {
|
||||
font-size: 31.4rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.tr-sub {
|
||||
font-size: 25.8rpx;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.tr-inj {
|
||||
font-size: 24.6rpx;
|
||||
color: #9CA3AF;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.tr-hos {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding-top: 24rpx;
|
||||
padding-bottom: 24rpx;
|
||||
border-bottom: 2rpx solid #F3F4F6;
|
||||
}
|
||||
|
||||
.tr-hos-on {
|
||||
/* 选中态仅体现在单选圈 */
|
||||
}
|
||||
|
||||
.tr-hos-dim {
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
.tr-radio {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 20rpx;
|
||||
border: 3.2rpx solid #E5E7EB;
|
||||
margin-right: 22rpx;
|
||||
}
|
||||
|
||||
.tr-radio-on {
|
||||
border: 3.2rpx solid #2563EB;
|
||||
background-color: #2563EB;
|
||||
}
|
||||
|
||||
.tr-hos-n {
|
||||
font-size: 30.2rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
.tr-hos-s {
|
||||
font-size: 23.6rpx;
|
||||
color: #9CA3AF;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.tr-hos-b {
|
||||
font-size: 24.6rpx;
|
||||
font-weight: bold;
|
||||
color: #059669;
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
|
||||
.tr-hos-b-no {
|
||||
color: #DC2626;
|
||||
}
|
||||
|
||||
.tr-seg-t {
|
||||
font-size: 29.2rpx;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.tr-seg-t-on {
|
||||
color: #2563EB;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tr-foot-cancel {
|
||||
flex: 0 0 200rpx;
|
||||
margin-right: 18rpx;
|
||||
}
|
||||
|
||||
.tr-foot-t {
|
||||
font-size: 31.4rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
.tr-foot-t2 {
|
||||
font-size: 32.4rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<hr-page page-bg="#F3F4F6" status-bg="#FFFFFF" nav-title="处置记录 · 李华" :xloading="true"
|
||||
@right-click="onAdd">
|
||||
<template v-slot:right>
|
||||
<x-icon name="add-line" color="#6B7280" font-size="19"></x-icon>
|
||||
</template>
|
||||
|
||||
<view class="hr-body">
|
||||
|
||||
<!-- 处置类型筛选(组件库 xRadioButton 分段切换) -->
|
||||
<view style="margin-bottom:8rpx">
|
||||
<x-radio-button v-model="chipId" :list="chipTabs" height="64rpx" space="4rpx" round="22rpx"
|
||||
text-style="font-weight:bold;" bg-color="#E5E7EB" active-color="#2563EB"
|
||||
active-font-color="#FFFFFF" font-color="#6B7280" font-size="22rpx"></x-radio-button>
|
||||
</view>
|
||||
|
||||
<hr-card style="margin-top:10px">
|
||||
<hr-timeline :nodes="shownNodes"></hr-timeline>
|
||||
</hr-card>
|
||||
|
||||
<hr-empty v-if="shownNodes.length == 0" icon="▤" title="该分类下暂无处置记录"
|
||||
sub="切换其他分类,或点击右下角新增一条处置记录"></hr-empty>
|
||||
|
||||
<view style="height:14px"></view>
|
||||
</view>
|
||||
|
||||
<template v-slot:footer>
|
||||
<view class="hr-fixedbar">
|
||||
<view class="hr-btn hr-btn-primary" style="flex:1" @click="onAdd">
|
||||
<x-icon name="add-line" color="#FFFFFF" font-size="16"></x-icon>
|
||||
<text class="trc-foot-t">新增处置记录</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</hr-page>
|
||||
</template>
|
||||
|
||||
<script lang="uts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { treatRecords } from '@/mock/index.uts'
|
||||
import { HrTimelineNode } from '@/mock/types.uts'
|
||||
import { RADIO_BUTTON } from '@/uni_modules/tmx-ui/interface.uts'
|
||||
|
||||
/**
|
||||
* s15 处置记录
|
||||
* 按处置类型分类查看,时间线倒序。
|
||||
*/
|
||||
/**
|
||||
* 处置类型筛选(组件库 xRadioButton 分段切换,替代原 hr-chip 横向滚动)
|
||||
* ⚠ RADIO_BUTTON 的 id 是 string:统一用下标字符串,选中值即筛选序号。
|
||||
*/
|
||||
const chipTabs : RADIO_BUTTON[] = [
|
||||
{ id: '0', title: '全部 4' } as RADIO_BUTTON,
|
||||
{ id: '1', title: '止血 1' } as RADIO_BUTTON,
|
||||
{ id: '2', title: '循环 1' } as RADIO_BUTTON,
|
||||
{ id: '3', title: '分级 2' } as RADIO_BUTTON
|
||||
]
|
||||
const chipId = ref('0')
|
||||
/** 由字符串 id 换算分类序号,供 shownNodes 筛选使用 */
|
||||
const chip = computed(() : number => {
|
||||
const i = parseInt(chipId.value)
|
||||
return isNaN(i) ? 0 : i
|
||||
})
|
||||
|
||||
const shownNodes = computed(() : HrTimelineNode[] => {
|
||||
if (chip.value == 0) { return treatRecords }
|
||||
const kw = chip.value == 1 ? '止血' : (chip.value == 2 ? '静脉' : '分级')
|
||||
const arr : HrTimelineNode[] = []
|
||||
for (let i = 0; i < treatRecords.length; i++) {
|
||||
if (treatRecords[i].title.indexOf(kw) > -1) { arr.push(treatRecords[i]) }
|
||||
}
|
||||
return arr
|
||||
})
|
||||
|
||||
function onAdd() : void {
|
||||
uni.showModal({
|
||||
title: '新增处置记录',
|
||||
editable: true,
|
||||
placeholderText: '如:15:40 清创缝合完成',
|
||||
success: (res) => {
|
||||
if (!res.confirm) { return }
|
||||
const text = res.content
|
||||
if (text == null || text == '') { return }
|
||||
uni.showToast({ title: '处置记录已提交', icon: 'success' })
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.trc-foot-t {
|
||||
font-size: 32.4rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,432 @@
|
||||
<template>
|
||||
<hr-page page-bg="#F3F4F6" status-bg="#FFFFFF" nav-title="伤员查询" :xloading="true"
|
||||
@right-click="onSort">
|
||||
<template v-slot:right>
|
||||
<x-icon name="arrow-up-down-line" color="#6B7280" font-size="17"></x-icon>
|
||||
</template>
|
||||
|
||||
<!-- 离线条 -->
|
||||
<view class="hr-offbar" @click="goOffline">
|
||||
<x-icon name="cloud-off-line" color="#92400E" font-size="15"></x-icon>
|
||||
<text class="vs-off-t">离线中 · 数据暂存本地</text>
|
||||
<view class="hr-offbar-cnt">
|
||||
<text class="vs-off-cnt-t">3</text>
|
||||
</view>
|
||||
<text class="hr-offbar-go">查看队列 ›</text>
|
||||
</view>
|
||||
|
||||
<view class="hr-body">
|
||||
|
||||
<!-- ============ 搜索(xSearch) ============ -->
|
||||
<x-search v-model="keyword" placeholder="姓名 / 身份证 / 编号" round="24rpx" height="84rpx"
|
||||
:border="searchBorder" input-bg-color="#FFFFFF" icon-color="#9CA3AF" font-color="#1F2937"
|
||||
:show-cancel="false"></x-search>
|
||||
|
||||
<!-- ============ 双下拉筛选 ============ -->
|
||||
<view class="vs-filter">
|
||||
<view :class="levelIdx > 0 ? 'vs-sel vs-sel-on' : 'vs-sel'" @click="openSheet(0)">
|
||||
<text class="vs-sel-l">检伤等级</text>
|
||||
<text :class="levelIdx > 0 ? 'vs-sel-v vs-sel-v-on' : 'vs-sel-v'">{{ levelOptions[levelIdx] }}</text>
|
||||
<x-icon name="arrow-down-s-line" color="#9CA3AF" font-size="14"></x-icon>
|
||||
</view>
|
||||
<view :class="statusIdx > 0 ? 'vs-sel vs-sel-on' : 'vs-sel'"
|
||||
style="margin-left:8px" @click="openSheet(1)">
|
||||
<text class="vs-sel-l">检伤状态</text>
|
||||
<text :class="statusIdx > 0 ? 'vs-sel-v vs-sel-v-on' : 'vs-sel-v'">{{ statusOptions[statusIdx] }}</text>
|
||||
<x-icon name="arrow-down-s-line" color="#9CA3AF" font-size="14"></x-icon>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- ============ 伤员列表 ============ -->
|
||||
<view style="margin-top:4px">
|
||||
<view v-for="(v, i) in shown" :key="v.id" :class="cardClass(v.level)" @click="openDetail(v)">
|
||||
<view class="hr-row">
|
||||
<view :class="avatarClass(v.level)">
|
||||
<text class="vs-avt-t">{{ v.name.substring(0, 1) }}</text>
|
||||
</view>
|
||||
<view class="hr-flex1">
|
||||
<view class="hr-row">
|
||||
<text class="vs-name">{{ v.name }}</text>
|
||||
<hr-wb :level="v.level" small></hr-wb>
|
||||
</view>
|
||||
<text class="vs-code">{{ v.gender }} · {{ v.age }} 岁 · {{ v.code }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="vs-inj">
|
||||
<text class="vs-inj-t">伤情:{{ v.injury }}</text>
|
||||
</view>
|
||||
<view class="vs-bot">
|
||||
<view class="vs-status" :style="statusStyle(v.statusTheme)">
|
||||
<text class="vs-status-t" :style="statusTextStyle(v.statusTheme)">{{ v.status }}</text>
|
||||
</view>
|
||||
<view class="hr-flex1"></view>
|
||||
<text class="vs-time">{{ v.createdAt }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<hr-empty v-if="shown.length == 0" icon="♡" title="没有匹配的伤员"
|
||||
sub="换个筛选条件,或点击右上角扫码按腕带编号查询"></hr-empty>
|
||||
|
||||
<view v-if="shown.length > 0" class="vs-hint">
|
||||
<text class="vs-hint-t">✦ 点击卡片查看伤员详情</text>
|
||||
</view>
|
||||
|
||||
<view style="height:14px"></view>
|
||||
</view>
|
||||
|
||||
<!-- ============ 筛选选择器 ============ -->
|
||||
<template v-slot:overlay>
|
||||
<view v-if="sheet >= 0" class="hr-mask" @click="closeSheet">
|
||||
<view class="hr-sheet" @click="stop">
|
||||
<view class="hr-sheet-h">
|
||||
<text class="hr-sheet-h-b">{{ sheet == 0 ? '选择检伤等级' : '选择检伤状态' }}</text>
|
||||
<view class="hr-sheet-h-x" @click="closeSheet">
|
||||
<x-icon name="close-line" color="#9CA3AF" font-size="18"></x-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view v-for="(o, i) in currentOptions" :key="i" class="hr-sheet-opt"
|
||||
:class="i == currentOptions.length - 1 ? 'hr-sheet-opt-last' : ''" @click="pickOption(i)">
|
||||
<text :class="isPicked(i) ? 'hr-sheet-opt-t hr-sheet-opt-on' : 'hr-sheet-opt-t'">{{ o }}</text>
|
||||
<x-icon v-if="isPicked(i)" name="check-line" color="#2563EB" font-size="17"></x-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</hr-page>
|
||||
</template>
|
||||
|
||||
<script lang="uts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { victimList } from '@/mock/index.uts'
|
||||
import { HrVictim } from '@/mock/types.uts'
|
||||
import { navTo } from '@/utils/nav.uts'
|
||||
|
||||
/**
|
||||
* s04 伤员查询
|
||||
* 支持按「检伤等级 / 检伤状态」双下拉筛选 + 关键字搜索 + 扫码查询。
|
||||
*/
|
||||
const levelOptions : string[] = ['全部', '危重', '重伤', '轻伤', '死亡']
|
||||
const statusOptions : string[] = ['全部', '已检伤', '转运中', '待转运', '未转运']
|
||||
|
||||
const keyword = ref('')
|
||||
const levelIdx = ref(0)
|
||||
const statusIdx = ref(0)
|
||||
const sheet = ref(-1)
|
||||
const list = ref<HrVictim[]>(victimList)
|
||||
|
||||
/**
|
||||
* xSearch 的 border 是「数组」prop,固定 3 项 = [宽度, 线型, 颜色],
|
||||
* 少于 3 项内部直接返回 none。设计稿搜索框为 1px solid #E5E7EB。
|
||||
*/
|
||||
const searchBorder : string[] = ['1px', 'solid', '#E5E7EB']
|
||||
|
||||
const currentOptions = computed(() : string[] => {
|
||||
return sheet.value == 0 ? levelOptions : statusOptions
|
||||
})
|
||||
|
||||
const shown = computed(() : HrVictim[] => {
|
||||
const out : HrVictim[] = []
|
||||
for (let i = 0; i < list.value.length; i++) {
|
||||
const v = list.value[i]
|
||||
if (levelIdx.value > 0 && v.level != levelIdx.value) { continue }
|
||||
if (statusIdx.value > 0) {
|
||||
const label = statusOptions[statusIdx.value]
|
||||
if (label == '转运中' && v.status.indexOf('转运中') < 0) { continue }
|
||||
if (label == '待转运' && v.status.indexOf('待转运') < 0) { continue }
|
||||
if (label == '未转运' && v.status.indexOf('未转运') < 0) { continue }
|
||||
if (label == '已检伤' && v.status.indexOf('已转运') < 0 && v.status.indexOf('转运中') < 0) { continue }
|
||||
}
|
||||
if (keyword.value != '') {
|
||||
const kw = keyword.value.toLowerCase()
|
||||
const hit = v.name.toLowerCase().indexOf(kw) > -1 || v.code.toLowerCase().indexOf(kw) > -1
|
||||
if (!hit) { continue }
|
||||
}
|
||||
out.push(v)
|
||||
}
|
||||
return out
|
||||
})
|
||||
|
||||
function cardClass(level : number) : string {
|
||||
return `vs-card vs-card-l${level}`
|
||||
}
|
||||
|
||||
function avatarClass(level : number) : string {
|
||||
return `vs-avt vs-avt-l${level}`
|
||||
}
|
||||
|
||||
function statusStyle(theme : string) : string {
|
||||
if (theme == 'pri') { return 'background-color:#EFF6FF;border:1px solid #BFDBFE' }
|
||||
if (theme == 'amb') { return 'background-color:#FFFBEB;border:1px solid #FDE68A' }
|
||||
if (theme == 'grn') { return 'background-color:#ECFDF5;border:1px solid #A7F3D0' }
|
||||
return 'background-color:#F3F4F6;border:1px solid #E5E7EB'
|
||||
}
|
||||
|
||||
function statusTextStyle(theme : string) : string {
|
||||
if (theme == 'pri') { return 'color:#1D4ED8' }
|
||||
if (theme == 'amb') { return 'color:#B45309' }
|
||||
if (theme == 'grn') { return 'color:#047857' }
|
||||
return 'color:#6B7280'
|
||||
}
|
||||
|
||||
function openSheet(i : number) : void {
|
||||
sheet.value = i
|
||||
}
|
||||
|
||||
function closeSheet() : void {
|
||||
sheet.value = -1
|
||||
}
|
||||
|
||||
function stop() : void {
|
||||
// 阻止点击面板时关闭
|
||||
}
|
||||
|
||||
function isPicked(i : number) : boolean {
|
||||
return sheet.value == 0 ? levelIdx.value == i : statusIdx.value == i
|
||||
}
|
||||
|
||||
function pickOption(i : number) : void {
|
||||
if (sheet.value == 0) { levelIdx.value = i } else { statusIdx.value = i }
|
||||
sheet.value = -1
|
||||
}
|
||||
|
||||
function openDetail(v : HrVictim) : void {
|
||||
navTo('/pages/triage/detail?id=' + v.id)
|
||||
}
|
||||
|
||||
function onSort() : void {
|
||||
uni.showToast({ title: '按建档时间 / 分级排序', icon: 'none' })
|
||||
}
|
||||
|
||||
function goOffline() : void {
|
||||
navTo('/pages/triage/offline-sync')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.vs-off-t {
|
||||
font-size: 26.8rpx;
|
||||
font-weight: bold;
|
||||
color: #92400E;
|
||||
margin-left: 18rpx;
|
||||
}
|
||||
|
||||
.vs-off-cnt-t {
|
||||
font-size: 22.4rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
/* ---------- 搜索 ---------- */
|
||||
.vs-srch {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
background-color: #FFFFFF;
|
||||
border: 2rpx solid #E5E7EB;
|
||||
border-radius: 24rpx;
|
||||
height: 84rpx;
|
||||
padding: 0rpx 20rpx 0rpx 20rpx;
|
||||
}
|
||||
|
||||
.vs-srch-input {
|
||||
flex: 1;
|
||||
font-size: 29.2rpx;
|
||||
color: #1F2937;
|
||||
height: 80rpx;
|
||||
padding: 0rpx 16rpx 0rpx 16rpx;
|
||||
}
|
||||
|
||||
.vs-srch-scan {
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
border-radius: 16rpx;
|
||||
background-color: #EFF6FF;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.vs-scan-btn {
|
||||
width: 84rpx;
|
||||
height: 84rpx;
|
||||
border-radius: 24rpx;
|
||||
background-color: #EFF6FF;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
|
||||
/* ---------- 筛选 ---------- */
|
||||
.vs-filter {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.vs-sel {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
background-color: #FFFFFF;
|
||||
border: 2rpx solid #E5E7EB;
|
||||
border-radius: 22rpx;
|
||||
padding: 18rpx 22rpx 18rpx 22rpx;
|
||||
}
|
||||
|
||||
.vs-sel-on {
|
||||
border: 2rpx solid #2563EB;
|
||||
background-color: #EFF6FF;
|
||||
}
|
||||
|
||||
.vs-sel-l {
|
||||
font-size: 23.6rpx;
|
||||
color: #9CA3AF;
|
||||
margin-right: 14rpx;
|
||||
}
|
||||
|
||||
.vs-sel-v {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
lines: 1;
|
||||
}
|
||||
|
||||
.vs-sel-v-on {
|
||||
color: #2563EB;
|
||||
}
|
||||
|
||||
/* ---------- 伤员卡 ---------- */
|
||||
.vs-card {
|
||||
position: relative;
|
||||
background-color: #FFFFFF;
|
||||
border: 2rpx solid #E5E7EB;
|
||||
border-radius: 26rpx;
|
||||
padding: 22rpx 24rpx 22rpx 32rpx;
|
||||
margin-bottom: 18rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.vs-card-bar {
|
||||
position: absolute;
|
||||
left: 0rpx;
|
||||
top: 0rpx;
|
||||
bottom: 0rpx;
|
||||
width: 8rpx;
|
||||
}
|
||||
|
||||
.vs-card-l1 {
|
||||
border-left: 8rpx solid #DC2626;
|
||||
}
|
||||
|
||||
.vs-card-l2 {
|
||||
border-left: 8rpx solid #F59E0B;
|
||||
}
|
||||
|
||||
.vs-card-l3 {
|
||||
border-left: 8rpx solid #10B981;
|
||||
}
|
||||
|
||||
.vs-card-l4 {
|
||||
border-left: 8rpx solid #1F2937;
|
||||
}
|
||||
|
||||
.vs-avt {
|
||||
width: 76rpx;
|
||||
height: 76rpx;
|
||||
border-radius: 22rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.vs-avt-l1 {
|
||||
background-color: #DC2626;
|
||||
}
|
||||
|
||||
.vs-avt-l2 {
|
||||
background-color: #D97706;
|
||||
}
|
||||
|
||||
.vs-avt-l3 {
|
||||
background-color: #059669;
|
||||
}
|
||||
|
||||
.vs-avt-l4 {
|
||||
background-color: #1F2937;
|
||||
}
|
||||
|
||||
.vs-avt-t {
|
||||
font-size: 33.6rpx;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.vs-name {
|
||||
font-size: 30.2rpx;
|
||||
font-weight: bold;
|
||||
color: #1F2937;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.vs-code {
|
||||
font-size: 23.6rpx;
|
||||
color: #9CA3AF;
|
||||
margin-top: 6rpx;
|
||||
}
|
||||
|
||||
.vs-inj {
|
||||
margin-top: 16rpx;
|
||||
background-color: #F9FAFB;
|
||||
border-radius: 16rpx;
|
||||
padding: 12rpx 16rpx 12rpx 16rpx;
|
||||
}
|
||||
|
||||
.vs-inj-t {
|
||||
font-size: 24.6rpx;
|
||||
color: #6B7280;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.vs-bot {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
|
||||
.vs-status {
|
||||
border-radius: 18rpx;
|
||||
padding: 8rpx 20rpx 8rpx 20rpx;
|
||||
}
|
||||
|
||||
.vs-status-t {
|
||||
font-size: 24.6rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.vs-time {
|
||||
font-size: 23.6rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
.vs-hint {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 12rpx 0rpx 16rpx 0rpx;
|
||||
}
|
||||
|
||||
.vs-hint-t {
|
||||
font-size: 23.6rpx;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user