finish 123
This commit is contained in:
parent
2bcc22bfe1
commit
0ea11b60fc
@ -1,7 +1,13 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:model_of_the_times/entities/ViewInformation.dart';
|
import 'package:model_of_the_times/entities/ViewInformation.dart';
|
||||||
import 'package:model_of_the_times/icons/material_design_icons.dart';
|
import 'package:model_of_the_times/icons/material_design_icons.dart';
|
||||||
|
import 'package:model_of_the_times/requester/requester.dart';
|
||||||
|
import 'package:model_of_the_times/views/activity.dart';
|
||||||
|
import 'package:model_of_the_times/views/common/data_required.dart';
|
||||||
import 'package:model_of_the_times/views/home.dart';
|
import 'package:model_of_the_times/views/home.dart';
|
||||||
|
import 'package:model_of_the_times/views/learned.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
@ -16,10 +22,19 @@ class MyApp extends StatelessWidget {
|
|||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: '时代楷模',
|
title: '时代楷模',
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.white),
|
colorScheme: ColorScheme.fromSeed(seedColor: Colors.red, surface: Colors.white),
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
),
|
),
|
||||||
home: const MainPage(),
|
home: DataRequired(
|
||||||
|
fetchData: (global) async {
|
||||||
|
var data = await global.requester.post(resolve("/app/login"), body: jsonEncode({'username': 'WUvFG3gY','password': 'ZogPgBF6'}));
|
||||||
|
return jsonFromResponse(data);
|
||||||
|
},
|
||||||
|
afterLoading: (data){
|
||||||
|
GlobalInformation.getInstance().token = data['token'];
|
||||||
|
return const MainPage();
|
||||||
|
}
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -34,7 +49,9 @@ class MainPage extends StatefulWidget {
|
|||||||
class _MainPageState extends State<MainPage> {
|
class _MainPageState extends State<MainPage> {
|
||||||
int _nowPageIndex = 0;
|
int _nowPageIndex = 0;
|
||||||
final List<ViewInformation> _pages = [
|
final List<ViewInformation> _pages = [
|
||||||
ViewInformation(const HomeView(), "时代楷模")
|
ViewInformation(const HomeView(), "时代楷模"),
|
||||||
|
ViewInformation(const Activity(), "公益活动"),
|
||||||
|
ViewInformation(const Learned(), "学习心得")
|
||||||
];
|
];
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -52,10 +69,14 @@ class _MainPageState extends State<MainPage> {
|
|||||||
body: page.view,
|
body: page.view,
|
||||||
bottomNavigationBar: BottomNavigationBar(
|
bottomNavigationBar: BottomNavigationBar(
|
||||||
onTap: (newIndex){
|
onTap: (newIndex){
|
||||||
|
if (newIndex >= _pages.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
_nowPageIndex = newIndex;
|
_nowPageIndex = newIndex;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
currentIndex: _nowPageIndex,
|
||||||
type: BottomNavigationBarType.fixed,
|
type: BottomNavigationBarType.fixed,
|
||||||
items: const [
|
items: const [
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
@ -64,7 +85,7 @@ class _MainPageState extends State<MainPage> {
|
|||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(MaterialDesign.feedback),
|
icon: Icon(MaterialDesign.feedback),
|
||||||
label: "公告"
|
label: "公益"
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(MaterialDesign.favorite),
|
icon: Icon(MaterialDesign.favorite),
|
||||||
|
@ -10,7 +10,7 @@ class CustomRequesterClient extends BaseClient {
|
|||||||
if (information.token.isNotEmpty){
|
if (information.token.isNotEmpty){
|
||||||
request.headers.addAll({"Authorization": information.token});
|
request.headers.addAll({"Authorization": information.token});
|
||||||
}
|
}
|
||||||
if (request.headers.containsKey("Content-Type")){
|
if (request.headers['Content-Type'] == 'text/plain; charset=utf-8'){
|
||||||
request.headers['Content-Type'] = "application/json";
|
request.headers['Content-Type'] = "application/json";
|
||||||
}
|
}
|
||||||
return client.send(request);
|
return client.send(request);
|
||||||
@ -37,3 +37,7 @@ dynamic jsonFromResponse(Response response) {
|
|||||||
var str = utf8.decode(response.bodyBytes);
|
var str = utf8.decode(response.bodyBytes);
|
||||||
return jsonDecode(str);
|
return jsonDecode(str);
|
||||||
}
|
}
|
||||||
|
dynamic jsonFromStreamResponse(StreamedResponse response) async {
|
||||||
|
var str = utf8.decode(await response.stream.toBytes());
|
||||||
|
return jsonDecode(str);
|
||||||
|
}
|
5
lib/utils/toast.dart
Normal file
5
lib/utils/toast.dart
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
void toast(String message, BuildContext context){
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message)));
|
||||||
|
}
|
196
lib/views/activity.dart
Normal file
196
lib/views/activity.dart
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:model_of_the_times/requester/requester.dart';
|
||||||
|
import 'package:model_of_the_times/utils/toast.dart';
|
||||||
|
import 'package:model_of_the_times/views/common/data_required.dart';
|
||||||
|
import 'package:model_of_the_times/views/common/full_paged_struct.dart';
|
||||||
|
|
||||||
|
class ActivityCard extends StatefulWidget {
|
||||||
|
final String picPath;
|
||||||
|
final int id;
|
||||||
|
final String startDate;
|
||||||
|
final String endDate;
|
||||||
|
final int status;
|
||||||
|
final String title;
|
||||||
|
final String content;
|
||||||
|
final String sponsor;
|
||||||
|
final int signUpNum;
|
||||||
|
const ActivityCard({super.key, required this.picPath, required this.id, required this.startDate, required this.endDate, required this.status, required this.title, required this.content, required this.sponsor, required this.signUpNum});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ActivityCard> createState() => _ActivityCardState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ActivityCardState extends State<ActivityCard> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Card(
|
||||||
|
child: Padding(padding: const EdgeInsets.all(10), child: Column(
|
||||||
|
children: [
|
||||||
|
Image.network(resolve(widget.picPath).toString(), height: 100, fit: BoxFit.fitHeight),
|
||||||
|
ListTile(
|
||||||
|
title: Text(widget.title),
|
||||||
|
subtitle: Column(
|
||||||
|
children: [
|
||||||
|
Text("活动时间:${widget.startDate} - ${widget.endDate}"),
|
||||||
|
Text("发起方:${widget.sponsor}"),
|
||||||
|
Text("简介:${widget.content}", maxLines: 1, overflow: TextOverflow.ellipsis)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
Flex(
|
||||||
|
direction: Axis.horizontal,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Flex(
|
||||||
|
direction: Axis.horizontal,
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.add),
|
||||||
|
Text("已报名${widget.signUpNum}人")
|
||||||
|
],
|
||||||
|
),
|
||||||
|
OutlinedButton(onPressed: (){
|
||||||
|
if (widget.status == 1) {
|
||||||
|
Navigator.push(context, MaterialPageRoute(builder: (context) => ActivityDetails(id: widget.id)));
|
||||||
|
}
|
||||||
|
}, child: Text(widget.status == 1 ? "去报名" : widget.status == 2 ? "报名截止" : "已报名"))
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Activity extends StatefulWidget {
|
||||||
|
const Activity({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<Activity> createState() => _ActivityState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ActivityState extends State<Activity> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return DataRequired(
|
||||||
|
fetchData: (global) async {
|
||||||
|
var req = global.requester;
|
||||||
|
var response = await req.get(resolve("/activity/app-o/list"));
|
||||||
|
return jsonFromResponse(response);
|
||||||
|
},
|
||||||
|
afterLoading: (data) {
|
||||||
|
if (kDebugMode) {
|
||||||
|
print(data);
|
||||||
|
}
|
||||||
|
data['rows'].sort((a,b){return (a['status'] - b['status'] )as int;});
|
||||||
|
return ListView(
|
||||||
|
children: data['rows'].map<Widget>((e) {
|
||||||
|
return Container(
|
||||||
|
margin: const EdgeInsets.only(top: 10),
|
||||||
|
child: ActivityCard(picPath: e['picPath'], id: e['id'], startDate: e['startDate'], endDate: e['endDate'], status: e['status'], title: e['title'], content: e['content'], sponsor: e['sponsor'], signUpNum: e['signUpNum']),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ActivityDetails extends StatefulWidget {
|
||||||
|
final int id;
|
||||||
|
const ActivityDetails({super.key, required this.id});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ActivityDetails> createState() => _ActivityDetailsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ActivityDetailsState extends State<ActivityDetails> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return FullPagedStruct(
|
||||||
|
title: "活动详情",
|
||||||
|
child: DataRequired(
|
||||||
|
fetchData: (global) async {
|
||||||
|
return jsonFromResponse(await global.requester.get(resolve("/activity/app-o/detail?id=${widget.id}")));
|
||||||
|
},
|
||||||
|
afterLoading: (data) {
|
||||||
|
data = data['data'];
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
ListView(
|
||||||
|
children: [
|
||||||
|
Image.network(resolve(data['picPath']).toString()),
|
||||||
|
ListTile(
|
||||||
|
title: Text(data['title']),
|
||||||
|
subtitle: Column(
|
||||||
|
children: [
|
||||||
|
Text("活动时间:${data['startDate']} - ${data['endDate']}"),
|
||||||
|
Text("报名截止时间:${data['signUpEndDate']}"),
|
||||||
|
Text("发起方:${data['sponsor']}"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
Flex(
|
||||||
|
direction: Axis.vertical,
|
||||||
|
children: [
|
||||||
|
const Flex(
|
||||||
|
direction: Axis.horizontal,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 20,
|
||||||
|
child: VerticalDivider(thickness: 8),
|
||||||
|
),
|
||||||
|
Text("活动详情"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Text(data['content'])
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Positioned.fill(
|
||||||
|
bottom: 0,
|
||||||
|
child: Flex(
|
||||||
|
direction: Axis.horizontal,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Flex(
|
||||||
|
direction: Axis.horizontal,
|
||||||
|
children: [
|
||||||
|
Text(data['signUpNum'].toString()),
|
||||||
|
const Text("人已报名")
|
||||||
|
],
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
var data = jsonFromResponse(await GlobalInformation.getInstance().requester.get(resolve("/activity/app/signUp?id=${widget.id}")));
|
||||||
|
if (kDebugMode) {
|
||||||
|
print(data);
|
||||||
|
}
|
||||||
|
if (data['code'] == 200){
|
||||||
|
if (context.mounted){
|
||||||
|
Navigator.pop(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (context.mounted){
|
||||||
|
toast("报名失败,请重试!", context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Text("报名")
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -11,10 +11,10 @@ class DataRequired extends StatefulWidget {
|
|||||||
const DataRequired({super.key, required this.fetchData, required this.afterLoading, this.height = -1, this.width = -1});
|
const DataRequired({super.key, required this.fetchData, required this.afterLoading, this.height = -1, this.width = -1});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<DataRequired> createState() => _DataRequiredState();
|
State<DataRequired> createState() => DataRequiredState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DataRequiredState extends State<DataRequired> {
|
class DataRequiredState extends State<DataRequired> {
|
||||||
bool isLoading = true;
|
bool isLoading = true;
|
||||||
dynamic data = {};
|
dynamic data = {};
|
||||||
void _fetch() async {
|
void _fetch() async {
|
||||||
@ -70,4 +70,8 @@ class _DataRequiredState extends State<DataRequired> {
|
|||||||
}
|
}
|
||||||
return const Center(child: Text("加载失败,网络错误!"));
|
return const Center(child: Text("加载失败,网络错误!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void update() {
|
||||||
|
_fetch();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
20
lib/views/common/full_paged_struct.dart
Normal file
20
lib/views/common/full_paged_struct.dart
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:model_of_the_times/icons/material_design_icons.dart';
|
||||||
|
|
||||||
|
class FullPagedStruct extends StatelessWidget {
|
||||||
|
final Widget child;
|
||||||
|
final String title;
|
||||||
|
const FullPagedStruct({super.key, required this.child, required this.title});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: IconButton(onPressed: (){Navigator.pop(context);}, icon: const Icon(MaterialDesign.keyboard_arrow_left)),
|
||||||
|
title: Text(title),
|
||||||
|
centerTitle: true,
|
||||||
|
),
|
||||||
|
body: Padding(padding: const EdgeInsets.all(10), child: child),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -53,8 +53,6 @@ class _HomeViewState extends State<HomeView> {
|
|||||||
bool onChange(index) {
|
bool onChange(index) {
|
||||||
var func = functions[index];
|
var func = functions[index];
|
||||||
var ret = func(context);
|
var ret = func(context);
|
||||||
print(func);
|
|
||||||
print(ret);
|
|
||||||
if (ret != null){
|
if (ret != null){
|
||||||
setState(() {
|
setState(() {
|
||||||
lastWidget = ret;
|
lastWidget = ret;
|
||||||
|
263
lib/views/learned.dart
Normal file
263
lib/views/learned.dart
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||||
|
import 'package:http/http.dart';
|
||||||
|
import 'package:model_of_the_times/requester/requester.dart';
|
||||||
|
import 'package:model_of_the_times/utils/toast.dart';
|
||||||
|
import 'package:model_of_the_times/views/common/data_required.dart';
|
||||||
|
import 'package:model_of_the_times/views/common/full_paged_struct.dart';
|
||||||
|
|
||||||
|
class Learned extends StatefulWidget {
|
||||||
|
const Learned({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<Learned> createState() => _LearnedState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LearnedState extends State<Learned> with SingleTickerProviderStateMixin {
|
||||||
|
late final TabController _controller;
|
||||||
|
int _index = 0;
|
||||||
|
List<Widget> items = [
|
||||||
|
const Testimonials(),
|
||||||
|
const LearnHistory()
|
||||||
|
];
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_controller = TabController(length: 2, vsync: this);
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: TabBar(
|
||||||
|
controller: _controller,
|
||||||
|
indicatorSize: TabBarIndicatorSize.tab,
|
||||||
|
labelPadding: const EdgeInsetsDirectional.all(10),
|
||||||
|
tabs: const [
|
||||||
|
Text("学习感言"),
|
||||||
|
Text("学习历史"),
|
||||||
|
],
|
||||||
|
onTap: (e){
|
||||||
|
setState(() {
|
||||||
|
_index = e;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
body: items[_index],
|
||||||
|
floatingActionButton: _index == 0 ? FloatingActionButton.extended(onPressed: (){Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) { return const AddTestimonials(); }));}, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), label: const Text("新建感言")) : null,
|
||||||
|
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Testimonial extends StatefulWidget {
|
||||||
|
final int id;
|
||||||
|
final String title;
|
||||||
|
final String content;
|
||||||
|
final GlobalKey<DataRequiredState> parentKey;
|
||||||
|
const Testimonial({super.key, required this.id, required this.title, required this.content, required this.parentKey});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<Testimonial> createState() => _TestimonialState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TestimonialState extends State<Testimonial> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Slidable(
|
||||||
|
endActionPane: ActionPane(
|
||||||
|
motion: const ScrollMotion(),
|
||||||
|
children: [
|
||||||
|
SlidableAction(
|
||||||
|
onPressed: (e){
|
||||||
|
var req = GlobalInformation.getInstance().requester;
|
||||||
|
req.get(resolve("/appStudy/app/deleteStatement?id=${widget.id}")).then((value) {
|
||||||
|
var data = jsonFromResponse(value);
|
||||||
|
if (data['code'] == 200){
|
||||||
|
widget.parentKey.currentState?.update();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (context.mounted){
|
||||||
|
toast("message", context);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
label: "删除",
|
||||||
|
spacing: 1,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
child: Card(
|
||||||
|
child: Padding(padding: const EdgeInsets.all(10), child: ListTile(
|
||||||
|
title: Text(
|
||||||
|
widget.title
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
widget.content,
|
||||||
|
maxLines: 3,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Testimonials extends StatefulWidget {
|
||||||
|
const Testimonials({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<Testimonials> createState() => _TestimonialsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TestimonialsState extends State<Testimonials> {
|
||||||
|
final GlobalKey<DataRequiredState> _key = GlobalKey();
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return DataRequired(
|
||||||
|
key: _key,
|
||||||
|
fetchData: (global) async {
|
||||||
|
var response = await global.requester.get(resolve("/appStudy/app/statementList"));
|
||||||
|
return jsonFromResponse(response);
|
||||||
|
},
|
||||||
|
afterLoading: (data) {
|
||||||
|
return ListView(
|
||||||
|
children: data['rows'].map<Widget>((e){
|
||||||
|
var content = e['content'];
|
||||||
|
var id = e['id'];
|
||||||
|
var title = e['title'];
|
||||||
|
return Testimonial(id: id, title: title, content: content, parentKey: _key);
|
||||||
|
}).toList()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestimonialsEditor extends StatefulWidget {
|
||||||
|
final String defaultTitle;
|
||||||
|
final String defaultContent;
|
||||||
|
const TestimonialsEditor({super.key, this.defaultContent = "", this.defaultTitle = ""});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TestimonialsEditor> createState() => _TestimonialsEditorState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TestimonialsEditorState extends State<TestimonialsEditor> {
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
late String _title;
|
||||||
|
late String _content;
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_title = widget.defaultTitle;
|
||||||
|
_content = widget.defaultContent;
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
TextFormField(
|
||||||
|
initialValue: _title,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: "标题"
|
||||||
|
),
|
||||||
|
validator: (value){
|
||||||
|
if (value == null || value.isEmpty){
|
||||||
|
return "请输入标题";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
onSaved: (value) {if (value != null){_title = value;}},
|
||||||
|
),
|
||||||
|
TextFormField(
|
||||||
|
initialValue: _content,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: "内容"
|
||||||
|
),
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty){
|
||||||
|
return "请输入内容";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
onSaved: (value) {if (value != null){_content = value;}},
|
||||||
|
),
|
||||||
|
SizedBox.fromSize(size: const Size.fromHeight(20),),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () async {
|
||||||
|
if (_formKey.currentState == null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!_formKey.currentState!.validate()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_formKey.currentState!.save();
|
||||||
|
var global = GlobalInformation.getInstance();
|
||||||
|
var createUri = resolve("appStudy/app/createStatement");
|
||||||
|
var req = MultipartRequest("POST", createUri);
|
||||||
|
req.fields.addAll({"title": _title, "content": _content, "picPath": ""});
|
||||||
|
var result = await global.requester.send(req);
|
||||||
|
var data = await jsonFromStreamResponse(result);
|
||||||
|
if (context.mounted){
|
||||||
|
if (data['code'] != 200){
|
||||||
|
toast("添加失败,请重试!", context);
|
||||||
|
}
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Text("提交")
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class AddTestimonials extends StatefulWidget {
|
||||||
|
const AddTestimonials({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AddTestimonials> createState() => _AddTestimonialsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AddTestimonialsState extends State<AddTestimonials> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return const FullPagedStruct(title: "新建感言", child: TestimonialsEditor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LearnHistory extends StatefulWidget {
|
||||||
|
const LearnHistory({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<LearnHistory> createState() => _LearnHistoryState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LearnHistoryState extends State<LearnHistory> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return DataRequired(
|
||||||
|
fetchData: (global) async {
|
||||||
|
var req = global.requester;
|
||||||
|
var historyResponse = await req.get(resolve("/appStudy/app/historyList"));
|
||||||
|
return jsonFromResponse(historyResponse);
|
||||||
|
},
|
||||||
|
afterLoading: (data){
|
||||||
|
if (kDebugMode) {
|
||||||
|
print(data);
|
||||||
|
}
|
||||||
|
return ListView();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -70,6 +70,14 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.2"
|
version: "3.0.2"
|
||||||
|
flutter_slidable:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_slidable
|
||||||
|
sha256: "2c5611c0b44e20d180e4342318e1bbc28b0a44ad2c442f5df16962606fd3e8e3"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.1"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -36,6 +36,7 @@ dependencies:
|
|||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.6
|
cupertino_icons: ^1.0.6
|
||||||
http: ^1.2.2
|
http: ^1.2.2
|
||||||
|
flutter_slidable: ^3.1.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user