Files
akmon/pages/ec/caregiver/task-execution.uvue
2026-01-20 08:04:15 +08:00

1256 lines
32 KiB
Plaintext

<!-- 护理任务执行 - 重构版本 -->
<template>
<view class="task-execution">
<!-- Header -->
<view class="header">
<text class="header-title">护理任务</text>
<view class="header-info">
<text class="current-shift">{{ currentShift }}</text>
<text class="current-time">{{ currentTime }}</text>
</view>
</view>
<!-- Task Summary -->
<view class="summary-section">
<view class="summary-card pending">
<view class="summary-icon">⏳</view>
<view class="summary-content">
<text class="summary-number">{{ stats.pending_tasks }}</text>
<text class="summary-label">待处理</text>
</view>
</view>
<view class="summary-card progress">
<view class="summary-icon">🔄</view>
<view class="summary-content">
<text class="summary-number">{{ stats.in_progress_tasks }}</text>
<text class="summary-label">进行中</text>
</view>
</view>
<view class="summary-card completed">
<view class="summary-icon">✅</view>
<view class="summary-content">
<text class="summary-number">{{ stats.completed_tasks }}</text>
<text class="summary-label">已完成</text>
</view>
</view>
<view class="summary-card overdue">
<view class="summary-icon">⚠️</view>
<view class="summary-content">
<text class="summary-number">{{ stats.overdue_tasks }}</text>
<text class="summary-label">已逾期</text>
</view>
</view>
</view>
<!-- Quick Actions -->
<view class="quick-actions">
<button class="quick-btn" @click="showEmergencyReport">
<text class="quick-icon">🚨</text>
<text class="quick-text">紧急上报</text>
</button>
<button class="quick-btn" @click="showQuickRecord">
<text class="quick-icon">📝</text>
<text class="quick-text">快速记录</text>
</button>
<button class="quick-btn" @click="showElderList">
<text class="quick-icon">👥</text>
<text class="quick-text">负责老人</text>
</button>
<button class="quick-btn" @click="refreshTasks">
<text class="quick-icon">🔄</text>
<text class="quick-text">刷新任务</text>
</button>
</view>
<!-- Filter Tabs -->
<view class="filter-tabs">
<button
class="filter-tab"
:class="{ active: activeTab === 'urgent' }"
@click="setActiveTab('urgent')"
>
<text class="tab-text">紧急任务</text>
<text class="tab-count">{{ urgentTasks.length }}</text>
</button>
<button
class="filter-tab"
:class="{ active: activeTab === 'scheduled' }"
@click="setActiveTab('scheduled')"
>
<text class="tab-text">计划任务</text>
<text class="tab-count">{{ scheduledTasks.length }}</text>
</button>
<button
class="filter-tab"
:class="{ active: activeTab === 'completed' }"
@click="setActiveTab('completed')"
>
<text class="tab-text">已完成</text>
<text class="tab-count">{{ completedTasks.length }}</text>
</button>
</view>
<!-- Task List -->
<view class="tasks-section">
<scroll-view class="tasks-list" scroll-y="true" :style="{ height: '500px' }">
<view
v-for="task in filteredTasks"
:key="task.id"
class="task-item"
:class="getTaskStatusClass(task)"
@click="viewTaskDetail(task)"
>
<view class="task-header">
<view class="task-priority">
<text class="priority-icon">{{ getPriorityIcon(task.priority) }}</text>
</view>
<view class="task-info">
<text class="task-name">{{ task.task_name }}</text>
<text class="elder-name">{{ task.elder_name }}</text>
</view>
<view class="task-time">
<text class="scheduled-time">{{ formatTime(task.scheduled_time) }}</text>
<text class="task-status">{{ getTaskStatusText(task.status) }}</text>
</view>
</view>
<view class="task-details">
<view class="detail-row">
<text class="detail-label">位置:</text>
<text class="detail-value">{{ task.room_number || '未指定' }}</text>
</view>
<view class="detail-row" v-if="task.estimated_duration">
<text class="detail-label">预计时长:</text>
<text class="detail-value">{{ task.estimated_duration }}分钟</text>
</view>
<view class="detail-row" v-if="task.description">
<text class="detail-label">备注:</text>
<text class="detail-value">{{ task.description }}</text>
</view>
</view>
<view class="task-actions">
<button
v-if="task.status === 'pending'"
class="action-btn primary"
@click.stop="startTask(task)"
>
<text class="btn-text">开始</text>
</button>
<button
v-if="task.status === 'in_progress'"
class="action-btn success"
@click.stop="completeTask(task)"
>
<text class="btn-text">完成</text>
</button>
<button
v-if="task.status === 'in_progress'"
class="action-btn warning"
@click.stop="pauseTask(task)"
>
<text class="btn-text">暂停</text>
</button>
<button
class="action-btn info"
@click.stop="addNote(task)"
>
<text class="btn-text">记录</text>
</button>
</view>
</view>
</scroll-view>
</view>
<!-- Task Detail Modal -->
<view v-if="showDetailModal" class="modal-overlay" @click="hideDetailModal">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">{{ currentTask?.task_name }}</text>
<button class="close-btn" @click="hideDetailModal">
<text class="close-text">✕</text>
</button>
</view>
<view class="modal-body">
<view class="task-summary">
<view class="summary-row">
<text class="summary-label">老人:</text>
<text class="summary-value">{{ currentTask?.elder_name }}</text>
</view>
<view class="summary-row">
<text class="summary-label">房间:</text>
<text class="summary-value">{{ currentTask?.room_number }}</text>
</view>
<view class="summary-row">
<text class="summary-label">计划时间:</text>
<text class="summary-value">{{ formatDateTime(currentTask?.scheduled_time) }}</text>
</view>
<view class="summary-row">
<text class="summary-label">优先级:</text>
<text class="summary-value">{{ getTaskPriorityText(currentTask?.priority) }}</text>
</view>
</view>
<view class="task-description" v-if="currentTask?.description">
<text class="desc-label">任务描述:</text>
<text class="desc-content">{{ currentTask.description }}</text>
</view>
<view class="execution-form" v-if="currentTask?.status === 'in_progress'">
<view class="form-group">
<text class="form-label">执行状态</text>
<picker
:value="executionStatusIndex"
:range="executionStatusOptions"
range-key="label"
@change="onExecutionStatusChange"
>
<text class="picker-text">{{ executionStatus?.label || '选择状态' }}</text>
</picker>
</view>
<view class="form-group">
<text class="form-label">执行记录</text>
<textarea
class="form-textarea"
placeholder="请记录执行情况、老人状态等"
v-model="executionRecord.notes"
/>
</view>
<view class="form-group">
<text class="form-label">老人状态</text>
<picker
:value="elderConditionIndex"
:range="elderConditionOptions"
range-key="label"
@change="onElderConditionChange"
>
<text class="picker-text">{{ elderCondition?.label || '选择状态' }}</text>
</picker>
</view>
<view class="form-group">
<text class="form-label">异常情况</text>
<textarea
class="form-textarea"
placeholder="如有异常情况请详细描述"
v-model="executionRecord.issues_notes"
/>
</view>
</view>
</view>
<view class="modal-footer">
<button class="cancel-btn" @click="hideDetailModal">
<text class="btn-text">关闭</text>
</button>
<button
v-if="currentTask?.status === 'pending'"
class="confirm-btn"
@click="startTaskFromModal"
>
<text class="btn-text">开始任务</text>
</button>
<button
v-if="currentTask?.status === 'in_progress'"
class="confirm-btn"
@click="completeTaskFromModal"
>
<text class="btn-text">完成任务</text>
</button>
</view>
</view>
</view>
<!-- Quick Record Modal -->
<view v-if="showQuickRecordModal" class="modal-overlay" @click="hideQuickRecordModal">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">快速记录</text>
<button class="close-btn" @click="hideQuickRecordModal">
<text class="close-text">✕</text>
</button>
</view>
<view class="modal-body">
<view class="form-group">
<text class="form-label">选择老人</text>
<picker
:value="quickRecordElderIndex"
:range="elderOptions"
range-key="name"
@change="onQuickRecordElderChange"
>
<text class="picker-text">{{ quickRecordElder?.name || '选择老人' }}</text>
</picker>
</view>
<view class="form-group">
<text class="form-label">记录类型</text>
<picker
:value="quickRecordTypeIndex"
:range="recordTypeOptions"
range-key="label"
@change="onQuickRecordTypeChange"
>
<text class="picker-text">{{ quickRecordType?.label || '选择类型' }}</text>
</picker>
</view>
<view class="form-group">
<text class="form-label">记录内容</text>
<textarea
class="form-textarea"
placeholder="请输入记录内容"
v-model="quickRecord.content"
/>
</view>
</view>
<view class="modal-footer">
<button class="cancel-btn" @click="hideQuickRecordModal">
<text class="btn-text">取消</text>
</button>
<button class="confirm-btn" @click="saveQuickRecord">
<text class="btn-text">保存</text>
</button>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { formatDateTime, formatTime, getTaskStatusText, getTaskPriorityText, getPriorityIcon } from '../types.uts'
import type { CareTask, Elder, CareRecord } from '../types.uts'
// Task stats type
type TaskStats = {
pending_tasks: number
in_progress_tasks: number
completed_tasks: number
overdue_tasks: number
}
// Execution record type
type ExecutionRecord = {
notes: string
issues_notes: string
elder_condition: string
status: string
}
// Quick record type
type QuickRecord = {
elder_id: string
type: string
content: string
}
// Data
const tasks = ref<CareTask[]>([])
const stats = ref<TaskStats>({
pending_tasks: 0,
in_progress_tasks: 0,
completed_tasks: 0,
overdue_tasks: 0
})
const currentTime = ref('')
const currentShift = ref('白班')
const activeTab = ref('urgent')
// Modal states
const showDetailModal = ref(false)
const showQuickRecordModal = ref(false)
const currentTask = ref<CareTask | null>(null)
// Form data
const executionRecord = ref<ExecutionRecord>({
notes: '',
issues_notes: '',
elder_condition: '',
status: ''
})
const quickRecord = ref<QuickRecord>({
elder_id: '',
type: '',
content: ''
})
// Options
const executionStatusOptions = ref([
{ value: 'normal', label: '正常执行' },
{ value: 'partial', label: '部分完成' },
{ value: 'delayed', label: '延期执行' },
{ value: 'cancelled', label: '取消执行' }
])
const elderConditionOptions = ref([
{ value: 'good', label: '状态良好' },
{ value: 'fair', label: '状态一般' },
{ value: 'poor', label: '状态较差' },
{ value: 'emergency', label: '紧急情况' }
])
const recordTypeOptions = ref([
{ value: 'health', label: '健康状况' },
{ value: 'behavior', label: '行为记录' },
{ value: 'mood', label: '情绪状态' },
{ value: 'diet', label: '饮食情况' },
{ value: 'sleep', label: '睡眠情况' },
{ value: 'medication', label: '用药情况' },
{ value: 'activity', label: '活动参与' },
{ value: 'other', label: '其他记录' }
])
const elderOptions = ref<Elder[]>([])
// Form indexes
const executionStatusIndex = ref(-1)
const elderConditionIndex = ref(-1)
const quickRecordElderIndex = ref(-1)
const quickRecordTypeIndex = ref(-1)
// Timer
let timeTimer: number | null = null
// Computed
const executionStatus = computed<any>(() => {
return executionStatusIndex.value >= 0 ? executionStatusOptions.value[executionStatusIndex.value] : null
})
const elderCondition = computed<any>(() => {
return elderConditionIndex.value >= 0 ? elderConditionOptions.value[elderConditionIndex.value] : null
})
const quickRecordElder = computed<Elder | null>(() => {
return quickRecordElderIndex.value >= 0 ? elderOptions.value[quickRecordElderIndex.value] : null
})
const quickRecordType = computed<any>(() => {
return quickRecordTypeIndex.value >= 0 ? recordTypeOptions.value[quickRecordTypeIndex.value] : null
})
const urgentTasks = computed<CareTask[]>(() => {
return tasks.value.filter(task =>
task.priority === 'urgent' || task.priority === 'high' || isTaskOverdue(task)
)
})
const scheduledTasks = computed<CareTask[]>(() => {
return tasks.value.filter(task =>
task.status === 'pending' || task.status === 'in_progress'
)
})
const completedTasks = computed<CareTask[]>(() => {
return tasks.value.filter(task => task.status === 'completed')
})
const filteredTasks = computed<CareTask[]>(() => {
switch (activeTab.value) {
case 'urgent':
return urgentTasks.value
case 'scheduled':
return scheduledTasks.value
case 'completed':
return completedTasks.value
default:
return tasks.value
}
})
// Methods
const loadTasks = async (): Promise<void> => {
try {
const response = await supa.executeAs('rpc/get_caregiver_tasks', {
caregiver_id: getCurrentCaregiver()
})
if (response.success && response.data) {
tasks.value = response.data as CareTask[]
}
} catch (error) {
console.error('加载任务列表失败:', error)
}
}
const loadStats = async (): Promise<void> => {
try {
const response = await supa.executeAs('rpc/get_task_stats', {
caregiver_id: getCurrentCaregiver()
})
if (response.success && response.data && response.data.length > 0) {
stats.value = response.data[0] as TaskStats
}
} catch (error) {
console.error('加载统计数据失败:', error)
}
}
const loadElders = async (): Promise<void> => {
try {
const response = await supa.executeAs('rpc/get_caregiver_elders', {
caregiver_id: getCurrentCaregiver()
})
if (response.success && response.data) {
elderOptions.value = response.data as Elder[]
}
} catch (error) {
console.error('加载老人列表失败:', error)
}
}
const getCurrentCaregiver = (): string => {
// 这里应该从用户状态或本地存储获取当前护理员ID
return 'current_caregiver_id'
}
const isTaskOverdue = (task: CareTask): boolean => {
if (!task.scheduled_time) return false
const scheduledTime = new Date(task.scheduled_time)
const now = new Date()
return scheduledTime < now && task.status !== 'completed'
}
const getTaskStatusClass = (task: CareTask): string => {
const classes = []
if (isTaskOverdue(task)) {
classes.push('overdue')
}
switch (task.priority) {
case 'urgent':
classes.push('priority-urgent')
break
case 'high':
classes.push('priority-high')
break
}
switch (task.status) {
case 'pending':
classes.push('status-pending')
break
case 'in_progress':
classes.push('status-progress')
break
case 'completed':
classes.push('status-completed')
break
}
return classes.join(' ')
}
const updateCurrentTime = (): void => {
const now = new Date()
currentTime.value = now.toLocaleTimeString('zh-CN', {
hour: '2-digit',
minute: '2-digit'
})
const hour = now.getHours()
if (hour >= 6 && hour < 14) {
currentShift.value = '白班'
} else if (hour >= 14 && hour < 22) {
currentShift.value = '夜班'
} else {
currentShift.value = '夜班'
}
}
// Event handlers
const setActiveTab = (tab: string): void => {
activeTab.value = tab
}
const refreshTasks = async (): Promise<void> => {
await Promise.all([
loadTasks(),
loadStats()
])
}
const viewTaskDetail = (task: CareTask): void => {
currentTask.value = task
executionRecord.value = {
notes: '',
issues_notes: '',
elder_condition: '',
status: ''
}
executionStatusIndex.value = -1
elderConditionIndex.value = -1
showDetailModal.value = true
}
const startTask = async (task: CareTask): Promise<void> => {
try {
const response = await supa.executeAs('update', {
table: 'care_tasks',
data: {
status: 'in_progress',
start_time: new Date().toISOString()
},
match: { id: task.id }
})
if (response.success) {
await refreshTasks()
}
} catch (error) {
console.error('开始任务失败:', error)
}
}
const completeTask = async (task: CareTask): Promise<void> => {
try {
const response = await supa.executeAs('update', {
table: 'care_tasks',
data: {
status: 'completed',
end_time: new Date().toISOString()
},
match: { id: task.id }
})
if (response.success) {
await refreshTasks()
}
} catch (error) {
console.error('完成任务失败:', error)
}
}
const pauseTask = async (task: CareTask): Promise<void> => {
try {
const response = await supa.executeAs('update', {
table: 'care_tasks',
data: { status: 'pending' },
match: { id: task.id }
})
if (response.success) {
await refreshTasks()
}
} catch (error) {
console.error('暂停任务失败:', error)
}
}
const addNote = (task: CareTask): void => {
currentTask.value = task
showDetailModal.value = true
}
// Modal methods
const hideDetailModal = (): void => {
showDetailModal.value = false
currentTask.value = null
}
const startTaskFromModal = async (): Promise<void> => {
if (currentTask.value) {
await startTask(currentTask.value)
hideDetailModal()
}
}
const completeTaskFromModal = async (): Promise<void> => {
if (!currentTask.value) return
try {
// 更新任务状态
const taskResponse = await supa.executeAs('update', {
table: 'care_tasks',
data: {
status: 'completed',
end_time: new Date().toISOString()
},
match: { id: currentTask.value.id }
})
// 保存护理记录
const recordResponse = await supa.executeAs('insert', {
table: 'care_records',
data: {
task_id: currentTask.value.id,
elder_id: currentTask.value.elder_id,
caregiver_id: getCurrentCaregiver(),
care_content: executionRecord.value.notes,
elder_condition: executionRecord.value.elder_condition,
issues_notes: executionRecord.value.issues_notes,
status: 'completed'
}
})
if (taskResponse.success && recordResponse.success) {
hideDetailModal()
await refreshTasks()
}
} catch (error) {
console.error('完成任务失败:', error)
}
}
const showEmergencyReport = (): void => {
console.log('显示紧急上报')
}
const showQuickRecord = (): void => {
quickRecord.value = {
elder_id: '',
type: '',
content: ''
}
quickRecordElderIndex.value = -1
quickRecordTypeIndex.value = -1
showQuickRecordModal.value = true
}
const hideQuickRecordModal = (): void => {
showQuickRecordModal.value = false
}
const showElderList = (): void => {
console.log('显示负责老人列表')
}
const onExecutionStatusChange = (e: any): void => {
executionStatusIndex.value = e.detail.value
if (executionStatus.value) {
executionRecord.value.status = executionStatus.value.value
}
}
const onElderConditionChange = (e: any): void => {
elderConditionIndex.value = e.detail.value
if (elderCondition.value) {
executionRecord.value.elder_condition = elderCondition.value.value
}
}
const onQuickRecordElderChange = (e: any): void => {
quickRecordElderIndex.value = e.detail.value
if (quickRecordElder.value) {
quickRecord.value.elder_id = quickRecordElder.value.id
}
}
const onQuickRecordTypeChange = (e: any): void => {
quickRecordTypeIndex.value = e.detail.value
if (quickRecordType.value) {
quickRecord.value.type = quickRecordType.value.value
}
}
const saveQuickRecord = async (): Promise<void> => {
if (!quickRecord.value.elder_id || !quickRecord.value.content.trim()) return
try {
const response = await supa.executeAs('insert', {
table: 'care_records',
data: {
elder_id: quickRecord.value.elder_id,
caregiver_id: getCurrentCaregiver(),
care_content: quickRecord.value.content,
status: 'completed'
}
})
if (response.success) {
hideQuickRecordModal()
}
} catch (error) {
console.error('保存快速记录失败:', error)
}
}
// Lifecycle
onMounted(async () => {
updateCurrentTime()
timeTimer = setInterval(updateCurrentTime, 60000) // 每分钟更新一次
await Promise.all([
loadTasks(),
loadStats(),
loadElders()
])
})
onUnmounted(() => {
if (timeTimer) {
clearInterval(timeTimer)
}
})
</script>
<style lang="scss">
.task-execution {
padding: 20px;
background: #f5f7fa;
min-height: 100vh;
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 12px;
color: white;
.header-title {
font-size: 24px;
font-weight: 600;
}
.header-info {
text-align: right;
.current-shift {
display: block;
font-size: 16px;
font-weight: 500;
margin-bottom: 4px;
}
.current-time {
font-size: 14px;
opacity: 0.9;
}
}
}
.summary-section {
display: flex;
gap: 16px;
margin-bottom: 24px;
flex-wrap: wrap;
.summary-card {
flex: 1;
min-width: 120px;
padding: 16px;
background: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
gap: 12px;
&.pending {
border-left: 4px solid #f59e0b;
}
&.progress {
border-left: 4px solid #3b82f6;
}
&.completed {
border-left: 4px solid #10b981;
}
&.overdue {
border-left: 4px solid #ef4444;
}
.summary-icon {
font-size: 24px;
}
.summary-content {
.summary-number {
display: block;
font-size: 24px;
font-weight: 700;
color: #1a202c;
margin-bottom: 2px;
}
.summary-label {
font-size: 12px;
color: #64748b;
}
}
}
}
.quick-actions {
display: flex;
gap: 12px;
margin-bottom: 24px;
flex-wrap: wrap;
.quick-btn {
flex: 1;
min-width: 100px;
padding: 16px;
background: white;
border: 2px solid #e5e7eb;
border-radius: 12px;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
&:hover {
border-color: #4a90e2;
background: #f8fafc;
}
.quick-icon {
font-size: 24px;
}
.quick-text {
font-size: 12px;
color: #374151;
font-weight: 500;
}
}
}
.filter-tabs {
display: flex;
gap: 12px;
margin-bottom: 24px;
background: white;
padding: 8px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
.filter-tab {
flex: 1;
padding: 12px 16px;
background: transparent;
border: none;
border-radius: 8px;
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
&.active {
background: #4a90e2;
.tab-text, .tab-count {
color: white;
}
}
.tab-text {
font-size: 14px;
font-weight: 500;
color: #374151;
}
.tab-count {
font-size: 12px;
color: #6b7280;
font-weight: 600;
}
}
}
.tasks-section {
background: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
.tasks-list {
padding: 16px;
.task-item {
padding: 16px;
border: 1px solid #e5e7eb;
border-radius: 12px;
margin-bottom: 12px;
background: white;
&.overdue {
border-left: 4px solid #ef4444;
background: #fef2f2;
}
&.priority-urgent {
border-left: 4px solid #dc2626;
}
&.priority-high {
border-left: 4px solid #f59e0b;
}
&.status-progress {
background: #f0f9ff;
border-color: #3b82f6;
}
&.status-completed {
background: #f6f6f6;
opacity: 0.8;
}
.task-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 12px;
.task-priority {
.priority-icon {
font-size: 20px;
}
}
.task-info {
flex: 1;
.task-name {
display: block;
font-size: 16px;
font-weight: 600;
color: #1a202c;
margin-bottom: 4px;
}
.elder-name {
font-size: 14px;
color: #6b7280;
}
}
.task-time {
text-align: right;
.scheduled-time {
display: block;
font-size: 14px;
font-weight: 500;
color: #374151;
margin-bottom: 4px;
}
.task-status {
font-size: 12px;
color: #6b7280;
}
}
}
.task-details {
margin-bottom: 12px;
.detail-row {
display: flex;
gap: 8px;
margin-bottom: 4px;
font-size: 14px;
.detail-label {
color: #6b7280;
min-width: 60px;
}
.detail-value {
color: #374151;
flex: 1;
}
}
}
.task-actions {
display: flex;
gap: 8px;
justify-content: flex-end;
.action-btn {
padding: 6px 12px;
border: none;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
&.primary {
background: #3b82f6;
color: white;
}
&.success {
background: #10b981;
color: white;
}
&.warning {
background: #f59e0b;
color: white;
}
&.info {
background: #6b7280;
color: white;
}
.btn-text {
color: inherit;
}
}
}
}
}
}
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
.modal-content {
background: white;
border-radius: 12px;
width: 90%;
max-width: 500px;
max-height: 80vh;
overflow-y: auto;
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
border-bottom: 1px solid #e5e7eb;
.modal-title {
font-size: 18px;
font-weight: 600;
color: #1a202c;
}
.close-btn {
padding: 4px;
background: none;
border: none;
font-size: 18px;
color: #6b7280;
}
}
.modal-body {
padding: 20px;
.task-summary {
padding: 16px;
background: #f8fafc;
border-radius: 8px;
margin-bottom: 20px;
.summary-row {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
.summary-label {
font-weight: 500;
color: #374151;
}
.summary-value {
color: #1a202c;
}
}
}
.task-description {
margin-bottom: 20px;
.desc-label {
display: block;
font-weight: 500;
color: #374151;
margin-bottom: 8px;
}
.desc-content {
color: #6b7280;
line-height: 1.5;
}
}
.execution-form, .form-group {
margin-bottom: 16px;
.form-label {
display: block;
font-size: 14px;
font-weight: 500;
color: #374151;
margin-bottom: 8px;
}
.form-textarea {
width: 100%;
padding: 10px 16px;
border: 1px solid #d1d5db;
border-radius: 8px;
font-size: 14px;
color: #374151;
height: 80px;
resize: vertical;
}
.picker-text {
padding: 10px 16px;
border: 1px solid #d1d5db;
border-radius: 8px;
background: white;
color: #374151;
width: 100%;
display: block;
}
}
}
.modal-footer {
display: flex;
gap: 12px;
justify-content: flex-end;
padding: 20px;
border-top: 1px solid #e5e7eb;
.cancel-btn, .confirm-btn {
padding: 10px 20px;
border: none;
border-radius: 8px;
font-size: 14px;
.btn-text {
color: inherit;
}
}
.cancel-btn {
background: #f3f4f6;
color: #374151;
}
.confirm-btn {
background: #4a90e2;
color: white;
}
}
}
}
}
</style>