| | |
| | | <view class="smart-parse-btn" @click="showSmartParsePopup"> |
| | | <uni-icons type="compose" size="20" color="#007AFF"></uni-icons> |
| | | <text>智能识别</text> |
| | | </view> |
| | | <view class="multi-photo-ocr-btn" @click="showMultiPhotoOCRPopup"> |
| | | <uni-icons type="images" size="20" color="#FF6B00"></uni-icons> |
| | | <text>拍照识别</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 多图片拍照识别弹窗 --> |
| | | <uni-popup ref="multiPhotoOCRPopup" type="bottom" :safe-area="true"> |
| | | <view class="photo-ocr-popup"> |
| | | <view class="popup-header"> |
| | | <view class="popup-title"> |
| | | <uni-icons type="images" size="22" color="#FF6B00"></uni-icons> |
| | | <text>拍照识别 - 知情同意书</text> |
| | | </view> |
| | | <view class="popup-close" @click="closeMultiPhotoOCRPopup"> |
| | | <uni-icons type="closeempty" size="24" color="#333"></uni-icons> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="ocr-content"> |
| | | <view class="ocr-tip"> |
| | | <uni-icons type="info" size="18" color="#FF6B00"></uni-icons> |
| | | <text>请分别上传知情同意书的第一页和第二页,系统将自动识别并填充到表单中</text> |
| | | </view> |
| | | |
| | | <!-- 知情同意书第一页 --> |
| | | <view class="page-upload-section first-page"> |
| | | <view class="page-header"> |
| | | <view class="page-title"> |
| | | <view class="page-badge"> |
| | | <uni-icons type="compose" size="18" color="#52c41a"></uni-icons> |
| | | <text class="page-number">1</text> |
| | | </view> |
| | | <view class="page-info"> |
| | | <text class="page-main-title">知情同意书第一页</text> |
| | | <text class="page-sub-title">患者基本信息页</text> |
| | | </view> |
| | | </view> |
| | | <!-- 只有未上传时显示+号 --> |
| | | <view class="upload-btn green" @click="selectPage1Images" v-if="!page1Image"> |
| | | <uni-icons type="plusempty" size="30" color="#52c41a"></uni-icons> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 识别字段提示 --> |
| | | <view class="field-hint" v-if="!page1Image"> |
| | | <text>识别字段:患者姓名、性别、年龄、身份证号、诊断、转运费用、行程、开始时间、结束时间、家属签名</text> |
| | | </view> |
| | | |
| | | <!-- 单图预览 --> |
| | | <view class="single-image-container" v-if="page1Image"> |
| | | <image :src="page1Image" mode="aspectFit" class="preview-image"></image> |
| | | <view class="delete-btn" @click="deletePage1Image"> |
| | | <uni-icons type="closeempty" size="20" color="#fff"></uni-icons> |
| | | </view> |
| | | <view class="image-status"> |
| | | <uni-icons type="checkmarkempty" size="16" color="#fff"></uni-icons> |
| | | <text>已上传</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 第一页识别结果 --> |
| | | <view class="recognition-result" v-if="Object.keys(page1Fields).length > 0"> |
| | | <view class="result-title"> |
| | | <uni-icons type="checkmarkempty" size="18" color="#52c41a"></uni-icons> |
| | | <text>识别结果</text> |
| | | <text class="result-count">(共{{ Object.keys(page1Fields).length }}个字段)</text> |
| | | </view> |
| | | <view class="field-list"> |
| | | <view class="field-item" v-for="(value, key) in page1Fields" :key="key"> |
| | | <text class="field-name">{{ key }}</text> |
| | | <text class="field-value">{{ value || '未识别' }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 知情同意书第二页 --> |
| | | <view class="page-upload-section second-page"> |
| | | <view class="page-header"> |
| | | <view class="page-title"> |
| | | <view class="page-badge"> |
| | | <uni-icons type="compose" size="18" color="#FF6B00"></uni-icons> |
| | | <text class="page-number">2</text> |
| | | </view> |
| | | <view class="page-info"> |
| | | <text class="page-main-title">知情同意书第二页</text> |
| | | <text class="page-sub-title">签名与联系信息页</text> |
| | | </view> |
| | | </view> |
| | | <!-- 只有未上传时显示+号 --> |
| | | <view class="upload-btn orange" @click="selectPage2Images" v-if="!page2Image"> |
| | | <uni-icons type="plusempty" size="30" color="#FF6B00"></uni-icons> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 识别字段提示 --> |
| | | <view class="field-hint" v-if="!page2Image"> |
| | | <text>识别字段:患者签名、签字人身份证号、签字日期、联系电话、签字人关系</text> |
| | | </view> |
| | | |
| | | <!-- 单图预览 --> |
| | | <view class="single-image-container" v-if="page2Image"> |
| | | <image :src="page2Image" mode="aspectFit" class="preview-image"></image> |
| | | <view class="delete-btn" @click="deletePage2Image"> |
| | | <uni-icons type="closeempty" size="20" color="#fff"></uni-icons> |
| | | </view> |
| | | <view class="image-status"> |
| | | <uni-icons type="checkmarkempty" size="16" color="#fff"></uni-icons> |
| | | <text>已上传</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 第二页识别结果 --> |
| | | <view class="recognition-result" v-if="Object.keys(page2Fields).length > 0"> |
| | | <view class="result-title"> |
| | | <uni-icons type="checkmarkempty" size="18" color="#FF6B00"></uni-icons> |
| | | <text>识别结果</text> |
| | | <text class="result-count">(共{{ Object.keys(page2Fields).length }}个字段)</text> |
| | | </view> |
| | | <view class="field-list"> |
| | | <view class="field-item" v-for="(value, key) in page2Fields" :key="key"> |
| | | <text class="field-name">{{ key }}</text> |
| | | <text class="field-value">{{ value || '未识别' }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="popup-footer"> |
| | | <button class="cancel-btn" @click="closeMultiPhotoOCRPopup">取消</button> |
| | | <button |
| | | class="confirm-btn" |
| | | @click="applyOcrResult" |
| | | :disabled="Object.keys(page1Fields).length === 0 && Object.keys(page2Fields).length === 0" |
| | | > |
| | | 应用到表单 |
| | | </button> |
| | | </view> |
| | | </view> |
| | | </uni-popup> |
| | | |
| | | <view class="form-section"> |
| | | <view class="form-item"> |
| | |
| | | import uniPopup from '@/uni_modules/uni-popup/components/uni-popup/uni-popup.vue' |
| | | import { addTask, checkTaskDuplicate } from "@/api/task" |
| | | import { listAvailableVehicles, getUserBoundVehicle } from "@/api/vehicle" |
| | | import { searchHospitals, searchHospitalsByDeptRegion } from "@/api/hospital" |
| | | import { searchHospitals, searchHospitalsByDeptRegion, searchHospitalsByKeywords } from "@/api/hospital" |
| | | import DepartureSelector from './components/DepartureSelector.vue' |
| | | import { calculateTianDiTuDistance } from "@/api/map" |
| | | import { listBranchUsers } from "@/api/system/user" |
| | | import { searchIcd10 } from "@/api/icd10" |
| | | import { calculateTransferPrice } from "@/api/price" |
| | | import { checkVehicleActiveTasks } from "@/api/task" |
| | | import { recognizeImage, batchRecognizeImages, DEFAULT_TRANSFER_ITEM_NAMES } from "@/api/ocr" |
| | | import config from '@/config' |
| | | import { getToken } from '@/utils/auth' |
| | | |
| | | import { getDicts } from "@/api/dict" |
| | | import { getServiceOrdAreaTypes, getServiceOrderTypes } from "@/api/dictionary" |
| | |
| | | loading: false, |
| | | // 智能识别相关 |
| | | rawText: '', |
| | | parseLoading: false |
| | | parseLoading: false, |
| | | // 多图片拍照识别相关 |
| | | multiOcrImages: [], |
| | | multiOcrLoading: false, |
| | | // 分页OCR识别相关 |
| | | currentOcrPage: 1, // 当前上传的页码:1=第一页,2=第二页 |
| | | page1Image: '', // 第一页图片(单图) |
| | | page2Image: '', // 第二页图片(单图) |
| | | page1Fields: {}, // 第一页识别结果 |
| | | page2Fields: {}, // 第二页识别结果 |
| | | // 附件临时存储(OCR图片) |
| | | pendingAttachments: [] // 待上传的附件列表 [{ filePath: '', category: '1' }] |
| | | } |
| | | }, |
| | | computed: { |
| | |
| | | if (!this.validateForm()) { |
| | | return |
| | | } |
| | | |
| | | // 获取当前日期(格式YYYY-MM-DD) |
| | | this.doSubmitTask(); |
| | | |
| | | }, |
| | | checkTaskDp(){ |
| | | // 获取当前日期(格式YYYY-MM-DD) |
| | | const today = new Date() |
| | | const createDate = today.getFullYear() + '-' + |
| | | String(today.getMonth() + 1).padStart(2, '0') + '-' + |
| | |
| | | this.$modal.showToast('检查失败,请重试') |
| | | }) |
| | | }, |
| | | |
| | | // 执行实际的提交操作 |
| | | doSubmitTask() { |
| | | this.$modal.confirm('确定要保存任务吗?').then(() => { |
| | |
| | | |
| | | addTask(submitData).then(response => { |
| | | this.loading = false |
| | | this.$modal.showToast('任务创建成功') |
| | | |
| | | // 延迟跳转,让用户看到成功提示 |
| | | setTimeout(() => { |
| | | // 跳转到任务列表并触发刷新 |
| | | uni.switchTab({ |
| | | url: '/pages/task/index', |
| | | success: () => { |
| | | // 使用事件总线通知任务列表页面刷新 |
| | | uni.$emit('refreshTaskList') |
| | | } |
| | | // 获取创建的任务ID |
| | | const taskId = response.taskId || (response.data && response.data.taskId) || null |
| | | console.log('任务创建成功,taskId:', taskId) |
| | | |
| | | // 如果有待上传的附件(OCR图片),先上传附件 |
| | | if (taskId && this.pendingAttachments.length > 0) { |
| | | this.uploadPendingAttachments(taskId).then(() => { |
| | | this.$modal.showToast('任务创建成功,附件已上传') |
| | | this.navigateToTaskList() |
| | | }).catch(error => { |
| | | console.error('附件上传失败:', error) |
| | | this.$modal.showToast('任务创建成功,但附件上传失败') |
| | | this.navigateToTaskList() |
| | | }) |
| | | }, 1000) |
| | | } else { |
| | | this.$modal.showToast('任务创建成功') |
| | | this.navigateToTaskList() |
| | | } |
| | | }).catch(error => { |
| | | this.loading = false |
| | | console.error('任务创建失败:', error) |
| | | this.$modal.showToast('任务创建失败,请重试') |
| | | }) |
| | | }).catch(() => {}) |
| | | }, |
| | | |
| | | // 上传待上传的附件(OCR图片) |
| | | uploadPendingAttachments(taskId) { |
| | | console.log('开始上传附件,taskId:', taskId, '附件数量:', this.pendingAttachments.length) |
| | | |
| | | // 使用 Promise.all 并发上传所有附件 |
| | | const uploadPromises = this.pendingAttachments.map(attachment => { |
| | | return this.uploadSingleAttachment(taskId, attachment) |
| | | }) |
| | | |
| | | return Promise.all(uploadPromises) |
| | | }, |
| | | |
| | | // 上传单个附件 |
| | | uploadSingleAttachment(taskId, attachment) { |
| | | return new Promise((resolve, reject) => { |
| | | uni.uploadFile({ |
| | | url: config.baseUrl + '/task/attachment/upload/' + taskId, |
| | | filePath: attachment.filePath, |
| | | name: 'file', |
| | | formData: { |
| | | 'category': attachment.category |
| | | }, |
| | | header: { |
| | | 'Authorization': 'Bearer ' + getToken() |
| | | }, |
| | | success: function(uploadRes) { |
| | | if (uploadRes.statusCode === 200) { |
| | | const result = JSON.parse(uploadRes.data) |
| | | if (result.code === 200) { |
| | | console.log('附件上传成功:', attachment.description) |
| | | resolve(result) |
| | | } else { |
| | | console.error('附件上传失败:', attachment.description, result.msg) |
| | | reject(result) |
| | | } |
| | | } else { |
| | | console.error('附件上传失败:', attachment.description, uploadRes) |
| | | reject(uploadRes) |
| | | } |
| | | }, |
| | | fail: function(err) { |
| | | console.error('附件上传失败:', attachment.description, err) |
| | | reject(err) |
| | | } |
| | | }) |
| | | }) |
| | | }, |
| | | |
| | | // 跳转到任务列表 |
| | | navigateToTaskList() { |
| | | setTimeout(() => { |
| | | // 跳转到任务列表并触发刷新 |
| | | uni.switchTab({ |
| | | url: '/pages/task/index', |
| | | success: () => { |
| | | // 使用事件总线通知任务列表页面刷新 |
| | | uni.$emit('refreshTaskList') |
| | | } |
| | | }) |
| | | }, 1000) |
| | | }, |
| | | |
| | | goBack() { |
| | |
| | | findHospitalByName(name, type, restrictRegion = true) { |
| | | if (!name) return Promise.resolve(null) |
| | | const normalized = name.trim() |
| | | |
| | | |
| | | // 特殊处理"家中" |
| | | if (normalized === '家中') { |
| | | // 查询医院库中的"家中"记录 |
| | |
| | | const queryPromise = restrictRegion && deptId |
| | | ? searchHospitalsByDeptRegion('家中', deptId, 50) |
| | | : searchHospitals('家中', null, 50) |
| | | |
| | | |
| | | return queryPromise.then(res => { |
| | | const list = res.data || [] |
| | | // 查找名称为"家中"的医院记录 |
| | |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // restrictRegion=false 时走全量查询;true 且有 deptId 时走区域接口 |
| | | |
| | | // OCR识别后的医院名称,使用新的分词匹配接口 |
| | | const deptId = this.selectedOrganizationId || null |
| | | const queryPromise = (restrictRegion && deptId) |
| | | ? searchHospitalsByDeptRegion(normalized, deptId, 50) |
| | | : searchHospitals(normalized, null, 50) |
| | | |
| | | return queryPromise.then(res => { |
| | | const list = res.data || [] |
| | | if (!list.length) return null |
| | | |
| | | // 自动选择第一个非"家中"的区院,如果全是"家中"则选第一个 |
| | | const best = this.pickBestHospitalMatch(list, normalized) |
| | | return best || null |
| | | |
| | | return searchHospitalsByKeywords(normalized, deptId, 50).then(res => { |
| | | const rawData = res.data || [] |
| | | if (!rawData.length) return null |
| | | |
| | | // 提取 hospital 对象(接口返回格式:{hospital: {...}, matchScore: ...}) |
| | | const firstItem = rawData[0] |
| | | const firstHospital = firstItem.hospital || firstItem |
| | | |
| | | console.log(`OCR识别医院"${normalized}",自动选中:${firstHospital.hospName}(匹配分数:${firstItem.matchScore || 'N/A'})`) |
| | | return firstHospital |
| | | }).catch(error => { |
| | | console.error(`搜索医院"${normalized}"失败:`, error) |
| | | return null |
| | | }) |
| | | }, |
| | | |
| | |
| | | console.error('距离计算失败:', error) |
| | | this.$modal.showToast('距离计算失败,请手动输入') |
| | | }) |
| | | }, |
| | | |
| | | // ==================== 拍照识别相关方法 ==================== |
| | | |
| | | // 显示多图拍照识别弹窗 |
| | | showMultiPhotoOCRPopup() { |
| | | this.page1Image = '' |
| | | this.page2Image = '' |
| | | this.page1Fields = {} |
| | | this.page2Fields = {} |
| | | this.$refs.multiPhotoOCRPopup.open() |
| | | }, |
| | | |
| | | // 关闭多图拍照识别弹窗 |
| | | closeMultiPhotoOCRPopup() { |
| | | this.$refs.multiPhotoOCRPopup.close() |
| | | }, |
| | | |
| | | // 选择第一页图片 |
| | | selectPage1Images() { |
| | | uni.showActionSheet({ |
| | | itemList: ['从相册选择', '拍照'], |
| | | success: (res) => { |
| | | if (res.tapIndex === 0) { |
| | | this.chooseImageForPage(1, 'album') |
| | | } else if (res.tapIndex === 1) { |
| | | this.chooseImageForPage(1, 'camera') |
| | | } |
| | | } |
| | | }) |
| | | }, |
| | | |
| | | // 选择第二页图片 |
| | | selectPage2Images() { |
| | | uni.showActionSheet({ |
| | | itemList: ['从相册选择', '拍照'], |
| | | success: (res) => { |
| | | if (res.tapIndex === 0) { |
| | | this.chooseImageForPage(2, 'album') |
| | | } else if (res.tapIndex === 1) { |
| | | this.chooseImageForPage(2, 'camera') |
| | | } |
| | | } |
| | | }) |
| | | }, |
| | | |
| | | // 删除第一页图片 |
| | | deletePage1Image() { |
| | | this.page1Image = '' |
| | | this.page1Fields = {} |
| | | }, |
| | | |
| | | // 删除第二页图片 |
| | | deletePage2Image() { |
| | | this.page2Image = '' |
| | | this.page2Fields = {} |
| | | }, |
| | | |
| | | // 为指定页码选择图片(单图) |
| | | chooseImageForPage(page, sourceType) { |
| | | uni.chooseImage({ |
| | | count: 1, // 只选择一张图片 |
| | | sizeType: ['compressed'], |
| | | sourceType: [sourceType], |
| | | success: (res) => { |
| | | const imagePath = res.tempFilePaths[0] |
| | | |
| | | if (page === 1) { |
| | | this.page1Image = imagePath |
| | | } else { |
| | | this.page2Image = imagePath |
| | | } |
| | | |
| | | // 选择完图片后,立即进行OCR识别 |
| | | this.$modal.showToast(`已选择图片,开始识别...`) |
| | | this.recognizeSinglePage(page) |
| | | }, |
| | | fail: (err) => { |
| | | console.error('选择图片失败:', err) |
| | | this.$modal.showToast('选择图片失败') |
| | | } |
| | | }) |
| | | }, |
| | | |
| | | // 应用OCR识别结果到表单 |
| | | applyOcrResult() { |
| | | // 合并两页的识别结果 |
| | | const mergedFields = { ...this.page1Fields, ...this.page2Fields } |
| | | |
| | | // 处理合并后的识别结果 |
| | | this.processMultiOCRResult(mergedFields) |
| | | |
| | | // 保存OCR图片到待上传附件列表(知情同意书,分类为'1') |
| | | this.pendingAttachments = [] |
| | | if (this.page1Image) { |
| | | this.pendingAttachments.push({ |
| | | filePath: this.page1Image, |
| | | category: '1', // 知情同意书 |
| | | description: '知情同意书第一页' |
| | | }) |
| | | } |
| | | if (this.page2Image) { |
| | | this.pendingAttachments.push({ |
| | | filePath: this.page2Image, |
| | | category: '1', // 知情同意书 |
| | | description: '知情同意书第二页' |
| | | }) |
| | | } |
| | | |
| | | console.log('保存待上传附件:', this.pendingAttachments) |
| | | |
| | | // 关闭弹窗 |
| | | this.closeMultiPhotoOCRPopup() |
| | | |
| | | // 清空图片和结果(但保留 pendingAttachments) |
| | | this.page1Image = '' |
| | | this.page2Image = '' |
| | | this.page1Fields = {} |
| | | this.page2Fields = {} |
| | | |
| | | this.$modal.showToast('已应用到表单,知情同意书将在任务创建后上传') |
| | | }, |
| | | |
| | | // 识别单个页码的图片(选择后立即识别) |
| | | recognizeSinglePage(page) { |
| | | const image = page === 1 ? this.page1Image : this.page2Image |
| | | |
| | | if (!image) { |
| | | return |
| | | } |
| | | |
| | | // 显示加载提示 |
| | | uni.showLoading({ |
| | | title: `识别第${page}页...` |
| | | }) |
| | | |
| | | // 第一页的itemNames |
| | | const page1ItemNames = [ |
| | | "患者姓名", "性别", "年龄", "身份证号", "诊断", |
| | | "需支付转运费用", "行程", "开始时间", "结束时间", "家属签名" |
| | | ] |
| | | |
| | | // 第二页的itemNames |
| | | const page2ItemNames = [ |
| | | "患者签名(手印)", "签字人身份证号码", "签字人身份证号", "日期", |
| | | "联系电话", "本人", "签字人与患者关系" |
| | | ] |
| | | |
| | | const itemNames = page === 1 ? page1ItemNames : page2ItemNames |
| | | |
| | | // 调用批量OCR API(传入单个图片) |
| | | batchRecognizeImages([image], itemNames) |
| | | .then(result => { |
| | | uni.hideLoading() |
| | | |
| | | if (result.success && result.successCount > 0) { |
| | | // 保存识别结果 |
| | | if (page === 1) { |
| | | this.page1Fields = result.fields |
| | | } else { |
| | | this.page2Fields = result.fields |
| | | } |
| | | |
| | | console.log(`第${page}页识别结果:`, result.fields) |
| | | this.$modal.showToast(`第${page}页识别成功`) |
| | | } else { |
| | | this.$modal.showToast(`第${page}页识别失败`) |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | uni.hideLoading() |
| | | console.error(`第${page}页OCR识别失败:`, error) |
| | | this.$modal.showToast(error.msg || `第${page}页识别失败`) |
| | | }) |
| | | }, |
| | | |
| | | // 处理多图OCR识别结果 |
| | | processMultiOCRResult(fields) { |
| | | console.log('多图OCR识别结果:', fields) |
| | | |
| | | // 提取患者姓名 |
| | | if (fields['患者姓名']) { |
| | | this.taskForm.patient.name = fields['患者姓名'].trim() |
| | | } |
| | | |
| | | // 提取联系人(优先患者签名,其次家属签名,最后本人) |
| | | if (fields['患者签名(手印)']) { |
| | | this.taskForm.patient.contact = fields['患者签名(手印)'].trim() |
| | | } else if (fields['家属签名']) { |
| | | this.taskForm.patient.contact = fields['家属签名'].trim() |
| | | } else if (fields['本人']) { |
| | | this.taskForm.patient.contact = fields['本人'].trim() |
| | | } |
| | | |
| | | // 提取性别 |
| | | if (fields['性别']) { |
| | | const gender = fields['性别'].trim() |
| | | if (gender.includes('男')) { |
| | | this.taskForm.patient.gender = 'male' |
| | | } else if (gender.includes('女')) { |
| | | this.taskForm.patient.gender = 'female' |
| | | } |
| | | } |
| | | |
| | | // 提取身份证号(优先身份证号,其次签字人身份证号码) |
| | | const patientIdCard = fields['身份证号'] || fields['患者身份证号'] |
| | | const signerIdCard = fields['签字人身份证号码'] || fields['签字人身份证号'] |
| | | |
| | | if (patientIdCard) { |
| | | this.taskForm.patient.idCard = patientIdCard.trim() |
| | | } else if (signerIdCard) { |
| | | this.taskForm.patient.idCard = signerIdCard.trim() |
| | | } |
| | | |
| | | // 提取日期(转运时间) |
| | | if (fields['日期']) { |
| | | const dateString = fields['日期'].trim() |
| | | const dateFormatted = this.formatDateString(dateString) |
| | | if (dateFormatted) { |
| | | this.taskForm.transferTime = dateFormatted |
| | | } |
| | | } |
| | | |
| | | // 提取联系电话 |
| | | if (fields['联系电话']) { |
| | | this.taskForm.patient.phone = fields['联系电话'].trim() |
| | | } |
| | | |
| | | // 提取需支付转运费用(成交价) |
| | | if (fields['需支付转运费用']) { |
| | | const priceText = fields['需支付转运费用'].trim() |
| | | const priceNumber = priceText.match(/\d+(?:\.\d{1,2})?/) |
| | | if (priceNumber) { |
| | | this.taskForm.price = parseFloat(priceNumber[0]).toFixed(2) |
| | | } |
| | | } |
| | | |
| | | // 提取诊断(病情)(限制10个字符以内,避免误识别) |
| | | if (fields['诊断']) { |
| | | const diagnosis = fields['诊断'].trim() |
| | | // 只有当10个字符以内的诊断信息才填入表单 |
| | | if (diagnosis.length <= 10) { |
| | | this.taskForm.patient.condition = diagnosis |
| | | } else { |
| | | console.log('诊断信息过长,可能为误识别,已忽略:', diagnosis) |
| | | } |
| | | } |
| | | |
| | | // 提取行程(转出医院和转入医院) |
| | | if (fields['行程']) { |
| | | const route = fields['行程'].trim() |
| | | console.log('【行程】OCR识别的行程信息:', route) |
| | | |
| | | // 按多种分隔符分割行程:-、—、---、-->、→、空格等 |
| | | const hospitals = route.split(/[-—]{1,3}|-->|→|\s{2,}/).map(h => h.trim()).filter(h => h.length > 0) |
| | | console.log('【行程】分割后的医院列表:', hospitals) |
| | | |
| | | if (hospitals.length >= 2) { |
| | | // 第一个是转出医院 |
| | | const outHospital = hospitals[0] |
| | | this.taskForm.hospitalOut.name = outHospital |
| | | |
| | | // 如枟转出医院是“家中”,提取后面的详细地址 |
| | | if (outHospital === '家中' && hospitals.length >= 3) { |
| | | // 将剩余部分作为详细地址 |
| | | const detailAddress = hospitals.slice(1, hospitals.length - 1).join(' ') |
| | | if (detailAddress) { |
| | | this.taskForm.hospitalOut.address = detailAddress |
| | | console.log('【行程】转出家中地址:', detailAddress) |
| | | } |
| | | // 最后一个是转入医院 |
| | | this.taskForm.hospitalIn.name = hospitals[hospitals.length - 1] |
| | | console.log('【行程】转入医院:', hospitals[hospitals.length - 1]) |
| | | } else { |
| | | // 第二个是转入医院 |
| | | const inHospital = hospitals[1] |
| | | this.taskForm.hospitalIn.name = inHospital |
| | | |
| | | // 如果转入医院是“家中”,提取后面的详细地址 |
| | | if (inHospital === '家中' && hospitals.length >= 3) { |
| | | // 将剩余部分作为详细地址 |
| | | const detailAddress = hospitals.slice(2).join(' ') |
| | | if (detailAddress) { |
| | | this.taskForm.hospitalIn.address = detailAddress |
| | | console.log('【行程】转入家中地址:', detailAddress) |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 尝试从医院库中匹配并补全地址(只在非“家中”时) |
| | | const outHospitalName = this.taskForm.hospitalOut.name |
| | | const inHospitalName = this.taskForm.hospitalIn.name |
| | | |
| | | Promise.all([ |
| | | outHospitalName !== '家中' ? this.findHospitalByName(outHospitalName, 'out', false) : Promise.resolve(null), |
| | | inHospitalName !== '家中' ? this.findHospitalByName(inHospitalName, 'in', false) : Promise.resolve(null) |
| | | ]).then(([outHosp, inHosp]) => { |
| | | // 处理转出医院 |
| | | if (outHospitalName !== '家中') { |
| | | if (outHosp) { |
| | | // 找到医院,使用医院库中的信息 |
| | | this.taskForm.hospitalOut.id = outHosp.hospId |
| | | this.taskForm.hospitalOut.name = outHosp.hospName |
| | | this.taskForm.hospitalOut.address = this.buildFullAddress(outHosp) |
| | | this.taskForm.hospitalOut.city = outHosp.hopsCity || '' |
| | | console.log('【行程】转出医院匹配成功:', outHosp.hospName) |
| | | } else { |
| | | // 找不到医院,默认设置为"家中",原医院名称作为地址 |
| | | console.log('【行程】转出医院未找到,默认设置为家中,地址为:', outHospitalName) |
| | | this.taskForm.hospitalOut.name = '家中' |
| | | this.taskForm.hospitalOut.address = outHospitalName |
| | | this.taskForm.hospitalOut.id = null |
| | | this.taskForm.hospitalOut.city = '' |
| | | } |
| | | } |
| | | |
| | | // 处理转入医院 |
| | | if (inHospitalName !== '家中') { |
| | | if (inHosp) { |
| | | // 找到医院,使用医院库中的信息 |
| | | this.taskForm.hospitalIn.id = inHosp.hospId |
| | | this.taskForm.hospitalIn.name = inHosp.hospName |
| | | this.taskForm.hospitalIn.address = this.buildFullAddress(inHosp) |
| | | this.taskForm.hospitalIn.city = inHosp.hopsCity || '' |
| | | console.log('【行程】转入医院匹配成功:', inHosp.hospName) |
| | | } else { |
| | | // 找不到医院,默认设置为"家中",原医院名称作为地址 |
| | | console.log('【行程】转入医院未找到,默认设置为家中,地址为:', inHospitalName) |
| | | this.taskForm.hospitalIn.name = '家中' |
| | | this.taskForm.hospitalIn.address = inHospitalName |
| | | this.taskForm.hospitalIn.id = null |
| | | this.taskForm.hospitalIn.city = '' |
| | | } |
| | | } |
| | | |
| | | // 如果两个医院地址都有,自动计算距离 |
| | | if (this.taskForm.hospitalOut.address && this.taskForm.hospitalIn.address && |
| | | this.taskForm.hospitalOut.name !== '家中' && this.taskForm.hospitalIn.name !== '家中') { |
| | | this.calculateHospitalDistance() |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | |
| | | console.log('多图OCR结果处理完成,表单数据更新') |
| | | }, |
| | | |
| | | // 格式化日期字符串(返回 yyyy-MM-dd HH:mm:ss 格式) |
| | | formatDateString(dateStr) { |
| | | // 尝试不同的日期格式 |
| | | // 支持格式: |
| | | // - yyyy年MM月dd日HH时mm分 |
| | | // - yyyy年MM月dd日 |
| | | // - YYYYMMDD |
| | | // - yyyy-MM-dd HH:mm:ss |
| | | console.log('尝试格式化日期字符串:', dateStr) |
| | | |
| | | // 如果输入为空或无效,返回空字符串 |
| | | if (!dateStr || typeof dateStr !== 'string') { |
| | | console.warn('日期字符串无效:', dateStr) |
| | | return '' |
| | | } |
| | | |
| | | // 清洗日期字符串 |
| | | let cleaned = dateStr |
| | | .replace(/[年月]/g, '-') |
| | | .replace(/[日号]/g, ' ') // 日/号 → 空格,保留日期和时间的分隔 |
| | | .replace(/时/g, ':') |
| | | .replace(/分/g, ':') |
| | | .replace(/秒/g, '') |
| | | .replace(/\s+/g, ' ') // 多个空格合并为一个 |
| | | .trim() |
| | | |
| | | console.log('清理后的日期字符串:', cleaned) |
| | | |
| | | // 分离日期和时间部分 |
| | | const parts = cleaned.split(' ') |
| | | let datePart = parts[0] || '' |
| | | let timePart = parts[1] || '' |
| | | |
| | | let dateResult = '' |
| | | |
| | | // 处理日期部分 |
| | | // 如果是YYMMDD格式 |
| | | if (/^\d{6}$/.test(datePart)) { |
| | | const year = '20' + datePart.substring(0, 2) |
| | | const month = datePart.substring(2, 4) |
| | | const day = datePart.substring(4, 6) |
| | | dateResult = `${year}-${month}-${day}` |
| | | } |
| | | // 如果是YYYYMMDD格式 |
| | | else if (/^\d{8}$/.test(datePart)) { |
| | | const year = datePart.substring(0, 4) |
| | | const month = datePart.substring(4, 6) |
| | | const day = datePart.substring(6, 8) |
| | | dateResult = `${year}-${month}-${day}` |
| | | } |
| | | // 如果是yyyy-MM-dd或yyyy/MM/dd格式 |
| | | else if (datePart.match(/^\d{4}[-\/]\d{1,2}[-\/]\d{1,2}$/)) { |
| | | dateResult = datePart.replace(/\//g, '-') |
| | | } |
| | | else { |
| | | dateResult = datePart |
| | | } |
| | | |
| | | // 验证日期部分是否有效 |
| | | if (!dateResult.match(/^\d{4}-\d{1,2}-\d{1,2}$/)) { |
| | | console.warn('日期格式不正确:', dateResult) |
| | | return '' |
| | | } |
| | | |
| | | // 处理时间部分 |
| | | let timeResult = '00:00:00' // 默认时间 |
| | | |
| | | if (timePart) { |
| | | // 移除末尾多余的冒号 |
| | | timePart = timePart.replace(/:+$/, '') |
| | | |
| | | // 分割时、分、秒 |
| | | const timeParts = timePart.split(':') |
| | | const hour = timeParts[0] || '00' |
| | | const minute = timeParts[1] || '00' |
| | | const second = timeParts[2] || '00' |
| | | |
| | | // 验证时间数字是否有效 |
| | | const hourNum = parseInt(hour, 10) |
| | | const minuteNum = parseInt(minute, 10) |
| | | const secondNum = parseInt(second, 10) |
| | | |
| | | if (!isNaN(hourNum) && !isNaN(minuteNum) && !isNaN(secondNum) && |
| | | hourNum >= 0 && hourNum < 24 && minuteNum >= 0 && minuteNum < 60 && secondNum >= 0 && secondNum < 60) { |
| | | // 补齐两位数 |
| | | timeResult = `${String(hourNum).padStart(2, '0')}:${String(minuteNum).padStart(2, '0')}:${String(secondNum).padStart(2, '0')}` |
| | | } else { |
| | | console.warn('时间数值超出范围,使用默认值00:00:00') |
| | | } |
| | | } |
| | | |
| | | const finalResult = `${dateResult} ${timeResult}` |
| | | console.log('最终格式化结果:', finalResult) |
| | | |
| | | return finalResult |
| | | } |
| | | } |
| | | } |
| | |
| | | color: #333; |
| | | } |
| | | |
| | | .smart-parse-btn { |
| | | .smart-parse-btn, |
| | | .ocr-page-btn { |
| | | position: relative; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | |
| | | |
| | | text { |
| | | font-size: 22rpx; |
| | | margin-top: 4rpx; |
| | | } |
| | | |
| | | .badge { |
| | | position: absolute; |
| | | top: 0; |
| | | right: 10rpx; |
| | | min-width: 32rpx; |
| | | height: 32rpx; |
| | | line-height: 32rpx; |
| | | text-align: center; |
| | | background-color: #ff4d4f; |
| | | color: white; |
| | | font-size: 20rpx; |
| | | border-radius: 16rpx; |
| | | padding: 0 8rpx; |
| | | } |
| | | } |
| | | |
| | | .smart-parse-btn { |
| | | text { |
| | | color: #007AFF; |
| | | } |
| | | } |
| | | |
| | | .ocr-page-btn:first-of-type { |
| | | text { |
| | | color: #52c41a; |
| | | } |
| | | } |
| | | |
| | | .ocr-page-btn:last-of-type { |
| | | text { |
| | | color: #FF6B00; |
| | | } |
| | | } |
| | | |
| | | .multi-photo-ocr-btn { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 10rpx 20rpx; |
| | | |
| | | text { |
| | | font-size: 22rpx; |
| | | color: #FF6B00; |
| | | margin-top: 4rpx; |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 拍照识别弹窗样式 |
| | | .photo-ocr-popup { |
| | | background-color: white; |
| | | border-radius: 20rpx 20rpx 0 0; |
| | | max-height: 80vh; |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | .popup-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 30rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | flex-shrink: 0; |
| | | |
| | | .popup-title { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 10rpx; |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | |
| | | text { |
| | | margin-left: 8rpx; |
| | | } |
| | | } |
| | | |
| | | .popup-close { |
| | | padding: 10rpx; |
| | | } |
| | | } |
| | | |
| | | .ocr-content { |
| | | flex: 1; |
| | | padding: 30rpx; |
| | | overflow-y: auto; |
| | | |
| | | .ocr-tip { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | padding: 20rpx; |
| | | background-color: #f0f7ff; |
| | | border-radius: 10rpx; |
| | | margin-bottom: 20rpx; |
| | | |
| | | text { |
| | | flex: 1; |
| | | margin-left: 10rpx; |
| | | font-size: 24rpx; |
| | | color: #666; |
| | | line-height: 1.6; |
| | | } |
| | | } |
| | | |
| | | .image-preview { |
| | | margin-bottom: 20rpx; |
| | | border: 1rpx solid #eee; |
| | | border-radius: 10rpx; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .multi-image-preview { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 15rpx; |
| | | margin-bottom: 20rpx; |
| | | |
| | | .image-item { |
| | | position: relative; |
| | | width: 200rpx; |
| | | height: 200rpx; |
| | | border: 1rpx solid #eee; |
| | | border-radius: 10rpx; |
| | | overflow: hidden; |
| | | |
| | | image { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .delete-btn { |
| | | position: absolute; |
| | | top: 5rpx; |
| | | right: 5rpx; |
| | | width: 40rpx; |
| | | height: 40rpx; |
| | | background-color: rgba(0, 0, 0, 0.6); |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .ocr-actions { |
| | | display: flex; |
| | | gap: 20rpx; |
| | | |
| | | button { |
| | | flex: 1; |
| | | height: 80rpx; |
| | | border-radius: 10rpx; |
| | | font-size: 28rpx; |
| | | } |
| | | |
| | | .select-btn { |
| | | background-color: #f5f5f5; |
| | | color: #333; |
| | | } |
| | | |
| | | .capture-btn { |
| | | background-color: #007AFF; |
| | | color: white; |
| | | } |
| | | } |
| | | |
| | | .image-count { |
| | | text-align: center; |
| | | margin-top: 20rpx; |
| | | font-size: 26rpx; |
| | | color: #FF6B00; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | // 页面上传区域 |
| | | .page-upload-section { |
| | | background: linear-gradient(135deg, #f9f9f9 0%, #ffffff 100%); |
| | | border-radius: 15rpx; |
| | | padding: 25rpx; |
| | | margin-bottom: 25rpx; |
| | | border: 2rpx solid #f0f0f0; |
| | | transition: all 0.3s; |
| | | |
| | | &.first-page { |
| | | border-left: 4rpx solid #52c41a; |
| | | |
| | | .page-badge { |
| | | background: linear-gradient(135deg, #52c41a 0%, #73d13d 100%); |
| | | |
| | | .page-number { |
| | | color: #52c41a; |
| | | } |
| | | } |
| | | } |
| | | |
| | | &.second-page { |
| | | border-left: 4rpx solid #FF6B00; |
| | | |
| | | .page-badge { |
| | | background: linear-gradient(135deg, #FF6B00 0%, #ff8c3a 100%); |
| | | |
| | | .page-number { |
| | | color: #FF6B00; |
| | | } |
| | | } |
| | | } |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .page-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20rpx; |
| | | |
| | | .page-title { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 15rpx; |
| | | flex: 1; |
| | | |
| | | .page-badge { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | width: 60rpx; |
| | | height: 60rpx; |
| | | background: linear-gradient(135deg, #52c41a 0%, #73d13d 100%); |
| | | border-radius: 50%; |
| | | position: relative; |
| | | |
| | | .page-number { |
| | | position: absolute; |
| | | bottom: -2rpx; |
| | | right: -2rpx; |
| | | width: 24rpx; |
| | | height: 24rpx; |
| | | background-color: #fff; |
| | | border-radius: 50%; |
| | | font-size: 16rpx; |
| | | font-weight: bold; |
| | | color: #52c41a; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); |
| | | } |
| | | } |
| | | |
| | | .page-info { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 4rpx; |
| | | |
| | | .page-main-title { |
| | | font-size: 28rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | |
| | | .page-sub-title { |
| | | font-size: 22rpx; |
| | | color: #999; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .upload-btn { |
| | | width: 60rpx; |
| | | height: 60rpx; |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | transition: all 0.3s; |
| | | box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); |
| | | |
| | | &.green { |
| | | border: 2rpx dashed #52c41a; |
| | | background-color: rgba(82, 196, 26, 0.05); |
| | | } |
| | | |
| | | &.orange { |
| | | border: 2rpx dashed #FF6B00; |
| | | background-color: rgba(255, 107, 0, 0.05); |
| | | } |
| | | |
| | | &:active { |
| | | transform: scale(0.95); |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 识别字段提示 |
| | | .field-hint { |
| | | background-color: #fffbe6; |
| | | border: 1rpx solid #ffe58f; |
| | | border-radius: 8rpx; |
| | | padding: 15rpx; |
| | | margin-bottom: 15rpx; |
| | | |
| | | text { |
| | | font-size: 22rpx; |
| | | color: #d48806; |
| | | line-height: 1.6; |
| | | } |
| | | } |
| | | |
| | | .images-container { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 10rpx; |
| | | margin-bottom: 15rpx; |
| | | |
| | | .image-item { |
| | | position: relative; |
| | | width: 150rpx; |
| | | height: 150rpx; |
| | | border: 1rpx solid #eee; |
| | | border-radius: 10rpx; |
| | | overflow: hidden; |
| | | |
| | | image { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .delete-btn { |
| | | position: absolute; |
| | | top: 5rpx; |
| | | right: 5rpx; |
| | | width: 35rpx; |
| | | height: 35rpx; |
| | | background-color: rgba(0, 0, 0, 0.6); |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 单图预览区域 |
| | | .single-image-container { |
| | | position: relative; |
| | | width: 100%; |
| | | height: 400rpx; |
| | | border: 1rpx solid #eee; |
| | | border-radius: 10rpx; |
| | | overflow: hidden; |
| | | margin-bottom: 15rpx; |
| | | background-color: #f5f5f5; |
| | | |
| | | .preview-image { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .delete-btn { |
| | | position: absolute; |
| | | top: 10rpx; |
| | | right: 10rpx; |
| | | width: 50rpx; |
| | | height: 50rpx; |
| | | background-color: rgba(0, 0, 0, 0.6); |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | z-index: 2; |
| | | |
| | | &:active { |
| | | transform: scale(0.95); |
| | | opacity: 0.9; |
| | | } |
| | | } |
| | | |
| | | // 图片状态标签 |
| | | .image-status { |
| | | position: absolute; |
| | | bottom: 10rpx; |
| | | left: 10rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 5rpx; |
| | | padding: 8rpx 15rpx; |
| | | background-color: rgba(82, 196, 26, 0.9); |
| | | border-radius: 20rpx; |
| | | z-index: 2; |
| | | |
| | | text { |
| | | font-size: 22rpx; |
| | | color: #fff; |
| | | font-weight: 500; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .recognition-result { |
| | | background-color: white; |
| | | border-radius: 10rpx; |
| | | padding: 15rpx; |
| | | border: 1rpx solid #e0e0e0; |
| | | |
| | | .result-title { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 15rpx; |
| | | padding-bottom: 10rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | text { |
| | | margin-left: 8rpx; |
| | | font-size: 26rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | |
| | | .result-count { |
| | | margin-left: 8rpx; |
| | | font-size: 22rpx; |
| | | color: #999; |
| | | font-weight: normal; |
| | | } |
| | | } |
| | | |
| | | .field-list { |
| | | .field-item { |
| | | display: flex; |
| | | padding: 10rpx 0; |
| | | border-bottom: 1rpx solid #f9f9f9; |
| | | |
| | | &:last-child { |
| | | border-bottom: none; |
| | | } |
| | | |
| | | .field-name { |
| | | min-width: 150rpx; |
| | | font-size: 24rpx; |
| | | color: #666; |
| | | font-weight: 500; |
| | | |
| | | &::after { |
| | | content: ':'; |
| | | margin-left: 4rpx; |
| | | } |
| | | } |
| | | |
| | | .field-value { |
| | | flex: 1; |
| | | font-size: 24rpx; |
| | | color: #333; |
| | | word-break: break-all; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .page-indicator { |
| | | display: flex; |
| | | justify-content: center; |
| | | gap: 30rpx; |
| | | margin-top: 30rpx; |
| | | |
| | | .page-dot { |
| | | padding: 15rpx 30rpx; |
| | | border: 2rpx solid #ddd; |
| | | border-radius: 30rpx; |
| | | font-size: 26rpx; |
| | | color: #999; |
| | | background-color: #f5f5f5; |
| | | transition: all 0.3s; |
| | | |
| | | &.active { |
| | | border-color: #007AFF; |
| | | background-color: #007AFF; |
| | | color: white; |
| | | } |
| | | |
| | | &.completed { |
| | | border-color: #52c41a; |
| | | color: #52c41a; |
| | | |
| | | &.active { |
| | | background-color: #007AFF; |
| | | border-color: #007AFF; |
| | | color: white; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .popup-footer { |
| | | display: flex; |
| | | padding: 20rpx 30rpx; |
| | | border-top: 1rpx solid #f0f0f0; |
| | | gap: 20rpx; |
| | | flex-shrink: 0; |
| | | flex-wrap: wrap; |
| | | |
| | | button { |
| | | flex: 1; |
| | | min-width: 160rpx; |
| | | height: 80rpx; |
| | | border-radius: 10rpx; |
| | | font-size: 30rpx; |
| | | } |
| | | |
| | | .cancel-btn { |
| | | background-color: #f5f5f5; |
| | | color: #666; |
| | | } |
| | | |
| | | .next-btn, |
| | | .prev-btn { |
| | | background-color: #52c41a; |
| | | color: white; |
| | | } |
| | | |
| | | .confirm-btn { |
| | | background-color: #007AFF; |
| | | color: white; |
| | | |
| | | &[disabled] { |
| | | background-color: #ccc; |
| | | color: #999; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |