Files
2026-09-24 16:25:22 +08:00

248 lines
6.2 KiB
Plaintext

<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>