| | |
| | | <!-- 表单内容 --> |
| | | <scroll-view scroll-y class="form-scroll" :show-scrollbar="false"> |
| | | <view class="form-content"> |
| | | <!-- 案例信息卡片 --> |
| | | <view class="form-section" v-if="transportData.caseNo"> |
| | | <view class="section-header"> |
| | | <view class="section-icon">📋</view> |
| | | <text class="section-title">关联案例信息</text> |
| | | </view> |
| | | |
| | | <view class="case-info"> |
| | | <view class="info-row"> |
| | | <text class="info-label">案例编号:</text> |
| | | <text class="info-value">{{ transportData.caseNo }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">患者姓名:</text> |
| | | <text class="info-value">{{ transportData.patName }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">性别/年龄:</text> |
| | | <text class="info-value" |
| | | >{{ getGenderText(transportData.sex) }} / |
| | | {{ transportData.age }}岁</text |
| | | > |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">疾病诊断:</text> |
| | | <text class="info-value">{{ transportData.diagnosisname }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">治疗医院:</text> |
| | | <text class="info-value">{{ |
| | | transportData.treatmentHospitalName |
| | | }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 基础信息卡片 --> |
| | | <view class="form-section"> |
| | | <view class="section-header"> |
| | | <view class="section-icon">📋</view> |
| | | <text class="section-title">基础信息</text> |
| | | </view> |
| | | |
| | | <view class="form-grid"> |
| | | <view class="form-item"> |
| | | <text class="item-label required">案例选择</text> |
| | | <u-input |
| | | v-model="form.caseInfo.donorName" |
| | | placeholder="选择案例" |
| | | readonly |
| | | border="none" |
| | | @click="showCasePicker = true" |
| | | :customStyle="inputStyle(!form.caseInfo.caseId)" |
| | | > |
| | | <template #suffix> |
| | | <u-icon name="arrow-down" color="#86868b"></u-icon> |
| | | </template> |
| | | </u-input> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <text class="item-label required">捐献医院</text> |
| | | <u-input |
| | | v-model="form.hospital" |
| | | placeholder="请输入捐献医院" |
| | | border="none" |
| | | :customStyle="inputStyle(!form.hospital)" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <text class="item-label">科室</text> |
| | | <u-input |
| | | v-model="form.department" |
| | | placeholder="请输入科室" |
| | | border="none" |
| | | /> |
| | | <view class="section-icon">📄</view> |
| | | <text class="section-title">转运单信息</text> |
| | | <!-- 状态标签 --> |
| | | <view |
| | | class="status-tag" |
| | | :class="getTransportStatusClass(transportData.transitStatus)" |
| | | > |
| | | {{ getTransportStatusText(transportData.transitStatus) }} |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 转运信息卡片 --> |
| | | <view class="form-section"> |
| | | <view class="section-header"> |
| | | <view class="section-icon">🚑</view> |
| | | <text class="section-title">转运信息</text> |
| | | </view> |
| | | |
| | | <view class="form-grid"> |
| | | <view class="form-item"> |
| | | <text class="item-label">转运单号</text> |
| | | <u-input |
| | | v-model="transportData.reportId" |
| | | placeholder="自动生成" |
| | | disabled |
| | | :disabledColor="disabledColor" |
| | | border="none" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <text class="item-label required">出发地点</text> |
| | | <u-input |
| | | v-model="transportData.transportStartPlace" |
| | | placeholder="请输入出发地点" |
| | | border="none" |
| | | :readonly="!isEdit" |
| | | :customStyle="inputStyle(!transportData.transportStartPlace)" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <text class="item-label required">出发时间</text> |
| | | <u-input |
| | | v-model="form.departureTime" |
| | | v-model="transportData.transportStartTime" |
| | | placeholder="请选择出发时间" |
| | | readonly |
| | | border="none" |
| | | @click="showTimePicker = true" |
| | | :customStyle="inputStyle(!form.departureTime)" |
| | | :disabled="!isEdit" |
| | | @click="isEdit && (showTimePicker = true)" |
| | | :customStyle="inputStyle(!transportData.transportStartTime)" |
| | | > |
| | | <template #suffix> |
| | | <template #suffix v-if="isEdit"> |
| | | <u-icon name="arrow-down" color="#86868b"></u-icon> |
| | | </template> |
| | | </u-input> |
| | | </view> |
| | | |
| | | <view class="form-item full-width"> |
| | | <text class="item-label">出发地点</text> |
| | | <u-textarea |
| | | v-model="form.departureLocation" |
| | | placeholder="请输入出发地点详细地址" |
| | | count |
| | | maxlength="200" |
| | | height="120" |
| | | |
| | | <view class="form-item"> |
| | | <text class="item-label">转运状态</text> |
| | | <u-select |
| | | v-model="statusSelectVisible" |
| | | :list="statusOptions" |
| | | :default-value="[statusIndex]" |
| | | :confirm-text="'确定'" |
| | | :cancel-text="'取消'" |
| | | @confirm="onStatusConfirm" |
| | | :disabled="!isEdit" |
| | | > |
| | | <template #default> |
| | | <view class="picker-trigger"> |
| | | <text>{{ |
| | | getTransportStatusText(transportData.transitStatus) |
| | | }}</text> |
| | | <u-icon |
| | | v-if="isEdit" |
| | | name="arrow-down" |
| | | size="16" |
| | | color="#999" |
| | | ></u-icon> |
| | | </view> |
| | | </template> |
| | | </u-select> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <text class="item-label required">负责协调员</text> |
| | | <u-input |
| | | v-model="transportData.contactPerson" |
| | | placeholder="请输入协调员姓名" |
| | | border="none" |
| | | :readonly="!isEdit" |
| | | :customStyle="inputStyle(!transportData.contactPerson)" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <text class="item-label">抵达医院</text> |
| | | |
| | | <view class="form-item" v-if="transportData.createTime"> |
| | | <text class="item-label">创建时间</text> |
| | | <u-input |
| | | v-model="form.destinationHospital" |
| | | placeholder="请输入抵达医院" |
| | | v-model="transportData.createTime" |
| | | placeholder="自动生成" |
| | | disabled |
| | | :disabledColor="disabledColor" |
| | | border="none" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item" v-if="transportData.createBy"> |
| | | <text class="item-label">创建人</text> |
| | | <u-input |
| | | v-model="transportData.createBy" |
| | | placeholder="自动获取" |
| | | disabled |
| | | :disabledColor="disabledColor" |
| | | border="none" |
| | | /> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 团队成员卡片 --> |
| | | <!-- 医护人员信息 --> |
| | | <view class="form-section"> |
| | | <view class="section-header"> |
| | | <view class="section-icon">👥</view> |
| | | <text class="section-title">团队成员</text> |
| | | <text class="section-title">医护人员信息</text> |
| | | </view> |
| | | |
| | | |
| | | <view class="form-grid"> |
| | | <view class="form-item"> |
| | | <text class="item-label">协调员</text> |
| | | <u-input |
| | | v-model="form.coordinator.name" |
| | | placeholder="选择协调员" |
| | | readonly |
| | | border="none" |
| | | @click="showCoordinatorPicker = true" |
| | | > |
| | | <template #suffix> |
| | | <u-icon name="arrow-down" color="#86868b"></u-icon> |
| | | </template> |
| | | </u-input> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <text class="item-label">急诊科医生</text> |
| | | <u-input |
| | | v-model="form.emergencyDoctor.name" |
| | | placeholder="选择急诊科医生" |
| | | readonly |
| | | v-model="transportData.doctor" |
| | | placeholder="请输入急诊科医生" |
| | | border="none" |
| | | @click="showDoctorPicker = true" |
| | | > |
| | | <template #suffix> |
| | | <u-icon name="arrow-down" color="#86868b"></u-icon> |
| | | </template> |
| | | </u-input> |
| | | :readonly="!isEdit" |
| | | /> |
| | | </view> |
| | | |
| | | |
| | | <view class="form-item"> |
| | | <text class="item-label">医生电话</text> |
| | | <u-input |
| | | v-model="transportData.doctorPhone" |
| | | placeholder="请输入医生手机号" |
| | | type="number" |
| | | border="none" |
| | | :readonly="!isEdit" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <text class="item-label">护士</text> |
| | | <u-input |
| | | v-model="form.nurse.name" |
| | | placeholder="选择护士" |
| | | readonly |
| | | v-model="transportData.nurse" |
| | | placeholder="请输入护士姓名" |
| | | border="none" |
| | | @click="showNursePicker = true" |
| | | > |
| | | <template #suffix> |
| | | <u-icon name="arrow-down" color="#86868b"></u-icon> |
| | | </template> |
| | | </u-input> |
| | | :readonly="!isEdit" |
| | | /> |
| | | </view> |
| | | |
| | | |
| | | <view class="form-item"> |
| | | <text class="item-label">司机</text> |
| | | <text class="item-label">护士电话</text> |
| | | <u-input |
| | | v-model="form.driver.name" |
| | | placeholder="选择司机" |
| | | readonly |
| | | v-model="transportData.nursePhone" |
| | | placeholder="请输入护士手机号" |
| | | type="number" |
| | | border="none" |
| | | @click="showDriverPicker = true" |
| | | > |
| | | <template #suffix> |
| | | <u-icon name="arrow-down" color="#86868b"></u-icon> |
| | | </template> |
| | | </u-input> |
| | | :readonly="!isEdit" |
| | | /> |
| | | </view> |
| | | |
| | | |
| | | <view class="form-item"> |
| | | <text class="item-label">驾驶员</text> |
| | | <u-input |
| | | v-model="transportData.driver" |
| | | placeholder="请输入驾驶员姓名" |
| | | border="none" |
| | | :readonly="!isEdit" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <text class="item-label">驾驶员电话</text> |
| | | <u-input |
| | | v-model="transportData.driverPhone" |
| | | placeholder="请输入驾驶员手机号" |
| | | type="number" |
| | | border="none" |
| | | :readonly="!isEdit" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <text class="item-label">ICU评估医生</text> |
| | | <u-input |
| | | v-model="form.icuDoctor.name" |
| | | placeholder="选择ICU评估医生" |
| | | readonly |
| | | v-model="transportData.icuDoctor" |
| | | placeholder="请输入ICU评估医生" |
| | | border="none" |
| | | @click="showIcuDoctorPicker = true" |
| | | > |
| | | <template #suffix> |
| | | <u-icon name="arrow-down" color="#86868b"></u-icon> |
| | | </template> |
| | | </u-input> |
| | | :readonly="!isEdit" |
| | | /> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 联系方式卡片 --> |
| | | <view class="form-section"> |
| | | <view class="section-header"> |
| | | <view class="section-icon">📞</view> |
| | | <text class="section-title">联系方式</text> |
| | | </view> |
| | | |
| | | <view class="form-grid"> |
| | | <view class="form-item" v-for="(contact, index) in form.contacts" :key="index"> |
| | | <text class="item-label">{{ contact.role }}</text> |
| | | <view class="form-item"> |
| | | <text class="item-label">ICU医生电话</text> |
| | | <u-input |
| | | v-model="contact.phone" |
| | | placeholder="请输入联系电话" |
| | | border="none" |
| | | v-model="transportData.icuDoctorPhone" |
| | | placeholder="请输入ICU医生手机号" |
| | | type="number" |
| | | border="none" |
| | | :readonly="!isEdit" |
| | | /> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 备注信息卡片 --> |
| | | <!-- 附件信息 --> |
| | | <view |
| | | class="form-section" |
| | | v-if=" |
| | | transportData.annexfilesList && |
| | | transportData.annexfilesList.length > 0 |
| | | " |
| | | > |
| | | <view class="section-header"> |
| | | <view class="section-icon">📎</view> |
| | | <text class="section-title" |
| | | >附件信息 ({{ transportData.annexfilesList.length }})</text |
| | | > |
| | | </view> |
| | | |
| | | <view class="attachment-list"> |
| | | <view |
| | | v-for="(file, index) in transportData.annexfilesList" |
| | | :key="index" |
| | | class="attachment-item" |
| | | @click="previewFile(file)" |
| | | > |
| | | <view class="file-info"> |
| | | <u-icon |
| | | name="file-text" |
| | | color="#409EFF" |
| | | size="20" |
| | | class="file-icon" |
| | | ></u-icon> |
| | | <view class="file-details"> |
| | | <text class="file-name">{{ file.fileName }}</text> |
| | | <text class="file-time">{{ |
| | | formatTime(file.createTime) |
| | | }}</text> |
| | | </view> |
| | | </view> |
| | | <u-icon name="arrow-right" color="#999" size="16"></u-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 备注信息 --> |
| | | <view class="form-section"> |
| | | <view class="section-header"> |
| | | <view class="section-icon">📝</view> |
| | | <text class="section-title">备注信息</text> |
| | | </view> |
| | | |
| | | |
| | | <view class="form-grid"> |
| | | <view class="form-item full-width"> |
| | | <u-textarea |
| | | v-model="form.remarks" |
| | | placeholder="请输入特殊要求或备注信息" |
| | | count |
| | | v-model="transportData.remark" |
| | | placeholder="请输入备注信息" |
| | | border="none" |
| | | :readonly="!isEdit" |
| | | :count="isEdit" |
| | | maxlength="500" |
| | | height="200" |
| | | height="150" |
| | | /> |
| | | </view> |
| | | </view> |
| | |
| | | |
| | | <!-- 操作按钮 --> |
| | | <view class="action-buttons"> |
| | | <u-button class="btn secondary" @click="handleCancel">取消</u-button> |
| | | <u-button class="btn primary" @click="handleSaveDraft">保存草稿</u-button> |
| | | <u-button class="btn success" @click="handleSubmit" :disabled="!isFormValid">提交申请</u-button> |
| | | <!-- 查看模式 --> |
| | | <template v-if="!isEdit"> |
| | | <u-button class="btn secondary" @click="goBack">返回</u-button> |
| | | <u-button v-if="canEdit" class="btn primary" @click="handleEdit"> |
| | | 编辑 |
| | | </u-button> |
| | | <u-button |
| | | v-if="canStartTransport" |
| | | class="btn warning" |
| | | @click="handleStartTransport" |
| | | > |
| | | 开始转运 |
| | | </u-button> |
| | | <u-button |
| | | v-if="canCompleteTransport" |
| | | class="btn success" |
| | | @click="handleCompleteTransport" |
| | | > |
| | | 完成转运 |
| | | </u-button> |
| | | <u-button v-if="canDelete" class="btn error" @click="handleDelete"> |
| | | 删除 |
| | | </u-button> |
| | | </template> |
| | | |
| | | <!-- 编辑模式 --> |
| | | <template v-else> |
| | | <u-button class="btn secondary" @click="cancelEdit">取消</u-button> |
| | | <u-button |
| | | class="btn success" |
| | | @click="handleSave" |
| | | :disabled="!isFormValid" |
| | | :loading="saving" |
| | | > |
| | | 保存 |
| | | </u-button> |
| | | </template> |
| | | </view> |
| | | </view> |
| | | </scroll-view> |
| | | |
| | | <!-- 选择器组件 --> |
| | | <u-picker |
| | | :show="showCasePicker" |
| | | :columns="[caseOptions]" |
| | | keyName="label" |
| | | @confirm="onCaseConfirm" |
| | | @cancel="showCasePicker = false" |
| | | title="选择案例" |
| | | ></u-picker> |
| | | |
| | | <!-- 时间选择器 --> |
| | | <u-datetime-picker |
| | | :show="showTimePicker" |
| | | v-model="departureTimeValue" |
| | |
| | | title="选择出发时间" |
| | | ></u-datetime-picker> |
| | | |
| | | <u-picker |
| | | :show="showCoordinatorPicker" |
| | | :columns="[coordinatorOptions]" |
| | | keyName="label" |
| | | @confirm="onCoordinatorConfirm" |
| | | @cancel="showCoordinatorPicker = false" |
| | | title="选择协调员" |
| | | ></u-picker> |
| | | |
| | | <u-picker |
| | | :show="showDoctorPicker" |
| | | :columns="[doctorOptions]" |
| | | keyName="label" |
| | | @confirm="onDoctorConfirm" |
| | | @cancel="showDoctorPicker = false" |
| | | title="选择急诊科医生" |
| | | ></u-picker> |
| | | |
| | | <u-picker |
| | | :show="showNursePicker" |
| | | :columns="[nurseOptions]" |
| | | keyName="label" |
| | | @confirm="onNurseConfirm" |
| | | @cancel="showNursePicker = false" |
| | | title="选择护士" |
| | | ></u-picker> |
| | | |
| | | <u-picker |
| | | :show="showDriverPicker" |
| | | :columns="[driverOptions]" |
| | | keyName="label" |
| | | @confirm="onDriverConfirm" |
| | | @cancel="showDriverPicker = false" |
| | | title="选择司机" |
| | | ></u-picker> |
| | | |
| | | <u-picker |
| | | :show="showIcuDoctorPicker" |
| | | :columns="[icuDoctorOptions]" |
| | | keyName="label" |
| | | @confirm="onIcuDoctorConfirm" |
| | | @cancel="showIcuDoctorPicker = false" |
| | | title="选择ICU评估医生" |
| | | ></u-picker> |
| | | |
| | | <!-- 加载状态 --> |
| | | <u-loading-icon :show="loading" text="提交中..."></u-loading-icon> |
| | | <u-loading-icon :show="loading" :text="loadingText"></u-loading-icon> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, computed, onMounted } from 'vue' |
| | | import { onLoad } from '@dcloudio/uni-app' |
| | | import { ref, computed, onMounted } from "vue"; |
| | | import { onLoad } from "@dcloudio/uni-app"; |
| | | |
| | | // 表单数据 |
| | | const form = reactive({ |
| | | caseInfo: { |
| | | caseId: '', |
| | | donorName: '', |
| | | gender: '', |
| | | age: '', |
| | | diagnosis: '' |
| | | }, |
| | | hospital: '', |
| | | department: '', |
| | | departureTime: '', |
| | | departureLocation: '', |
| | | destinationHospital: '', |
| | | coordinator: { id: '', name: '' }, |
| | | emergencyDoctor: { id: '', name: '' }, |
| | | nurse: { id: '', name: '' }, |
| | | driver: { id: '', name: '' }, |
| | | icuDoctor: { id: '', name: '' }, |
| | | contacts: [ |
| | | { role: '协调员电话', phone: '' }, |
| | | { role: '急诊医生电话', phone: '' }, |
| | | { role: '护士电话', phone: '' }, |
| | | { role: '司机电话', phone: '' }, |
| | | { role: 'ICU医生电话', phone: '' } |
| | | ], |
| | | remarks: '' |
| | | }) |
| | | // 字典数据 |
| | | const dict = ref({}); |
| | | |
| | | // 选择器状态 |
| | | const showCasePicker = ref(false) |
| | | const showTimePicker = ref(false) |
| | | const showCoordinatorPicker = ref(false) |
| | | const showDoctorPicker = ref(false) |
| | | const showNursePicker = ref(false) |
| | | const showDriverPicker = ref(false) |
| | | const showIcuDoctorPicker = ref(false) |
| | | const departureTimeValue = ref(0) |
| | | // 数据 |
| | | const transportData = ref({}); |
| | | const loading = ref(false); |
| | | const saving = ref(false); |
| | | const isEdit = ref(false); |
| | | const transportId = ref(null); |
| | | const showTimePicker = ref(false); |
| | | const departureTimeValue = ref(0); |
| | | const statusSelectVisible = ref(false); |
| | | |
| | | // 选项数据 |
| | | const caseOptions = ref([ |
| | | { |
| | | label: '张三 - 脑外伤导致脑死亡 - 青岛镜湖医院', |
| | | value: 'DON20241216001', |
| | | data: { |
| | | donorName: '张三', |
| | | gender: '男', |
| | | age: '38', |
| | | diagnosis: '脑外伤导致脑死亡', |
| | | hospital: '青岛镜湖医院' |
| | | } |
| | | }, |
| | | { |
| | | label: '李四 - 脑梗死 - 青岛大学附属医院', |
| | | value: 'DON20241216002', |
| | | data: { |
| | | donorName: '李四', |
| | | gender: '女', |
| | | age: '45', |
| | | diagnosis: '脑梗死', |
| | | hospital: '青岛大学附属医院' |
| | | } |
| | | } |
| | | ]) |
| | | // 字典选项 |
| | | const statusOptions = ref([ |
| | | { label: "待转运", value: 1 }, |
| | | { label: "转运中", value: 2 }, |
| | | { label: "转运完成", value: 3 }, |
| | | { label: "转运取消", value: 4 }, |
| | | { label: "暂存", value: 5 }, |
| | | ]); |
| | | |
| | | const coordinatorOptions = ref([ |
| | | { label: '张医生', value: '1' }, |
| | | { label: '李医生', value: '2' }, |
| | | { label: '王医生', value: '3' } |
| | | ]) |
| | | |
| | | const doctorOptions = ref([ |
| | | { label: '赵医生', value: '1' }, |
| | | { label: '钱医生', value: '2' }, |
| | | { label: '孙医生', value: '3' } |
| | | ]) |
| | | |
| | | const nurseOptions = ref([ |
| | | { label: '周护士', value: '1' }, |
| | | { label: '吴护士', value: '2' }, |
| | | { label: '郑护士', value: '3' } |
| | | ]) |
| | | |
| | | const driverOptions = ref([ |
| | | { label: '刘师傅', value: '1' }, |
| | | { label: '陈师傅', value: '2' }, |
| | | { label: '杨师傅', value: '3' } |
| | | ]) |
| | | |
| | | const icuDoctorOptions = ref([ |
| | | { label: '朱医生', value: '1' }, |
| | | { label: '秦医生', value: '2' }, |
| | | { label: '尤医生', value: '3' } |
| | | ]) |
| | | |
| | | // 状态管理 |
| | | const loading = ref(false) |
| | | const isEdit = ref(false) |
| | | const transportId = ref('') |
| | | const disabledColor = ref('#f5f5f7') |
| | | // 样式 |
| | | const disabledColor = ref("#f5f5f7"); |
| | | |
| | | // 计算属性 |
| | | const loadingText = computed(() => { |
| | | return loading.value ? "加载中..." : saving.value ? "保存中..." : ""; |
| | | }); |
| | | |
| | | const isFormValid = computed(() => { |
| | | return form.caseInfo.caseId && form.hospital && form.departureTime |
| | | }) |
| | | return ( |
| | | transportData.value.transportStartPlace && |
| | | transportData.value.transportStartTime && |
| | | transportData.value.contactPerson |
| | | ); |
| | | }); |
| | | |
| | | // 样式方法 |
| | | const inputStyle = (isError) => { |
| | | return isError ? |
| | | 'border: 2rpx solid #ff4757 !important; border-radius: 12rpx !important;' : |
| | | 'border: 2rpx solid #e5e5e7 !important; border-radius: 12rpx !important;' |
| | | } |
| | | // 权限判断 |
| | | const canEdit = computed(() => { |
| | | if (loading.value) return false; |
| | | return ( |
| | | transportData.value.transitStatus === 1 || // 待转运 |
| | | transportData.value.transitStatus === 5 |
| | | ); // 暂存 |
| | | }); |
| | | |
| | | // 方法定义 |
| | | const onCaseConfirm = (e) => { |
| | | if (e.value && e.value[0]) { |
| | | const selectedCase = e.value[0] |
| | | form.caseInfo.caseId = selectedCase.value |
| | | form.caseInfo.donorName = selectedCase.data.donorName |
| | | form.caseInfo.gender = selectedCase.data.gender |
| | | form.caseInfo.age = selectedCase.data.age |
| | | form.caseInfo.diagnosis = selectedCase.data.diagnosis |
| | | form.hospital = selectedCase.data.hospital |
| | | const canStartTransport = computed(() => { |
| | | if (loading.value) return false; |
| | | return transportData.value.transitStatus === 1; // 待转运 |
| | | }); |
| | | |
| | | const canCompleteTransport = computed(() => { |
| | | if (loading.value) return false; |
| | | return transportData.value.transitStatus === 2; // 转运中 |
| | | }); |
| | | |
| | | const canDelete = computed(() => { |
| | | if (loading.value) return false; |
| | | return true; // 根据实际权限控制 |
| | | }); |
| | | |
| | | // 计算索引 |
| | | const statusIndex = computed(() => { |
| | | if (!transportData.value.transitStatus) return 0; |
| | | return statusOptions.value.findIndex( |
| | | (item) => item.value === transportData.value.transitStatus, |
| | | ); |
| | | }); |
| | | |
| | | onLoad(async (options) => { |
| | | if (options.id) { |
| | | transportId.value = options.id; |
| | | await loadTransportData(options.id); |
| | | } else if (options.caseId) { |
| | | // 新增模式 |
| | | isEdit.value = true; |
| | | await initNewTransport(options.caseId, options.caseNo); |
| | | } |
| | | showCasePicker.value = false |
| | | } |
| | | }); |
| | | |
| | | const onTimeConfirm = (e) => { |
| | | const date = new Date(e.value) |
| | | form.departureTime = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}` |
| | | showTimePicker.value = false |
| | | } |
| | | |
| | | const onCoordinatorConfirm = (e) => { |
| | | if (e.value && e.value[0]) { |
| | | form.coordinator.name = e.value[0].label |
| | | form.coordinator.id = e.value[0].value |
| | | // 自动填充协调员电话 |
| | | const contact = form.contacts.find(item => item.role === '协调员电话') |
| | | if (contact) { |
| | | contact.phone = '13800138000' // 模拟数据 |
| | | } |
| | | } |
| | | showCoordinatorPicker.value = false |
| | | } |
| | | |
| | | const onDoctorConfirm = (e) => { |
| | | if (e.value && e.value[0]) { |
| | | form.emergencyDoctor.name = e.value[0].label |
| | | form.emergencyDoctor.id = e.value[0].value |
| | | // 自动填充急诊医生电话 |
| | | const contact = form.contacts.find(item => item.role === '急诊医生电话') |
| | | if (contact) { |
| | | contact.phone = '13800138001' // 模拟数据 |
| | | } |
| | | } |
| | | showDoctorPicker.value = false |
| | | } |
| | | |
| | | const onNurseConfirm = (e) => { |
| | | if (e.value && e.value[0]) { |
| | | form.nurse.name = e.value[0].label |
| | | form.nurse.id = e.value[0].value |
| | | // 自动填充护士电话 |
| | | const contact = form.contacts.find(item => item.role === '护士电话') |
| | | if (contact) { |
| | | contact.phone = '13800138002' // 模拟数据 |
| | | } |
| | | } |
| | | showNursePicker.value = false |
| | | } |
| | | |
| | | const onDriverConfirm = (e) => { |
| | | if (e.value && e.value[0]) { |
| | | form.driver.name = e.value[0].label |
| | | form.driver.id = e.value[0].value |
| | | // 自动填充司机电话 |
| | | const contact = form.contacts.find(item => item.role === '司机电话') |
| | | if (contact) { |
| | | contact.phone = '13800138003' // 模拟数据 |
| | | } |
| | | } |
| | | showDriverPicker.value = false |
| | | } |
| | | |
| | | const onIcuDoctorConfirm = (e) => { |
| | | if (e.value && e.value[0]) { |
| | | form.icuDoctor.name = e.value[0].label |
| | | form.icuDoctor.id = e.value[0].value |
| | | // 自动填充ICU医生电话 |
| | | const contact = form.contacts.find(item => item.role === 'ICU医生电话') |
| | | if (contact) { |
| | | contact.phone = '13800138004' // 模拟数据 |
| | | } |
| | | } |
| | | showIcuDoctorPicker.value = false |
| | | } |
| | | |
| | | const handleCancel = () => { |
| | | uni.navigateBack() |
| | | } |
| | | |
| | | const validateForm = () => { |
| | | if (!form.caseInfo.caseId) { |
| | | uni.showToast({ title: '请选择案例', icon: 'none' }) |
| | | return false |
| | | } |
| | | if (!form.hospital) { |
| | | uni.showToast({ title: '请输入捐献医院', icon: 'none' }) |
| | | return false |
| | | } |
| | | if (!form.departureTime) { |
| | | uni.showToast({ title: '请选择出发时间', icon: 'none' }) |
| | | return false |
| | | } |
| | | return true |
| | | } |
| | | |
| | | const handleSaveDraft = async () => { |
| | | if (!validateForm()) return |
| | | |
| | | loading.value = true |
| | | // 加载转运单数据 |
| | | const loadTransportData = async (id) => { |
| | | loading.value = true; |
| | | try { |
| | | await new Promise(resolve => setTimeout(resolve, 1000)) |
| | | await saveTransport('draft') |
| | | uni.showToast({ title: '保存草稿成功', icon: 'success' }) |
| | | } catch (error) { |
| | | console.error('保存草稿失败:', error) |
| | | uni.showToast({ title: '保存失败,请重试', icon: 'none' }) |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | } |
| | | const res = await uni.$uapi.post(`/project/transport/list`, { id: id }); |
| | | |
| | | const handleSubmit = async () => { |
| | | if (!validateForm()) return |
| | | |
| | | if (res) { |
| | | transportData.value = res[0]; |
| | | } else { |
| | | throw new Error(res.msg || "数据加载失败"); |
| | | } |
| | | } catch (error) { |
| | | console.error("加载转运单失败:", error); |
| | | uni.showToast({ |
| | | title: "数据加载失败,请重试", |
| | | icon: "none", |
| | | }); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | |
| | | // 初始化新的转运单 |
| | | const initNewTransport = async (caseId, caseNo) => { |
| | | try { |
| | | // 如果有案例ID,加载案例信息 |
| | | if (caseId) { |
| | | const res = await uni.$uapi.post( |
| | | `/project/transport/list`, |
| | | { id: caseId }, |
| | | ); |
| | | if (res) { |
| | | const caseData = res[0]; |
| | | transportData.value = { |
| | | ...transportData.value, |
| | | caseNo: caseNo || caseData.caseNo, |
| | | patName: caseData.patName, |
| | | sex: caseData.sex, |
| | | age: caseData.age, |
| | | diagnosisname: caseData.diagnosisname, |
| | | treatmentHospitalName: caseData.treatmenthospitalname, |
| | | transitStatus: 1, // 待转运 |
| | | createTime: new Date() |
| | | .toISOString() |
| | | .replace("T", " ") |
| | | .substring(0, 19), |
| | | }; |
| | | } |
| | | } else { |
| | | transportData.value = { |
| | | transitStatus: 1, |
| | | createTime: new Date().toISOString().replace("T", " ").substring(0, 19), |
| | | }; |
| | | } |
| | | } catch (error) { |
| | | console.error("初始化转运单失败:", error); |
| | | } |
| | | }; |
| | | |
| | | // 获取转运状态文本 |
| | | const getTransportStatusText = (status) => { |
| | | const map = { |
| | | 1: "待转运", |
| | | 2: "转运中", |
| | | 3: "转运完成", |
| | | 4: "转运取消", |
| | | 5: "暂存", |
| | | }; |
| | | return map[status] || "未知"; |
| | | }; |
| | | |
| | | // 获取转运状态样式 |
| | | const getTransportStatusClass = (status) => { |
| | | const map = { |
| | | 1: "pending", |
| | | 2: "transporting", |
| | | 3: "completed", |
| | | 4: "cancelled", |
| | | 5: "draft", |
| | | }; |
| | | return map[status] || "draft"; |
| | | }; |
| | | |
| | | // 获取性别文本 |
| | | const getGenderText = (gender) => { |
| | | if (!gender) return "未知"; |
| | | return gender === "1" ? "男" : "女"; |
| | | }; |
| | | |
| | | // 格式化时间 |
| | | const formatTime = (timeStr) => { |
| | | if (!timeStr) return ""; |
| | | return timeStr.replace("T", " ").substring(0, 16); |
| | | }; |
| | | |
| | | // 输入框样式 |
| | | const inputStyle = (isError) => { |
| | | return isError |
| | | ? "border: 2rpx solid #f56c6c !important; border-radius: 12rpx !important;" |
| | | : "border: 2rpx solid #e5e5e7 !important; border-radius: 12rpx !important;"; |
| | | }; |
| | | |
| | | // 时间确认 |
| | | const onTimeConfirm = (e) => { |
| | | const date = new Date(e.value); |
| | | transportData.value.transportStartTime = `${date.getFullYear()}-${( |
| | | date.getMonth() + 1 |
| | | ) |
| | | .toString() |
| | | .padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")} ${date |
| | | .getHours() |
| | | .toString() |
| | | .padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}`; |
| | | showTimePicker.value = false; |
| | | }; |
| | | |
| | | // 状态确认 |
| | | const onStatusConfirm = (e) => { |
| | | if (e[0]) { |
| | | transportData.value.transitStatus = e[0].value; |
| | | } |
| | | statusSelectVisible.value = false; |
| | | }; |
| | | |
| | | // 预览文件 |
| | | const previewFile = (file) => { |
| | | const fullUrl = file.path || file.fileUrl; |
| | | if (!fullUrl) { |
| | | uni.showToast({ title: "文件路径不存在", icon: "none" }); |
| | | return; |
| | | } |
| | | |
| | | if (file.fileName && file.fileName.match(/\.(jpg|jpeg|png|gif|bmp|webp)$/i)) { |
| | | uni.previewImage({ |
| | | urls: [fullUrl], |
| | | current: 0, |
| | | }); |
| | | } else if (file.fileName && file.fileName.match(/\.pdf$/i)) { |
| | | uni.downloadFile({ |
| | | url: fullUrl, |
| | | success: (res) => { |
| | | uni.openDocument({ |
| | | filePath: res.tempFilePath, |
| | | fileType: "pdf", |
| | | showMenu: true, |
| | | }); |
| | | }, |
| | | fail: (err) => { |
| | | console.error("打开文档失败:", err); |
| | | uni.showToast({ title: "打开文件失败", icon: "none" }); |
| | | }, |
| | | }); |
| | | } else { |
| | | uni.showToast({ title: "暂不支持此文件类型预览", icon: "none" }); |
| | | } |
| | | }; |
| | | |
| | | // 返回 |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | // 编辑 |
| | | const handleEdit = () => { |
| | | isEdit.value = true; |
| | | }; |
| | | |
| | | // 取消编辑 |
| | | const cancelEdit = () => { |
| | | if (transportId.value) { |
| | | // 重新加载数据 |
| | | isEdit.value = false; |
| | | loadTransportData(transportId.value); |
| | | } else { |
| | | // 新增模式,直接返回 |
| | | uni.navigateBack(); |
| | | } |
| | | }; |
| | | |
| | | // 保存 |
| | | const handleSave = async () => { |
| | | if (!validateForm()) return; |
| | | |
| | | saving.value = true; |
| | | |
| | | try { |
| | | const submitData = { |
| | | ...transportData.value, |
| | | }; |
| | | |
| | | let res; |
| | | if (transportId.value) { |
| | | // 修改 |
| | | res = await uni.$uapi.post("/project/transport/edit", submitData); |
| | | } else { |
| | | // 新增 |
| | | submitData.createBy = "移动端用户"; |
| | | res = await uni.$uapi.post("/project/transport/add", submitData); |
| | | } |
| | | |
| | | if (res.code === 200) { |
| | | uni.showToast({ |
| | | title: transportId.value ? "修改成功" : "新增成功", |
| | | icon: "success", |
| | | }); |
| | | |
| | | if (transportId.value) { |
| | | // 重新加载数据 |
| | | isEdit.value = false; |
| | | await loadTransportData(transportId.value); |
| | | } else { |
| | | // 新增成功后返回列表 |
| | | setTimeout(() => { |
| | | uni.navigateBack(); |
| | | }, 1500); |
| | | } |
| | | } else { |
| | | throw new Error(res.msg || "操作失败"); |
| | | } |
| | | } catch (error) { |
| | | console.error("保存失败:", error); |
| | | uni.showToast({ |
| | | title: error.message || (transportId.value ? "修改失败" : "新增失败"), |
| | | icon: "none", |
| | | }); |
| | | } finally { |
| | | saving.value = false; |
| | | } |
| | | }; |
| | | |
| | | // 表单验证 |
| | | const validateForm = () => { |
| | | if (!transportData.value.transportStartPlace) { |
| | | uni.showToast({ title: "请输入出发地点", icon: "none" }); |
| | | return false; |
| | | } |
| | | |
| | | if (!transportData.value.transportStartTime) { |
| | | uni.showToast({ title: "请选择出发时间", icon: "none" }); |
| | | return false; |
| | | } |
| | | |
| | | if (!transportData.value.contactPerson) { |
| | | uni.showToast({ title: "请输入负责协调员", icon: "none" }); |
| | | return false; |
| | | } |
| | | |
| | | return true; |
| | | }; |
| | | |
| | | // 开始转运 |
| | | const handleStartTransport = () => { |
| | | uni.showModal({ |
| | | title: '确认提交', |
| | | content: '确定要提交转运单申请吗?', |
| | | title: "开始转运", |
| | | content: "确定要开始转运吗?", |
| | | success: async (res) => { |
| | | if (res.confirm) { |
| | | loading.value = true |
| | | await updateTransportStatus(2, "开始转运"); |
| | | } |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | // 完成转运 |
| | | const handleCompleteTransport = () => { |
| | | uni.showModal({ |
| | | title: "完成转运", |
| | | content: "确定要完成转运吗?", |
| | | success: async (res) => { |
| | | if (res.confirm) { |
| | | await updateTransportStatus(3, "完成转运"); |
| | | } |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | // 更新转运状态 |
| | | const updateTransportStatus = async (newStatus, actionName) => { |
| | | try { |
| | | const updateData = { |
| | | id: transportId.value, |
| | | transitStatus: newStatus, |
| | | }; |
| | | |
| | | const res = await uni.$uapi.post("/system/transport/edit", updateData); |
| | | |
| | | if (res.code === 200) { |
| | | uni.showToast({ title: `${actionName}成功`, icon: "success" }); |
| | | await loadTransportData(transportId.value); |
| | | } else { |
| | | throw new Error(res.msg || `${actionName}失败`); |
| | | } |
| | | } catch (error) { |
| | | console.error(`${actionName}失败:`, error); |
| | | uni.showToast({ title: `${actionName}失败`, icon: "none" }); |
| | | } |
| | | }; |
| | | |
| | | // 删除转运单 |
| | | const handleDelete = () => { |
| | | uni.showModal({ |
| | | title: "确认删除", |
| | | content: `确定要删除转运单 ${transportData.value.reportId} 吗?`, |
| | | success: async (res) => { |
| | | if (res.confirm) { |
| | | try { |
| | | await new Promise(resolve => setTimeout(resolve, 1500)) |
| | | await saveTransport('pending') |
| | | uni.showToast({ title: '提交成功', icon: 'success' }) |
| | | setTimeout(() => { |
| | | uni.navigateBack() |
| | | }, 1500) |
| | | const result = await uni.$uapi.delete( |
| | | `/system/transport/${transportId.value}`, |
| | | ); |
| | | if (result.code === 200) { |
| | | uni.showToast({ title: "删除成功", icon: "success" }); |
| | | setTimeout(() => { |
| | | uni.navigateBack(); |
| | | }, 1500); |
| | | } else { |
| | | uni.showToast({ title: result.msg || "删除失败", icon: "none" }); |
| | | } |
| | | } catch (error) { |
| | | console.error('提交失败:', error) |
| | | uni.showToast({ title: '提交失败,请重试', icon: 'none' }) |
| | | } finally { |
| | | loading.value = false |
| | | console.error("删除失败:", error); |
| | | uni.showToast({ title: "删除失败", icon: "none" }); |
| | | } |
| | | } |
| | | } |
| | | }) |
| | | } |
| | | |
| | | const saveTransport = async (status) => { |
| | | const submitData = { |
| | | ...form, |
| | | status: status, |
| | | id: isEdit.value ? transportId.value : generateTransportId(), |
| | | createTime: new Date().toISOString() |
| | | } |
| | | |
| | | console.log('保存转运单:', submitData) |
| | | // 实际项目中调用API接口 |
| | | } |
| | | |
| | | const generateTransportId = () => { |
| | | const date = new Date() |
| | | return `T${date.getFullYear()}${(date.getMonth() + 1).toString().padStart(2, '0')}${date.getDate().toString().padStart(2, '0')}${Math.random().toString().slice(-3)}` |
| | | } |
| | | |
| | | const loadTransportData = (id) => { |
| | | // 模拟加载编辑数据 |
| | | const mockData = { |
| | | caseInfo: { |
| | | caseId: 'DON20241216001', |
| | | donorName: '张三', |
| | | gender: '男', |
| | | age: '38', |
| | | diagnosis: '脑外伤导致脑死亡' |
| | | }, |
| | | hospital: '青岛镜湖医院', |
| | | department: '神经外科', |
| | | departureTime: '2024-12-17 14:30:00', |
| | | departureLocation: '青岛市立医院急诊科', |
| | | destinationHospital: '青岛镜湖医院', |
| | | coordinator: { id: '1', name: '张医生' }, |
| | | emergencyDoctor: { id: '2', name: '王医生' }, |
| | | nurse: { id: '3', name: '李护士' }, |
| | | driver: { id: '4', name: '刘师傅' }, |
| | | icuDoctor: { id: '5', name: '赵医生' }, |
| | | contacts: [ |
| | | { role: '协调员电话', phone: '13800138000' }, |
| | | { role: '急诊医生电话', phone: '13800138001' }, |
| | | { role: '护士电话', phone: '13800138002' }, |
| | | { role: '司机电话', phone: '13800138003' }, |
| | | { role: 'ICU医生电话', phone: '13800138004' } |
| | | ], |
| | | remarks: '需要准备呼吸机等急救设备' |
| | | } |
| | | |
| | | Object.assign(form, mockData) |
| | | } |
| | | |
| | | // 生命周期 |
| | | onLoad((options) => { |
| | | if (options.id) { |
| | | isEdit.value = true |
| | | transportId.value = options.id |
| | | loadTransportData(options.id) |
| | | } |
| | | }) |
| | | }); |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .transport-edit-container { |
| | | min-height: 100vh; |
| | | background: linear-gradient(135deg, #f8fdff 0%, #e8f7f6 100%); |
| | | padding-bottom: 120rpx; /* 为操作栏留出空间 */ |
| | | } |
| | | |
| | | .form-scroll { |
| | |
| | | padding: 30rpx; |
| | | margin-bottom: 30rpx; |
| | | box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06); |
| | | |
| | | .section-header { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 30rpx; |
| | | padding-bottom: 20rpx; |
| | | border-bottom: 2rpx solid #f0f0f0; |
| | | } |
| | | |
| | | .section-icon { |
| | | font-size: 32rpx; |
| | | margin-right: 16rpx; |
| | | } |
| | | |
| | | .section-title { |
| | | font-size: 32rpx; |
| | | font-weight: 600; |
| | | color: #1d1d1f; |
| | | flex: 1; |
| | | } |
| | | |
| | | .status-tag { |
| | | padding: 6rpx 16rpx; |
| | | border-radius: 8rpx; |
| | | font-size: 24rpx; |
| | | font-weight: 500; |
| | | |
| | | &.pending { |
| | | background: rgba(240, 173, 78, 0.1); |
| | | color: #f0ad4e; |
| | | } |
| | | |
| | | &.transporting { |
| | | background: rgba(0, 122, 255, 0.1); |
| | | color: #007aff; |
| | | } |
| | | |
| | | &.completed { |
| | | background: rgba(76, 217, 100, 0.1); |
| | | color: #4cd964; |
| | | } |
| | | |
| | | &.cancelled { |
| | | background: rgba(220, 223, 230, 0.1); |
| | | color: #dcdfe6; |
| | | } |
| | | |
| | | &.draft { |
| | | background: rgba(144, 147, 153, 0.1); |
| | | color: #909399; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .section-header { |
| | | display: flex; |
| | | // align-items: center; |
| | | margin-bottom: 30rpx; |
| | | padding-bottom: 20rpx; |
| | | border-bottom: 2rpx solid #f0f0f0; |
| | | } |
| | | .case-info { |
| | | .info-row { |
| | | display: flex; |
| | | margin-bottom: 16rpx; |
| | | |
| | | .section-icon { |
| | | font-size: 32rpx; |
| | | margin-right: 16rpx; |
| | | } |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .section-title { |
| | | font-size: 32rpx; |
| | | font-weight: 600; |
| | | color: #1d1d1f; |
| | | .info-label { |
| | | font-size: 28rpx; |
| | | color: #606266; |
| | | min-width: 140rpx; |
| | | margin-right: 10rpx; |
| | | } |
| | | |
| | | .info-value { |
| | | font-size: 28rpx; |
| | | color: #303133; |
| | | flex: 1; |
| | | font-weight: 500; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .form-grid { |
| | |
| | | .form-item { |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | |
| | | &.full-width { |
| | | grid-column: 1 / -1; |
| | | } |
| | | } |
| | | |
| | | .item-label { |
| | | font-size: 28rpx; |
| | | color: #1d1d1f; |
| | | font-weight: 500; |
| | | margin-bottom: 12rpx; |
| | | |
| | | &.required::after { |
| | | content: '*'; |
| | | color: #ff4757; |
| | | margin-left: 4rpx; |
| | | .item-label { |
| | | font-size: 28rpx; |
| | | color: #1d1d1f; |
| | | font-weight: 500; |
| | | margin-bottom: 12rpx; |
| | | |
| | | &.required::after { |
| | | content: "*"; |
| | | color: #f56c6c; |
| | | margin-left: 4rpx; |
| | | } |
| | | } |
| | | |
| | | .picker-trigger { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | height: 88rpx; |
| | | padding: 0 20rpx; |
| | | background: #f5f5f5; |
| | | border-radius: 8rpx; |
| | | border: 1rpx solid #dcdfe6; |
| | | |
| | | text { |
| | | font-size: 28rpx; |
| | | color: #303133; |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | border-radius: 12rpx !important; |
| | | padding: 20rpx 24rpx !important; |
| | | background: #fff !important; |
| | | min-height: 150rpx; |
| | | } |
| | | |
| | | // 附件列表 |
| | | .attachment-list { |
| | | .attachment-item { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 20rpx 0; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | &:last-child { |
| | | border-bottom: none; |
| | | } |
| | | |
| | | &:active { |
| | | background: #f5f5f5; |
| | | } |
| | | |
| | | .file-info { |
| | | display: flex; |
| | | align-items: center; |
| | | flex: 1; |
| | | |
| | | .file-icon { |
| | | margin-right: 16rpx; |
| | | } |
| | | |
| | | .file-details { |
| | | display: flex; |
| | | flex-direction: column; |
| | | flex: 1; |
| | | |
| | | .file-name { |
| | | font-size: 28rpx; |
| | | color: #303133; |
| | | margin-bottom: 4rpx; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | max-width: 500rpx; |
| | | } |
| | | |
| | | .file-time { |
| | | font-size: 24rpx; |
| | | color: #909399; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .action-buttons { |
| | | display: flex; |
| | | gap: 20rpx; |
| | | margin-top: 40rpx; |
| | | background: #fff; |
| | | padding: 20rpx 0; |
| | | position: fixed; |
| | | bottom: 0; |
| | | left: 0; |
| | | right: 0; |
| | | padding: 20rpx 30rpx; |
| | | padding-bottom: calc(20rpx + env(safe-area-inset-bottom)); |
| | | box-shadow: 0 -2rpx 20rpx rgba(0, 0, 0, 0.08); |
| | | z-index: 100; |
| | | } |
| | | |
| | | .btn { |
| | | flex: 1; |
| | | height: 80rpx; |
| | | border-radius: 16rpx; |
| | | font-size: 32rpx; |
| | | font-weight: 500; |
| | | |
| | | border-radius: 20rpx; |
| | | font-size: 28rpx; |
| | | font-weight: 600; |
| | | border: none; |
| | | transition: all 0.3s ease; |
| | | |
| | | &.secondary { |
| | | background: #f5f5f7 !important; |
| | | color: #1d1d1f !important; |
| | | background: #f5f5f7; |
| | | color: #1d1d1f; |
| | | |
| | | &:active { |
| | | background: #e5e5e7; |
| | | } |
| | | } |
| | | |
| | | |
| | | &.primary { |
| | | background: #2979ff !important; |
| | | color: #fff !important; |
| | | background: linear-gradient(90deg, #0071e3 0%, #2997ff 100%); |
| | | color: #fff; |
| | | |
| | | &:active { |
| | | transform: scale(0.98); |
| | | } |
| | | } |
| | | |
| | | |
| | | &.warning { |
| | | background: linear-gradient(90deg, #f0ad4e 0%, #f8b62d 100%); |
| | | color: #fff; |
| | | |
| | | &:active { |
| | | transform: scale(0.98); |
| | | } |
| | | } |
| | | |
| | | &.success { |
| | | background: linear-gradient(135deg, #0f95b0, #89C4C1) !important; |
| | | color: #fff !important; |
| | | |
| | | background: linear-gradient(90deg, #34c759 0%, #4cd964 100%); |
| | | color: #fff; |
| | | |
| | | &:disabled { |
| | | background: #c0c0c0 !important; |
| | | background: #c0c4cc; |
| | | opacity: 0.6; |
| | | } |
| | | |
| | | &:active:not(:disabled) { |
| | | transform: scale(0.98); |
| | | } |
| | | } |
| | | |
| | | &.error { |
| | | background: linear-gradient(90deg, #ff3b30 0%, #ff5a5a 100%); |
| | | color: #fff; |
| | | |
| | | &:active { |
| | | transform: scale(0.98); |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | | </style> |