feat(clinical-web): 新增签署任务弹窗与文档库管理页面
This commit is contained in:
@@ -0,0 +1,923 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, ref, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
import type { SigningTaskRecord, SigningTemplate } from '@/api/workbench/types'
|
||||
import { useSigningTaskForm } from '@/composables/useSigningTaskForm'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean
|
||||
initialTemplate?: SigningTemplate | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
close: []
|
||||
created: [task: SigningTaskRecord]
|
||||
}>()
|
||||
|
||||
const appStore = useAppStore()
|
||||
const patientInput = ref<HTMLInputElement | null>(null)
|
||||
const initialTemplate = computed(() => props.initialTemplate ?? null)
|
||||
|
||||
const {
|
||||
documentSearch,
|
||||
errors,
|
||||
filteredTemplateGroups,
|
||||
loadingTemplates,
|
||||
loadTemplates,
|
||||
locatePatient,
|
||||
locating,
|
||||
maskPhone,
|
||||
method,
|
||||
patient,
|
||||
patientId,
|
||||
patientPhoneRevealed,
|
||||
resetForNextTask,
|
||||
resetForm,
|
||||
selectMethod,
|
||||
selectTemplate,
|
||||
selectVisit,
|
||||
selectedTemplate,
|
||||
selectedTemplateId,
|
||||
selectedVisit,
|
||||
selectedVisitId,
|
||||
smsPhone,
|
||||
submit: submitForm,
|
||||
submitting,
|
||||
togglePhone,
|
||||
visits,
|
||||
} = useSigningTaskForm({
|
||||
campus: computed(() => appStore.selectedCampus),
|
||||
initialTemplate,
|
||||
})
|
||||
|
||||
async function submitTask(keepOpen: boolean) {
|
||||
try {
|
||||
const task = await submitForm()
|
||||
|
||||
if (!task) {
|
||||
return
|
||||
}
|
||||
|
||||
emit('created', task)
|
||||
ElMessage.success(`已创建 1 个签署任务${task.method === 'sms' ? ',短信已发送' : ''}`)
|
||||
|
||||
if (keepOpen) {
|
||||
resetForNextTask()
|
||||
await nextTick()
|
||||
patientInput.value?.focus()
|
||||
return
|
||||
}
|
||||
|
||||
emit('close')
|
||||
} catch {
|
||||
ElMessage.error('签署任务创建失败,请稍后重试')
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
async (visible) => {
|
||||
if (!visible) {
|
||||
return
|
||||
}
|
||||
|
||||
resetForm()
|
||||
await loadTemplates()
|
||||
await nextTick()
|
||||
patientInput.value?.focus()
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Teleport to="body">
|
||||
<div v-if="visible" class="dialog-mask" @click.self="emit('close')">
|
||||
<section
|
||||
class="dialog-card new-task-dialog"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="new-task-title"
|
||||
>
|
||||
<header class="dialog-header">
|
||||
<strong id="new-task-title">新增签署任务</strong>
|
||||
<span>单页完成,无需分步</span>
|
||||
<button type="button" class="dialog-close" aria-label="关闭" @click="emit('close')">
|
||||
×
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<div class="dialog-body">
|
||||
<section class="form-section">
|
||||
<header class="section-header">
|
||||
<span class="section-index">A</span>
|
||||
<strong>患者定位</strong>
|
||||
<span>输入患者 ID / 门诊号 / 住院号,回车定位</span>
|
||||
</header>
|
||||
<div class="section-body">
|
||||
<div class="patient-search">
|
||||
<input
|
||||
ref="patientInput"
|
||||
v-model="patientId"
|
||||
placeholder="如:P202610001"
|
||||
aria-label="患者 ID"
|
||||
@input="errors.patient = ''"
|
||||
@keydown.enter.prevent="locatePatient"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="action-button"
|
||||
:disabled="locating"
|
||||
@click="locatePatient"
|
||||
>
|
||||
{{ locating ? '定位中…' : '定位患者' }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="patient" class="patient-card">
|
||||
<span class="patient-avatar" aria-hidden="true">人</span>
|
||||
<strong>{{ patient.name }}</strong>
|
||||
<span>{{ patient.sex }} · {{ patient.age }}岁</span>
|
||||
<span class="patient-field"><small>身份证号</small>{{ patient.idCard }}</span>
|
||||
<span class="patient-field">
|
||||
<small>手机号</small>
|
||||
{{ patientPhoneRevealed ? patient.phone : maskPhone(patient.phone) }}
|
||||
<button type="button" class="inline-button" @click="togglePhone">
|
||||
{{ patientPhoneRevealed ? '隐藏明文' : '显示明文' }}
|
||||
</button>
|
||||
</span>
|
||||
<span class="patient-field"><small>患者 ID</small>{{ patient.id }}</span>
|
||||
<span v-if="selectedVisit?.isCurrent" class="in-hospital">在院</span>
|
||||
</div>
|
||||
<p v-if="errors.patient" class="field-error">{{ errors.patient }}</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="form-section">
|
||||
<header class="section-header">
|
||||
<span class="section-index">B</span>
|
||||
<strong>关联就诊</strong>
|
||||
<span>默认最近一次,在院优先</span>
|
||||
</header>
|
||||
<div class="section-body">
|
||||
<div v-if="visits.length" class="visit-list">
|
||||
<button
|
||||
v-for="visit in visits"
|
||||
:key="visit.id"
|
||||
type="button"
|
||||
class="visit-option"
|
||||
:class="{ 'visit-option--active': visit.id === selectedVisitId }"
|
||||
@click="selectVisit(visit)"
|
||||
>
|
||||
<span class="radio-mark" />
|
||||
<strong>{{ visit.type }} · {{ visit.department }}</strong>
|
||||
<span class="visit-number">{{ visit.visitNo }}</span>
|
||||
<span class="visit-date">{{ visit.visitDate }}</span>
|
||||
<span v-if="visit.isCurrent" class="visit-current">● 在院</span>
|
||||
<span v-else-if="visit === visits[0]" class="visit-current visit-current--recent"
|
||||
>最近一次</span
|
||||
>
|
||||
</button>
|
||||
</div>
|
||||
<p v-else class="section-empty">请先定位患者…</p>
|
||||
<p v-if="errors.visit" class="field-error">{{ errors.visit }}</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="document-method-grid">
|
||||
<section class="form-section document-section">
|
||||
<header class="section-header">
|
||||
<span class="section-index">C</span>
|
||||
<strong>选择文档</strong>
|
||||
<span>单选一份</span>
|
||||
<input
|
||||
v-model="documentSearch"
|
||||
placeholder="⌕ 搜索文档名称…"
|
||||
aria-label="搜索文档"
|
||||
/>
|
||||
</header>
|
||||
<div class="section-body">
|
||||
<div v-if="selectedTemplate" class="selected-template">
|
||||
<span>已选:</span>
|
||||
<strong>{{ selectedTemplate.name }}</strong>
|
||||
<button type="button" aria-label="移除已选文档" @click="selectedTemplateId = ''">
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="loadingTemplates" class="tree-loading">正在加载文档模板…</div>
|
||||
<div v-else-if="filteredTemplateGroups.length" class="template-tree">
|
||||
<div
|
||||
v-for="department in filteredTemplateGroups"
|
||||
:key="department.name"
|
||||
class="tree-department"
|
||||
>
|
||||
<div class="tree-label">
|
||||
<span>▾</span><strong>{{ department.name }}</strong>
|
||||
</div>
|
||||
<div
|
||||
v-for="category in department.categories"
|
||||
:key="category.name"
|
||||
class="tree-category"
|
||||
>
|
||||
<div class="tree-label tree-label--category">
|
||||
<span>▾</span>{{ category.name
|
||||
}}<small>{{ category.templates.length }}</small>
|
||||
</div>
|
||||
<button
|
||||
v-for="template in category.templates"
|
||||
:key="template.id"
|
||||
type="button"
|
||||
class="document-option"
|
||||
:class="{ 'document-option--active': selectedTemplateId === template.id }"
|
||||
@click="selectTemplate(template)"
|
||||
>
|
||||
<span class="radio-mark radio-mark--document">●</span>
|
||||
<span>{{ template.name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="tree-empty">没有匹配的文档模板</div>
|
||||
<p v-if="errors.document" class="field-error">{{ errors.document }}</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="form-section method-section">
|
||||
<header class="section-header">
|
||||
<span class="section-index">D</span>
|
||||
<strong>签署方式</strong>
|
||||
<span>二选一</span>
|
||||
</header>
|
||||
<div class="section-body">
|
||||
<div class="method-list">
|
||||
<button
|
||||
type="button"
|
||||
class="method-option"
|
||||
:class="{ 'method-option--active': method === 'pad' }"
|
||||
:disabled="
|
||||
Boolean(
|
||||
selectedTemplate && !selectedTemplate.supportedMethods.includes('pad'),
|
||||
)
|
||||
"
|
||||
@click="selectMethod('pad')"
|
||||
>
|
||||
<span class="method-icon">✍</span>
|
||||
<span
|
||||
><strong>手写板签署(现场)</strong
|
||||
><small>护士站手写板签署,即签即得</small></span
|
||||
>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="method-option"
|
||||
:class="{ 'method-option--active': method === 'sms' }"
|
||||
:disabled="
|
||||
Boolean(
|
||||
selectedTemplate && !selectedTemplate.supportedMethods.includes('sms'),
|
||||
)
|
||||
"
|
||||
@click="selectMethod('sms')"
|
||||
>
|
||||
<span class="method-icon">📱</span>
|
||||
<span
|
||||
><strong>线上签署(短信链接)</strong
|
||||
><small>短信发送链接,48 小时内有效</small></span
|
||||
>
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="method === 'sms'" class="sms-confirm">
|
||||
<div class="sms-row">
|
||||
<span class="sms-icon">📱</span>
|
||||
<strong>短信将发送至</strong>
|
||||
<input
|
||||
v-model="smsPhone"
|
||||
placeholder="请确认手机号"
|
||||
aria-label="短信接收手机号"
|
||||
@input="errors.phone = ''"
|
||||
/>
|
||||
</div>
|
||||
<p>可修改为患者其他号码,修改将记录留痕</p>
|
||||
<p v-if="errors.phone" class="field-error">{{ errors.phone }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="dialog-footer">
|
||||
<span>患者手写签名图片将合成至文档签名域,PDF 原件与签名原图双留存</span>
|
||||
<span class="footer-spacer" />
|
||||
<button type="button" class="action-button action-button--ghost" @click="emit('close')">
|
||||
取消
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="action-button action-button--ghost"
|
||||
:disabled="submitting"
|
||||
@click="submitTask(true)"
|
||||
>
|
||||
提交并继续新增
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="action-button"
|
||||
:disabled="submitting"
|
||||
@click="submitTask(false)"
|
||||
>
|
||||
{{ submitting ? '提交中…' : '提交任务' }}
|
||||
</button>
|
||||
</footer>
|
||||
</section>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.dialog-mask {
|
||||
position: fixed;
|
||||
z-index: 50;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
overflow-y: auto;
|
||||
background: rgb(9 40 52 / 45%);
|
||||
}
|
||||
|
||||
.dialog-card {
|
||||
width: 680px;
|
||||
max-width: 96vw;
|
||||
max-height: calc(100vh - 32px);
|
||||
margin: auto;
|
||||
background: #fff;
|
||||
border-radius: 14px;
|
||||
box-shadow: var(--sh-modal);
|
||||
animation: dialog-pop 0.18s ease;
|
||||
}
|
||||
|
||||
.new-task-dialog {
|
||||
display: flex;
|
||||
width: 1200px;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
padding: 12px 18px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.dialog-header strong {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.dialog-header > span {
|
||||
color: var(--mut);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.dialog-close {
|
||||
flex-shrink: 0;
|
||||
padding: 0;
|
||||
margin-left: auto;
|
||||
color: var(--mut);
|
||||
font-size: 20px;
|
||||
line-height: 1;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.dialog-body {
|
||||
min-height: 0;
|
||||
padding: 12px 18px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
margin-bottom: 8px;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
padding: 6px 12px;
|
||||
font-size: 12.5px;
|
||||
background: #f5f9fa;
|
||||
}
|
||||
|
||||
.section-header > span:not(.section-index) {
|
||||
margin-left: auto;
|
||||
color: var(--mut);
|
||||
font-size: 11px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.section-index {
|
||||
display: grid;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
flex-shrink: 0;
|
||||
color: #fff;
|
||||
font-size: 10.5px;
|
||||
background: var(--brand);
|
||||
border-radius: 50%;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.section-body {
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.patient-search {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.patient-search input,
|
||||
.sms-row input {
|
||||
min-width: 0;
|
||||
padding: 7px 10px;
|
||||
color: var(--ink);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.patient-search input {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.patient-search input:focus,
|
||||
.sms-row input:focus,
|
||||
.section-header input:focus {
|
||||
outline: none;
|
||||
border-color: var(--brand);
|
||||
}
|
||||
|
||||
.action-button {
|
||||
flex-shrink: 0;
|
||||
padding: 8px 16px;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
background: var(--brand);
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.action-button:hover:not(:disabled) {
|
||||
background: var(--brand-d);
|
||||
}
|
||||
|
||||
.action-button:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
.action-button--ghost {
|
||||
color: var(--brand);
|
||||
background: #fff;
|
||||
border: 1px solid var(--brand);
|
||||
}
|
||||
|
||||
.action-button--ghost:hover:not(:disabled) {
|
||||
background: var(--brand-l);
|
||||
}
|
||||
|
||||
.patient-card {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
padding: 7px 12px;
|
||||
margin-top: 8px;
|
||||
background: var(--brand-l);
|
||||
border: 1px solid var(--brand);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.patient-avatar {
|
||||
display: grid;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
background: var(--brand);
|
||||
border-radius: 50%;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.patient-card > strong {
|
||||
color: var(--brand-d);
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.patient-card > span:not(.patient-field):not(.patient-avatar):not(.in-hospital) {
|
||||
color: var(--ink);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.patient-field {
|
||||
display: inline-flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
color: var(--ink);
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.patient-field small {
|
||||
color: var(--mut);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.inline-button {
|
||||
padding: 2px 5px;
|
||||
color: var(--brand);
|
||||
font-size: 11px;
|
||||
background: transparent;
|
||||
border: 1px solid var(--brand);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.in-hospital {
|
||||
padding: 1px 7px;
|
||||
color: #fff;
|
||||
font-size: 10.5px;
|
||||
background: var(--err);
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.field-error {
|
||||
margin: 6px 0 0;
|
||||
color: var(--err);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.visit-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.visit-option {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 5px 10px;
|
||||
color: var(--ink);
|
||||
text-align: left;
|
||||
background: #fff;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.visit-option:hover,
|
||||
.visit-option--active {
|
||||
border-color: var(--brand);
|
||||
}
|
||||
|
||||
.visit-option--active {
|
||||
background: var(--brand-l);
|
||||
}
|
||||
|
||||
.radio-mark {
|
||||
display: inline-block;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
flex-shrink: 0;
|
||||
border: 2px solid #b8cbd4;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.visit-option--active .radio-mark {
|
||||
background: radial-gradient(circle, var(--brand) 42%, transparent 46%);
|
||||
border-color: var(--brand);
|
||||
}
|
||||
|
||||
.visit-option strong {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.visit-number,
|
||||
.visit-date {
|
||||
color: var(--mut);
|
||||
font-size: 11.5px;
|
||||
}
|
||||
|
||||
.visit-current {
|
||||
margin-left: auto;
|
||||
color: var(--ok);
|
||||
font-size: 10.5px;
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.visit-current--recent {
|
||||
color: var(--brand);
|
||||
}
|
||||
|
||||
.section-empty,
|
||||
.tree-empty,
|
||||
.tree-loading {
|
||||
padding: 4px 0;
|
||||
margin: 0;
|
||||
color: var(--mut);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.document-method-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 360px;
|
||||
gap: 12px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.document-section,
|
||||
.method-section {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.document-section .section-header input {
|
||||
width: 240px;
|
||||
padding: 4px 10px;
|
||||
margin-left: auto;
|
||||
color: var(--ink);
|
||||
font-size: 12.5px;
|
||||
background: #fff;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.document-section .section-header > span:not(.section-index) {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.selected-template {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
padding: 5px 8px;
|
||||
margin-bottom: 6px;
|
||||
color: var(--brand-d);
|
||||
font-size: 12px;
|
||||
background: var(--brand-l);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.selected-template strong {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.selected-template button {
|
||||
padding: 0 3px;
|
||||
margin-left: auto;
|
||||
color: var(--mut);
|
||||
font-size: 16px;
|
||||
line-height: 1;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.template-tree {
|
||||
height: 252px;
|
||||
padding: 6px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.tree-label {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
padding: 5px 6px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.tree-label > span {
|
||||
width: 12px;
|
||||
color: var(--mut);
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.tree-category {
|
||||
margin-left: 18px;
|
||||
}
|
||||
|
||||
.tree-label--category {
|
||||
color: var(--ink);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tree-label small {
|
||||
margin-left: auto;
|
||||
color: var(--mut);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.document-option {
|
||||
display: flex;
|
||||
width: calc(100% - 10px);
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
padding: 5px 6px;
|
||||
margin-left: 10px;
|
||||
color: var(--ink);
|
||||
font-size: 12.5px;
|
||||
text-align: left;
|
||||
background: transparent;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.document-option:hover,
|
||||
.document-option--active {
|
||||
background: var(--brand-l);
|
||||
}
|
||||
|
||||
.radio-mark--document {
|
||||
display: grid;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
color: transparent;
|
||||
font-size: 10px;
|
||||
border: 1.5px solid #b8cbd4;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.document-option--active .radio-mark--document {
|
||||
color: #fff;
|
||||
background: var(--brand);
|
||||
border-color: var(--brand);
|
||||
}
|
||||
|
||||
.method-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.method-option {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
padding: 8px 12px;
|
||||
color: var(--ink);
|
||||
text-align: left;
|
||||
background: #fff;
|
||||
border: 1.5px solid var(--line);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.method-option:hover:not(:disabled),
|
||||
.method-option--active {
|
||||
border-color: var(--brand);
|
||||
}
|
||||
|
||||
.method-option--active {
|
||||
background: var(--brand-l);
|
||||
}
|
||||
|
||||
.method-option:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
.method-icon {
|
||||
font-size: 19px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.method-option strong,
|
||||
.method-option small {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.method-option strong {
|
||||
margin-bottom: 1px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.method-option small {
|
||||
overflow: hidden;
|
||||
color: var(--mut);
|
||||
font-size: 11px;
|
||||
line-height: 1.5;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sms-confirm {
|
||||
padding: 9px 12px;
|
||||
margin-top: 10px;
|
||||
background: var(--brand-l);
|
||||
border: 1px dashed var(--brand);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.sms-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sms-row strong {
|
||||
flex-shrink: 0;
|
||||
color: var(--brand-d);
|
||||
font-size: 12.5px;
|
||||
}
|
||||
|
||||
.sms-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.sms-row input {
|
||||
width: 170px;
|
||||
}
|
||||
|
||||
.sms-confirm p {
|
||||
padding-left: 28px;
|
||||
margin: 6px 0 0;
|
||||
color: var(--mut);
|
||||
font-size: 11.5px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
padding: 10px 18px;
|
||||
color: var(--mut);
|
||||
font-size: 12px;
|
||||
background: #f8fbfc;
|
||||
border-top: 1px solid var(--line);
|
||||
border-radius: 0 0 14px 14px;
|
||||
}
|
||||
|
||||
.footer-spacer {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@keyframes dialog-pop {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.96) translateY(8px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1000px) {
|
||||
.document-method-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.method-section {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 680px) {
|
||||
.patient-card {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.section-header > span:not(.section-index) {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.document-section .section-header input {
|
||||
width: 100%;
|
||||
margin-left: 26px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
align-items: flex-end;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.dialog-footer > span:first-child {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user