feat(apps): establish shared mobile design system
This commit is contained in:
@@ -5,6 +5,7 @@ import 'package:uuid/uuid.dart';
|
||||
import '../../../app/dependencies.dart';
|
||||
import '../../../data/offline/encrypted_draft_store.dart';
|
||||
import '../../../data/repositories/service_repository.dart';
|
||||
import '../../core/widgets.dart';
|
||||
|
||||
class EvidencePage extends StatefulWidget {
|
||||
const EvidencePage({
|
||||
@@ -160,66 +161,108 @@ class _EvidencePageState extends State<EvidencePage> {
|
||||
@override
|
||||
Widget build(BuildContext context) => Scaffold(
|
||||
appBar: AppBar(title: const Text('现场取证')),
|
||||
body: ListView(
|
||||
padding: const EdgeInsets.all(18),
|
||||
children: [
|
||||
const Card(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(18),
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.fromLTRB(20, 12, 20, 32),
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(18),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.lock_outline),
|
||||
SizedBox(width: 12),
|
||||
Expanded(child: Text('照片与签名先按当前账号加密暂存;上传成功前仅显示“已暂存”。')),
|
||||
Icon(Icons.lock_outline, color: Theme.of(context).colorScheme.primary),
|
||||
const SizedBox(width: 12),
|
||||
const Expanded(child: Text('照片与签名先按当前账号加密暂存;上传成功前仅显示“已暂存”。')),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
..._requiredStages.map(
|
||||
(stage) => Card(
|
||||
child: ListTile(
|
||||
leading: Icon(
|
||||
_evidence.containsKey(stage) ? Icons.check_circle : Icons.camera_alt_outlined,
|
||||
color: _evidence.containsKey(stage) ? Colors.green : null,
|
||||
),
|
||||
title: Text(_stageName(stage)),
|
||||
subtitle: Text(_evidence.containsKey(stage) ? '已加密暂存' : '尚未采集'),
|
||||
trailing: TextButton(
|
||||
onPressed: _busy ? null : () => _capture(stage),
|
||||
child: Text(_evidence.containsKey(stage) ? '重拍' : '拍摄'),
|
||||
),
|
||||
const SizedBox(height: 28),
|
||||
SectionHeader(
|
||||
title: '取证进度',
|
||||
description: '已完成 ${_evidence.length}/${_requiredStages.length} 项必需材料',
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
LinearProgressIndicator(
|
||||
value: _requiredStages.isEmpty ? 0 : _evidence.length / _requiredStages.length,
|
||||
minHeight: 6,
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SurfaceSection(
|
||||
padding: EdgeInsets.zero,
|
||||
child: Column(
|
||||
children: [
|
||||
for (var index = 0; index < _requiredStages.length; index++) ...[
|
||||
ListTile(
|
||||
minTileHeight: 68,
|
||||
leading: Icon(
|
||||
_evidence.containsKey(_requiredStages[index])
|
||||
? Icons.check_circle_outline
|
||||
: Icons.camera_alt_outlined,
|
||||
color: _evidence.containsKey(_requiredStages[index])
|
||||
? Theme.of(context).colorScheme.secondary
|
||||
: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
title: Text(_stageName(_requiredStages[index])),
|
||||
subtitle: Text(
|
||||
_evidence.containsKey(_requiredStages[index]) ? '已加密暂存' : '尚未采集',
|
||||
),
|
||||
trailing: TextButton(
|
||||
onPressed: _busy ? null : () => _capture(_requiredStages[index]),
|
||||
child: Text(_evidence.containsKey(_requiredStages[index]) ? '重拍' : '拍摄'),
|
||||
),
|
||||
),
|
||||
if (index < _requiredStages.length - 1) const Divider(indent: 56),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: _result,
|
||||
maxLines: 4,
|
||||
onChanged: (_) => _save(),
|
||||
decoration: const InputDecoration(labelText: '现场结果说明'),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
DropdownButtonFormField<String>(
|
||||
initialValue: _conclusion,
|
||||
decoration: const InputDecoration(labelText: '结论'),
|
||||
items: const [
|
||||
DropdownMenuItem(value: 'qualified', child: Text('合格')),
|
||||
DropdownMenuItem(value: 'noncompliant', child: Text('不合格')),
|
||||
DropdownMenuItem(value: 'high_risk', child: Text('高风险')),
|
||||
],
|
||||
onChanged: (value) {
|
||||
if (value == null) return;
|
||||
setState(() => _conclusion = value);
|
||||
_save();
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 22),
|
||||
ElevatedButton(
|
||||
onPressed: _busy ? null : _submit,
|
||||
child: Text(_busy ? '正在上传并等待服务端确认…' : '在线提交结果'),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 28),
|
||||
const SectionHeader(title: '作业结论', description: '说明现场处理结果,并选择对应结论'),
|
||||
const SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: _result,
|
||||
maxLines: 4,
|
||||
minLines: 3,
|
||||
onChanged: (_) => _save(),
|
||||
decoration: const InputDecoration(
|
||||
labelText: '现场结果说明',
|
||||
helperText: '请填写处理过程、现场状态和后续建议',
|
||||
alignLabelWithHint: true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
DropdownButtonFormField<String>(
|
||||
initialValue: _conclusion,
|
||||
decoration: const InputDecoration(labelText: '结论'),
|
||||
items: const [
|
||||
DropdownMenuItem(value: 'qualified', child: Text('合格')),
|
||||
DropdownMenuItem(value: 'noncompliant', child: Text('不合格')),
|
||||
DropdownMenuItem(value: 'high_risk', child: Text('高风险')),
|
||||
],
|
||||
onChanged: (value) {
|
||||
if (value == null) return;
|
||||
setState(() => _conclusion = value);
|
||||
_save();
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 28),
|
||||
FilledButton.icon(
|
||||
onPressed: _busy ? null : _submit,
|
||||
icon: _busy
|
||||
? const SizedBox.square(
|
||||
dimension: 20,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
: const Icon(Icons.cloud_upload_outlined),
|
||||
label: Text(_busy ? '正在上传并等待服务端确认…' : '在线提交结果'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user