Files
akmon/pages/ec/incident/management.uvue
2026-01-20 08:04:15 +08:00

1109 lines
26 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 养老管理系统 - 事件报告管理 -->
<template>
<view class="incident-management">
<view class="header">
<text class="title">事件报告</text>
<button class="add-btn" @click="showAddIncident">新建报告</button>
</view>
<!-- 统计卡片 -->
<view class="stats-section">
<view class="stat-card">
<view class="stat-icon"></view>
<view class="stat-content">
<text class="stat-number">{{ stats.total_incidents }}</text>
<text class="stat-label">总事件数</text>
</view>
</view>
<view class="stat-card">
<view class="stat-icon"></view>
<view class="stat-content">
<text class="stat-number">{{ stats.high_severity }}</text>
<text class="stat-label">高严重性</text>
</view>
</view>
<view class="stat-card">
<view class="stat-icon">⏳</view>
<view class="stat-content">
<text class="stat-number">{{ stats.pending_incidents }}</text>
<text class="stat-label">待处理</text>
</view>
</view>
<view class="stat-card">
<view class="stat-icon">✅</view>
<view class="stat-content">
<text class="stat-number">{{ stats.resolved_incidents }}</text>
<text class="stat-label">已解决</text>
</view>
</view>
</view>
<!-- 筛选区域 -->
<view class="filter-section">
<view class="filter-item">
<text class="filter-label">老人:</text>
<picker-view class="picker" :value="selectedElderIndex" @change="onElderChange">
<picker-view-column>
<view v-for="(elder, index) in elderOptions" :key="elder.id" class="picker-item">
{{ elder.name }}
</view>
</picker-view-column>
</picker-view>
</view>
<view class="filter-item">
<text class="filter-label">类型:</text>
<picker-view class="picker" :value="selectedTypeIndex" @change="onTypeChange">
<picker-view-column>
<view v-for="(type, index) in typeOptions" :key="index" class="picker-item">
{{ type.label }}
</view>
</picker-view-column>
</picker-view>
</view>
<view class="filter-item">
<text class="filter-label">严重性:</text>
<picker-view class="picker" :value="selectedSeverityIndex" @change="onSeverityChange">
<picker-view-column>
<view v-for="(severity, index) in severityOptions" :key="index" class="picker-item">
{{ severity.label }}
</view>
</picker-view-column>
</picker-view>
</view>
<view class="filter-item">
<text class="filter-label">状态:</text>
<picker-view class="picker" :value="selectedStatusIndex" @change="onStatusChange">
<picker-view-column>
<view v-for="(status, index) in statusOptions" :key="index" class="picker-item">
{{ status.label }}
</view>
</picker-view-column>
</picker-view>
</view>
<button class="search-btn" @click="searchIncidents">搜索</button>
</view>
<!-- 事件列表 -->
<view class="incidents-list">
<view v-for="incident in incidents" :key="incident.id" class="incident-item" @click="viewIncidentDetail(incident)">
<view class="incident-header">
<text class="incident-title">{{ incident.title }}</text>
<view class="severity-badge" :class="getSeverityClass(incident.severity)">
<text class="severity-text">{{ getSeverityText(incident.severity) }}</text>
</view>
</view>
<view class="incident-info">
<text class="elder-name">{{ getElderName(incident.elder_id) }}</text>
<text class="incident-type">类型: {{ getTypeText(incident.incident_type) }}</text>
<text class="incident-location">地点: {{ incident.location ?? '未记录' }}</text>
</view>
<view class="incident-time">
<text class="time-text">发生时间: {{ formatDateTime(incident.incident_time) }}</text>
<text class="time-text">报告时间: {{ formatDateTime(incident.created_at) }}</text>
</view>
<view class="incident-description">
<text class="description-text">{{ incident.description ?? '无描述' }}</text>
</view>
<view class="incident-status">
<view class="status-badge" :class="getStatusClass(incident.status)">
<text class="status-text">{{ getStatusText(incident.status) }}</text>
</view>
<text class="follow-up" v-if="incident.follow_up_required">需要跟进</text>
</view>
<view class="incident-actions">
<button class="action-btn edit-btn" @click.stop="editIncident(incident)">编辑</button>
<button class="action-btn resolve-btn" v-if="incident.status !== 'resolved'" @click.stop="resolveIncident(incident)">解决</button>
<button class="action-btn report-btn" @click.stop="generateReport(incident)">生成报告</button>
</view>
</view>
</view>
<!-- 添加/编辑事件弹窗 -->
<view v-if="showIncidentModal" class="modal-overlay" @click="closeIncidentModal">
<view class="modal-content" @click.stop="">
<view class="modal-header">
<text class="modal-title">{{ isEditMode ? '编辑事件' : '新建事件报告' }}</text>
<button class="close-btn" @click="closeIncidentModal">×</button>
</view>
<view class="modal-body">
<view class="form-group">
<text class="form-label">老人:</text>
<picker-view class="form-picker" :value="formData.elderIndex" @change="onFormElderChange">
<picker-view-column>
<view v-for="(elder, index) in elderOptions" :key="elder.id" class="picker-item">
{{ elder.name }}
</view>
</picker-view-column>
</picker-view>
</view>
<view class="form-group">
<text class="form-label">事件标题:</text>
<input class="form-input" v-model="formData.title" placeholder="请输入事件标题" />
</view>
<view class="form-group">
<text class="form-label">事件类型:</text>
<picker-view class="form-picker" :value="formData.typeIndex" @change="onFormTypeChange">
<picker-view-column>
<view v-for="(type, index) in incidentTypes" :key="index" class="picker-item">
{{ type.label }}
</view>
</picker-view-column>
</picker-view>
</view>
<view class="form-group">
<text class="form-label">严重性:</text>
<picker-view class="form-picker" :value="formData.severityIndex" @change="onFormSeverityChange">
<picker-view-column>
<view v-for="(severity, index) in incidentSeverities" :key="index" class="picker-item">
{{ severity.label }}
</view>
</picker-view-column>
</picker-view>
</view>
<view class="form-group">
<text class="form-label">发生地点:</text>
<input class="form-input" v-model="formData.location" placeholder="请输入发生地点" />
</view>
<view class="form-group">
<text class="form-label">发生时间:</text>
<view class="datetime-row">
<lime-date-time-picker v-model="formData.incident_date" type="date" :placeholder="'选择事件日期'" />
<lime-date-time-picker v-model="formData.incident_time" type="time" :placeholder="'选择事件时间'" />
</view>
</view>
<view class="form-group">
<text class="form-label">事件描述:</text>
<textarea class="form-textarea" v-model="formData.description" placeholder="请详细描述事件经过"></textarea>
</view>
<view class="form-group">
<text class="form-label">已采取措施:</text>
<textarea class="form-textarea" v-model="formData.actions_taken" placeholder="请描述已采取的措施"></textarea>
</view>
<view class="form-group">
<text class="form-label">见证人:</text>
<input class="form-input" v-model="formData.witnesses" placeholder="请输入见证人姓名,多人用逗号分隔" />
</view>
<view class="form-group">
<view class="checkbox-item">
<input type="checkbox" v-model="formData.follow_up_required" />
<text class="checkbox-label">需要后续跟进</text>
</view>
</view>
</view>
<view class="modal-footer">
<button class="cancel-btn" @click="closeIncidentModal">取消</button>
<button class="save-btn" @click="saveIncident">保存</button>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref, onMounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import type { Incident, Elder } from '../types.uts'
import { formatDateTime, getSeverityClass, getStatusClass } from '../types.uts'
import supa from '@/components/supadb/aksupainstance.uts'
// 统计数据类型
type IncidentStats = {
total_incidents: number
high_severity: number
pending_incidents: number
resolved_incidents: number
}
// 响应式数据
const incidents = ref<Incident[]>([])
const elderOptions = ref<Elder[]>([])
const eldersMap = ref<Map<string, string>>(new Map())
const stats = ref<IncidentStats>({
total_incidents: 0,
high_severity: 0,
pending_incidents: 0,
resolved_incidents: 0
})
// 筛选相关
const selectedElderIndex = ref([0])
const selectedTypeIndex = ref([0])
const selectedSeverityIndex = ref([0])
const selectedStatusIndex = ref([0])
const typeOptions = [
{ value: 'all', label: '全部类型' },
{ value: 'fall', label: '跌倒' },
{ value: 'medical', label: '医疗事件' },
{ value: 'behavior', label: '行为事件' },
{ value: 'medication', label: '用药事件' },
{ value: 'equipment', label: '设备故障' },
{ value: 'other', label: '其他事件' }
]
const severityOptions = [
{ value: 'all', label: '全部级别' },
{ value: 'low', label: '低' },
{ value: 'medium', label: '中' },
{ value: 'high', label: '高' },
{ value: 'critical', label: '紧急' }
]
const statusOptions = [
{ value: 'all', label: '全部状态' },
{ value: 'reported', label: '已报告' },
{ value: 'investigating', label: '调查中' },
{ value: 'resolved', label: '已解决' },
{ value: 'closed', label: '已关闭' }
]
const incidentTypes = [
{ value: 'fall', label: '跌倒' },
{ value: 'medical', label: '医疗事件' },
{ value: 'behavior', label: '行为事件' },
{ value: 'medication', label: '用药事件' },
{ value: 'equipment', label: '设备故障' },
{ value: 'other', label: '其他事件' }
]
const incidentSeverities = [
{ value: 'low', label: '低' },
{ value: 'medium', label: '中' },
{ value: 'high', label: '高' },
{ value: 'critical', label: '紧急' }
]
// 弹窗相关
const showIncidentModal = ref(false)
const isEditMode = ref(false)
const currentIncidentId = ref<string | null>(null)
// 表单数据
const formData = ref({
elderIndex: [0],
title: '',
typeIndex: [0],
severityIndex: [0],
location: '',
incident_date: '',
incident_time: '',
description: '',
actions_taken: '',
witnesses: '',
follow_up_required: false
})
// 页面加载
onLoad(() => {
loadData()
})
// 加载数据
async function loadData(): Promise<void> {
try {
await Promise.all([
loadElders(),
loadIncidents(),
loadStats()
])
} catch (error) {
console.error('加载数据失败:', error)
uni.showToast({
title: '加载数据失败',
icon: 'error'
})
}
}
// 加载老人列表
async function loadElders(): Promise<void> {
const result = await supa.executeAs<Elder>('eldercare_admin', `
SELECT id, name FROM ec_elders
WHERE status = 'active'
ORDER BY name
`)
elderOptions.value = [{ id: '', name: '全部老人' } as Elder, ...result]
// 建立映射
const map = new Map<string, string>()
for (let i: Int = 0; i < result.length; i++) {
const elder = result[i]
map.set(elder.id, elder.name)
}
eldersMap.value = map
}
// 加载事件列表
async function loadIncidents(): Promise<void> {
let whereClause = "WHERE 1=1"
// 老人筛选
if (selectedElderIndex.value[0] > 0) {
const selectedElder = elderOptions.value[selectedElderIndex.value[0]]
whereClause += ` AND elder_id = '${selectedElder.id}'`
}
// 类型筛选
if (selectedTypeIndex.value[0] > 0) {
const selectedType = typeOptions[selectedTypeIndex.value[0]]
whereClause += ` AND incident_type = '${selectedType.value}'`
}
// 严重性筛选
if (selectedSeverityIndex.value[0] > 0) {
const selectedSeverity = severityOptions[selectedSeverityIndex.value[0]]
whereClause += ` AND severity = '${selectedSeverity.value}'`
}
// 状态筛选
if (selectedStatusIndex.value[0] > 0) {
const selectedStatus = statusOptions[selectedStatusIndex.value[0]]
whereClause += ` AND status = '${selectedStatus.value}'`
}
const result = await supa.executeAs<Incident>('eldercare_admin', `
SELECT * FROM ec_incidents
${whereClause}
ORDER BY incident_time DESC, created_at DESC
`)
incidents.value = result
}
// 加载统计数据
async function loadStats(): Promise<void> {
const result = await supa.executeAs<IncidentStats>('eldercare_admin', `
SELECT
COUNT(*) as total_incidents,
COUNT(CASE WHEN severity IN ('high', 'critical') THEN 1 END) as high_severity,
COUNT(CASE WHEN status IN ('reported', 'investigating') THEN 1 END) as pending_incidents,
COUNT(CASE WHEN status = 'resolved' THEN 1 END) as resolved_incidents
FROM ec_incidents
`)
if (result.length > 0) {
stats.value = result[0]
}
}
// 获取老人姓名
function getElderName(elderId: string): string {
return eldersMap.value.get(elderId) ?? '未知老人'
}
// 获取类型文本
function getTypeText(type: string): string {
const typeMap: Record<string, string> = {
'fall': '跌倒',
'medical': '医疗事件',
'behavior': '行为事件',
'medication': '用药事件',
'equipment': '设备故障',
'other': '其他事件'
}
return typeMap[type] ?? type
}
// 获取严重性文本
function getSeverityText(severity: string): string {
const severityMap: Record<string, string> = {
'low': '低',
'medium': '中',
'high': '高',
'critical': '紧急'
}
return severityMap[severity] ?? severity
}
// 获取状态文本
function getStatusText(status: string): string {
const statusMap: Record<string, string> = {
'reported': '已报告',
'investigating': '调查中',
'resolved': '已解决',
'closed': '已关闭'
}
return statusMap[status] ?? status
}
// 格式化日期
function formatDate(dateStr: string | null): string {
if (dateStr === null || dateStr === '') return ''
const date = new Date(dateStr)
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const day = date.getDate().toString().padStart(2, '0')
return `${year}-${month}-${day}`
}
// 筛选事件
function onElderChange(e: any): void {
selectedElderIndex.value = e.detail.value
}
function onTypeChange(e: any): void {
selectedTypeIndex.value = e.detail.value
}
function onSeverityChange(e: any): void {
selectedSeverityIndex.value = e.detail.value
}
function onStatusChange(e: any): void {
selectedStatusIndex.value = e.detail.value
}
// 搜索事件
function searchIncidents(): void {
loadIncidents()
loadStats()
}
// 查看事件详情
function viewIncidentDetail(incident: Incident): void {
uni.navigateTo({
url: `/pages/ec/incident/detail?id=${incident.id}`
})
}
// 编辑事件
function editIncident(incident: Incident): void {
isEditMode.value = true
currentIncidentId.value = incident.id
// 填充表单数据
const elderIndex = elderOptions.value.findIndex(elder => elder.id === incident.elder_id)
const typeIndex = incidentTypes.findIndex(type => type.value === incident.incident_type)
const severityIndex = incidentSeverities.findIndex(severity => severity.value === incident.severity)
const incidentDateTime = incident.incident_time ? new Date(incident.incident_time) : new Date()
formData.value = {
elderIndex: [elderIndex > 0 ? elderIndex : 0],
title: incident.title,
typeIndex: [typeIndex > 0 ? typeIndex : 0],
severityIndex: [severityIndex > 0 ? severityIndex : 0],
location: incident.location ?? '',
incident_date: formatDate(incidentDateTime.toISOString()),
incident_time: incidentDateTime.getHours().toString().padStart(2, '0') + ':' + incidentDateTime.getMinutes().toString().padStart(2, '0'),
description: incident.description ?? '',
actions_taken: incident.actions_taken ?? '',
witnesses: incident.witnesses?.join(', ') ?? '',
follow_up_required: incident.follow_up_required
}
showIncidentModal.value = true
}
// 解决事件
async function resolveIncident(incident: Incident): Promise<void> {
uni.showModal({
title: '确认解决',
content: '确定标记此事件为已解决吗?',
success: async (res) => {
if (res.confirm) {
try {
await supa.executeAs('eldercare_admin', `
UPDATE ec_incidents
SET status = 'resolved', resolved_at = NOW(), updated_at = NOW()
WHERE id = '${incident.id}'
`)
uni.showToast({
title: '解决成功',
icon: 'success'
})
loadIncidents()
loadStats()
} catch (error) {
console.error('解决事件失败:', error)
uni.showToast({
title: '操作失败',
icon: 'error'
})
}
}
}
})
}
// 生成报告
function generateReport(incident: Incident): void {
uni.navigateTo({
url: `/pages/ec/incident/report?id=${incident.id}`
})
}
// 显示添加事件弹窗
function showAddIncident(): void {
isEditMode.value = false
currentIncidentId.value = null
// 重置表单
const now = new Date()
const today = formatDate(now.toISOString())
const currentTime = now.getHours().toString().padStart(2, '0') + ':' + now.getMinutes().toString().padStart(2, '0')
formData.value = {
elderIndex: [0],
title: '',
typeIndex: [0],
severityIndex: [0],
location: '',
incident_date: today,
incident_time: currentTime,
description: '',
actions_taken: '',
witnesses: '',
follow_up_required: false
}
showIncidentModal.value = true
}
// 关闭弹窗
function closeIncidentModal(): void {
showIncidentModal.value = false
}
// 表单事件
function onFormElderChange(e: any): void {
formData.value.elderIndex = e.detail.value
}
function onFormTypeChange(e: any): void {
formData.value.typeIndex = e.detail.value
}
function onFormSeverityChange(e: any): void {
formData.value.severityIndex = e.detail.value
}
function onIncidentDateChange(date: string): void {
formData.value.incident_date = date
}
function onIncidentTimeChange(time: string): void {
formData.value.incident_time = time
}
// 保存事件
async function saveIncident(): Promise<void> {
// 验证表单
if (formData.value.elderIndex[0] === 0) {
uni.showToast({
title: '请选择老人',
icon: 'error'
})
return
}
if (formData.value.title.trim() === '') {
uni.showToast({
title: '请输入事件标题',
icon: 'error'
})
return
}
try {
const selectedElder = elderOptions.value[formData.value.elderIndex[0]]
const selectedType = incidentTypes[formData.value.typeIndex[0]]
const selectedSeverity = incidentSeverities[formData.value.severityIndex[0]]
const incidentDateTime = `${formData.value.incident_date} ${formData.value.incident_time}:00`
const witnessesArray = formData.value.witnesses.split(',').map(w => w.trim()).filter(w => w !== '')
if (isEditMode.value && currentIncidentId.value !== null) {
// 更新事件
await supa.executeAs('eldercare_admin', `
UPDATE ec_incidents SET
elder_id = '${selectedElder.id}',
title = '${formData.value.title}',
incident_type = '${selectedType.value}',
severity = '${selectedSeverity.value}',
location = '${formData.value.location}',
incident_time = '${incidentDateTime}',
description = '${formData.value.description}',
actions_taken = '${formData.value.actions_taken}',
witnesses = '${JSON.stringify(witnessesArray)}',
follow_up_required = ${formData.value.follow_up_required},
updated_at = NOW()
WHERE id = '${currentIncidentId.value}'
`)
} else {
// 新增事件
await supa.executeAs('eldercare_admin', `
INSERT INTO ec_incidents (
elder_id, title, incident_type, severity, location,
incident_time, description, actions_taken, witnesses,
follow_up_required, status
) VALUES (
'${selectedElder.id}',
'${formData.value.title}',
'${selectedType.value}',
'${selectedSeverity.value}',
'${formData.value.location}',
'${incidentDateTime}',
'${formData.value.description}',
'${formData.value.actions_taken}',
'${JSON.stringify(witnessesArray)}',
${formData.value.follow_up_required},
'reported'
)
`)
}
uni.showToast({
title: '保存成功',
icon: 'success'
})
closeIncidentModal()
loadIncidents()
loadStats()
} catch (error) {
console.error('保存失败:', error)
uni.showToast({
title: '保存失败',
icon: 'error'
})
}
}
</script>
<style scoped>
.incident-management {
padding: 20px;
background-color: #f5f5f5;
min-height: 100vh;
}
.header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.title {
font-size: 24px;
font-weight: bold;
color: #333;
}
.add-btn {
background-color: #2196f3;
color: white;
border: none;
border-radius: 6px;
padding: 10px 20px;
font-size: 14px;
}
.stats-section {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-bottom: 20px;
}
.stat-card {
flex: 1;
min-width: 200px;
background-color: white;
border-radius: 12px;
padding: 20px;
margin: 5px;
display: flex;
flex-direction: row;
align-items: center;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.stat-icon {
font-size: 32px;
margin-right: 15px;
}
.stat-content {
flex: 1;
}
.stat-number {
font-size: 24px;
font-weight: bold;
color: #333;
display: block;
}
.stat-label {
font-size: 14px;
color: #666;
margin-top: 5px;
}
.filter-section {
background-color: white;
border-radius: 12px;
padding: 20px;
margin-bottom: 20px;
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: wrap;
}
.filter-item {
display: flex;
flex-direction: row;
align-items: center;
margin-right: 20px;
margin-bottom: 10px;
}
.filter-label {
font-size: 14px;
color: #666;
margin-right: 10px;
}
.picker {
width: 120px;
height: 40px;
border: 1px solid #ddd;
border-radius: 6px;
}
.picker-item {
padding: 10px;
text-align: center;
font-size: 14px;
}
.search-btn {
background-color: #4caf50;
color: white;
border: none;
border-radius: 6px;
padding: 10px 20px;
font-size: 14px;
}
.incidents-list {
background-color: white;
border-radius: 12px;
padding: 20px;
}
.incident-item {
padding: 15px 0;
border-bottom: 1px solid #f0f0f0;
}
.incident-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.incident-title {
font-size: 18px;
font-weight: bold;
color: #333;
}
.severity-badge {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
}
.severity-text {
color: white;
}
.severity-low {
background-color: #4caf50;
}
.severity-medium {
background-color: #ff9800;
}
.severity-high {
background-color: #f44336;
}
.severity-critical {
background-color: #d32f2f;
}
.incident-info, .incident-time, .incident-description, .incident-status {
margin-bottom: 10px;
}
.elder-name, .incident-type, .incident-location, .time-text, .description-text {
font-size: 14px;
color: #666;
margin-bottom: 5px;
}
.description-text {
line-height: 1.4;
}
.incident-status {
display: flex;
flex-direction: row;
align-items: center;
}
.status-badge {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
margin-right: 10px;
}
.status-text {
color: white;
}
.status-reported {
background-color: #ff9800;
}
.status-investigating {
background-color: #2196f3;
}
.status-resolved {
background-color: #4caf50;
}
.status-closed {
background-color: #9e9e9e;
}
.follow-up {
font-size: 12px;
color: #f44336;
background-color: #ffebee;
padding: 2px 6px;
border-radius: 4px;
}
.incident-actions {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.action-btn {
border: none;
border-radius: 4px;
padding: 6px 12px;
font-size: 12px;
margin-right: 10px;
margin-bottom: 5px;
}
.edit-btn {
background-color: #ff9800;
color: white;
}
.resolve-btn {
background-color: #4caf50;
color: white;
}
.report-btn {
background-color: #2196f3;
color: white;
}
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-content {
background-color: white;
border-radius: 12px;
width: 90%;
max-width: 600px;
max-height: 80%;
}
.modal-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 20px;
border-bottom: 1px solid #f0f0f0;
}
.modal-title {
font-size: 18px;
font-weight: bold;
color: #333;
}
.close-btn {
background: none;
border: none;
font-size: 24px;
color: #999;
}
.modal-body {
padding: 20px;
max-height: 500px;
overflow-y: auto;
}
.form-group {
margin-bottom: 20px;
}
.form-label {
font-size: 14px;
color: #333;
margin-bottom: 8px;
display: block;
}
.form-input {
width: 100%;
height: 40px;
border: 1px solid #ddd;
border-radius: 6px;
padding: 0 12px;
font-size: 14px;
}
.form-picker {
width: 100%;
height: 40px;
border: 1px solid #ddd;
border-radius: 6px;
}
.form-textarea {
width: 100%;
height: 80px;
border: 1px solid #ddd;
border-radius: 6px;
padding: 12px;
font-size: 14px;
}
.datetime-row {
display: flex;
flex-direction: row;
}
.date-input, .time-input {
flex: 1;
margin-right: 10px;
}
.time-input {
margin-right: 0;
}
.checkbox-item {
display: flex;
flex-direction: row;
align-items: center;
}
.checkbox-label {
margin-left: 8px;
font-size: 14px;
color: #333;
}
.modal-footer {
display: flex;
flex-direction: row;
justify-content: flex-end;
padding: 20px;
border-top: 1px solid #f0f0f0;
}
.cancel-btn, .save-btn {
border: none;
border-radius: 6px;
padding: 10px 20px;
font-size: 14px;
margin-left: 10px;
}
.cancel-btn {
background-color: #f5f5f5;
color: #666;
}
.save-btn {
background-color: #2196f3;
color: white;
}
/* 小屏幕适配 */
@media (max-width: 768px) {
.incident-management {
padding: 15px;
}
.stats-section {
flex-direction: column;
}
.stat-card {
margin: 5px 0;
min-width: auto;
}
.filter-section {
flex-direction: column;
align-items: stretch;
}
.filter-item {
margin-right: 0;
justify-content: space-between;
}
.picker {
width: 150px;
}
.modal-content {
width: 95%;
}
.datetime-row {
flex-direction: column;
}
.date-input, .time-input {
margin-right: 0;
margin-bottom: 10px;
}
}
</style>