feat: add Flutter schema-driven form cards

This commit is contained in:
selfrelease
2026-07-18 09:13:27 +08:00
parent e13b6c7778
commit 2105fe3bac
85 changed files with 3141 additions and 3 deletions
+17
View File
@@ -0,0 +1,17 @@
import 'package:aioa_mobile/app/router.dart';
import 'package:aioa_mobile/app/theme.dart';
import 'package:flutter/material.dart';
class AioaApp extends StatelessWidget {
const AioaApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp.router(
title: 'AIOA',
debugShowCheckedModeBanner: false,
theme: buildAioaTheme(),
routerConfig: appRouter,
);
}
}
+31
View File
@@ -0,0 +1,31 @@
import 'package:aioa_mobile/app/shell.dart';
import 'package:aioa_mobile/features/assistant/presentation/assistant_page.dart';
import 'package:aioa_mobile/features/form/presentation/leave_form_page.dart';
import 'package:aioa_mobile/features/profile/presentation/profile_page.dart';
import 'package:aioa_mobile/features/tasks/presentation/tasks_page.dart';
import 'package:aioa_mobile/features/workspace/presentation/workspace_page.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
final appRouter = GoRouter(
initialLocation: '/workspace',
routes: [
ShellRoute(
builder: (context, state, child) =>
AioaShell(location: state.uri.path, child: child),
routes: [
GoRoute(path: '/workspace', builder: (_, _) => const WorkspacePage()),
GoRoute(path: '/assistant', builder: (_, _) => const AssistantPage()),
GoRoute(path: '/tasks', builder: (_, _) => const TasksPage()),
GoRoute(path: '/profile', builder: (_, _) => const ProfilePage()),
],
),
GoRoute(
path: '/leave/new',
pageBuilder: (context, state) => MaterialPage<void>(
fullscreenDialog: true,
child: const LeaveFormPage(),
),
),
],
);
+47
View File
@@ -0,0 +1,47 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class AioaShell extends StatelessWidget {
const AioaShell({super.key, required this.location, required this.child});
final String location;
final Widget child;
@override
Widget build(BuildContext context) {
final index = switch (location) {
String path when path.startsWith('/assistant') => 1,
String path when path.startsWith('/tasks') => 2,
String path when path.startsWith('/profile') => 3,
_ => 0,
};
return Scaffold(
body: SafeArea(child: child),
bottomNavigationBar: NavigationBar(
selectedIndex: index,
onDestinationSelected: (value) {
const paths = ['/workspace', '/assistant', '/tasks', '/profile'];
context.go(paths[value]);
},
destinations: const [
NavigationDestination(
icon: Icon(Icons.grid_view_rounded),
label: '工作台',
),
NavigationDestination(
icon: Icon(Icons.auto_awesome_rounded),
label: 'AI 助手',
),
NavigationDestination(
icon: Icon(Icons.task_alt_rounded),
label: '待办',
),
NavigationDestination(
icon: Icon(Icons.person_outline_rounded),
label: '我的',
),
],
),
);
}
}
+36
View File
@@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
ThemeData buildAioaTheme() {
const seed = Color(0xFF3157D5);
final scheme = ColorScheme.fromSeed(
seedColor: seed,
brightness: Brightness.light,
surface: const Color(0xFFF7F8FC),
);
return ThemeData(
colorScheme: scheme,
useMaterial3: true,
scaffoldBackgroundColor: scheme.surface,
cardTheme: const CardThemeData(
elevation: 0,
margin: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
side: BorderSide(color: Color(0xFFE6E8F0)),
),
),
inputDecorationTheme: const InputDecorationTheme(
filled: true,
fillColor: Colors.white,
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(14)),
borderSide: BorderSide(color: Color(0xFFDDE1EA)),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(14)),
borderSide: BorderSide(color: Color(0xFFDDE1EA)),
),
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 14),
),
);
}