任务发布模块

master
张萌 3 years ago
parent 2e8615f610
commit 9a118e2aa0

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

@ -153,8 +153,32 @@ class _Search {
String get homeSearch => "/user/search/search";
}
class _Task {
///
String get hallList => '/user/taskRelease/list';
///
String get myTask => '/user/taskRelease/myList';
///
String get myTakeTask => '/user/taskRelease/myOrder';
///
String get publish => '/user/taskRelease/insert';
///
String get cancel => '/user/taskRelease/cancel';
///
String get take => '/user/taskRelease/access';
///
String get finish => '/user/taskRelease/finish';
}
class _Manager {
_Facility facility = _Facility();
_Task task = _Task();
///
String get commiteeStaff => '/ownersCommittee/findAll';

@ -31,6 +31,7 @@ import 'package:aku_new_community/ui/manager/questionnaire/questionnaire_page.da
import 'package:aku_new_community/ui/profile/car/car_manage_page.dart';
import 'package:aku_new_community/ui/profile/car_parking/car_parking_page.dart';
import 'package:aku_new_community/ui/profile/house/house_owners_page.dart';
import 'package:aku_new_community/ui/service/task_page.dart';
import 'package:aku_new_community/widget/others/user_tool.dart';
import 'package:flutter/material.dart';
@ -100,7 +101,7 @@ List<AO> appObjects = [
AO('住房说明', R.ASSETS_ICONS_FUNC_ZFSM_PNG, () => HouseIntroducePage()),
AO('智慧养老', Assets.icons.provideAged.path, () => OldAgeSupportPageSimple()),
AO('周边服务', Assets.icons.nearbyService.path, null),
AO('小蜜蜂任务', Assets.icons.beeTask.path, null),
AO('小蜜蜂任务', Assets.icons.beeTask.path, () => TaskPage()),
AO('自营商城', Assets.icons.shoppingMall.path, null),
AO('邻家宠物', Assets.icons.nearbyPet.path, null),
AO('共享停车', Assets.icons.sharePark.path, null),

@ -0,0 +1,11 @@
import 'package:flutter/material.dart';
extension ColorExt on Color {
///
Color get complementary {
var r = ~this.red;
var g = ~this.green;
var b = ~this.blue;
return Color.fromARGB(this.alpha, r, g, b);
}
}

@ -190,6 +190,10 @@ class $AssetsIconsGen {
/// File path: assets/icons/change.png
AssetGenImage get change => const AssetGenImage('assets/icons/change.png');
/// File path: assets/icons/clock_circle.png
AssetGenImage get clockCircle =>
const AssetGenImage('assets/icons/clock_circle.png');
/// File path: assets/icons/clock_success.png
AssetGenImage get clockSuccess =>
const AssetGenImage('assets/icons/clock_success.png');
@ -246,6 +250,13 @@ class $AssetsIconsGen {
AssetGenImage get deviceAlarm =>
const AssetGenImage('assets/icons/device_alarm.png');
/// File path: assets/icons/edit.png
AssetGenImage get edit => const AssetGenImage('assets/icons/edit.png');
/// File path: assets/icons/environment.png
AssetGenImage get environment =>
const AssetGenImage('assets/icons/environment.png');
/// File path: assets/icons/examine.png
AssetGenImage get examine => const AssetGenImage('assets/icons/examine.png');
@ -663,6 +674,10 @@ class $AssetsIconsGen {
/// File path: assets/icons/phone.png
AssetGenImage get phone => const AssetGenImage('assets/icons/phone.png');
/// File path: assets/icons/phone_circle.png
AssetGenImage get phoneCircle =>
const AssetGenImage('assets/icons/phone_circle.png');
/// File path: assets/icons/projection_screen.png
AssetGenImage get projectionScreen =>
const AssetGenImage('assets/icons/projection_screen.png');
@ -682,6 +697,9 @@ class $AssetsIconsGen {
/// File path: assets/icons/report.png
AssetGenImage get report => const AssetGenImage('assets/icons/report.png');
/// File path: assets/icons/reward.png
AssetGenImage get reward => const AssetGenImage('assets/icons/reward.png');
/// File path: assets/icons/second_hand.png
AssetGenImage get secondHand =>
const AssetGenImage('assets/icons/second_hand.png');
@ -791,6 +809,9 @@ class $AssetsIconsGen {
AssetGenImage get tabbarUserNo =>
const AssetGenImage('assets/icons/tabbar_user_no.png');
/// File path: assets/icons/tag.png
AssetGenImage get tag => const AssetGenImage('assets/icons/tag.png');
/// File path: assets/icons/test_kingcion.png
AssetGenImage get testKingcion =>
const AssetGenImage('assets/icons/test_kingcion.png');

@ -0,0 +1,40 @@
import 'package:json_annotation/json_annotation.dart';
part 'hall_list_model.g.dart';
@JsonSerializable()
class HallListModel {
final int id;
final String title;
final int status;
final int type;
final int sex;
final int serviceObject;
final String content;
final String appointmentDate;
final String appointmentAddress;
final int rewardType;
final int reward;
final int createType;
final String? createName;
final String createDate;
factory HallListModel.fromJson(Map<String, dynamic> json) =>
_$HallListModelFromJson(json);
const HallListModel({
required this.id,
required this.title,
required this.status,
required this.type,
required this.sex,
required this.serviceObject,
required this.content,
required this.appointmentDate,
required this.appointmentAddress,
required this.rewardType,
required this.reward,
required this.createType,
this.createName,
required this.createDate,
});
}

@ -0,0 +1,25 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'hall_list_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
HallListModel _$HallListModelFromJson(Map<String, dynamic> json) =>
HallListModel(
id: json['id'] as int,
title: json['title'] as String,
status: json['status'] as int,
type: json['type'] as int,
sex: json['sex'] as int,
serviceObject: json['serviceObject'] as int,
content: json['content'] as String,
appointmentDate: json['appointmentDate'] as String,
appointmentAddress: json['appointmentAddress'] as String,
rewardType: json['rewardType'] as int,
reward: json['reward'] as int,
createType: json['createType'] as int,
createName: json['createName'] as String?,
createDate: json['createDate'] as String,
);

@ -0,0 +1,41 @@
import 'package:json_annotation/json_annotation.dart';
part 'my_take_task_list_model.g.dart';
@JsonSerializable()
class MyTakeTaskListModel {
final int id;
final String title;
final int status;
final int type;
final int sex;
final int serviceObject;
final String content;
final String appointmentDate;
final String appointmentAddress;
final int rewardType;
final int reward;
final int createType;
final String? createName;
final String createDate;
factory MyTakeTaskListModel.fromJson(Map<String, dynamic> json) =>
_$MyTakeTaskListModelFromJson(json);
const MyTakeTaskListModel({
required this.id,
required this.title,
required this.status,
required this.type,
required this.sex,
required this.serviceObject,
required this.content,
required this.appointmentDate,
required this.appointmentAddress,
required this.rewardType,
required this.reward,
required this.createType,
this.createName,
required this.createDate,
});
}

@ -0,0 +1,25 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'my_take_task_list_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
MyTakeTaskListModel _$MyTakeTaskListModelFromJson(Map<String, dynamic> json) =>
MyTakeTaskListModel(
id: json['id'] as int,
title: json['title'] as String,
status: json['status'] as int,
type: json['type'] as int,
sex: json['sex'] as int,
serviceObject: json['serviceObject'] as int,
content: json['content'] as String,
appointmentDate: json['appointmentDate'] as String,
appointmentAddress: json['appointmentAddress'] as String,
rewardType: json['rewardType'] as int,
reward: json['reward'] as int,
createType: json['createType'] as int,
createName: json['createName'] as String?,
createDate: json['createDate'] as String,
);

@ -0,0 +1,40 @@
import 'package:json_annotation/json_annotation.dart';
part 'my_task_list_model.g.dart';
@JsonSerializable()
class MyTaskListModel {
final int id;
final String title;
final int status;
final int type;
final int sex;
final int serviceObject;
final String content;
final String appointmentDate;
final String appointmentAddress;
final int rewardType;
final int reward;
final int createType;
final String? createName;
final String createDate;
factory MyTaskListModel.fromJson(Map<String, dynamic> json) =>
_$MyTaskListModelFromJson(json);
const MyTaskListModel({
required this.id,
required this.title,
required this.status,
required this.type,
required this.sex,
required this.serviceObject,
required this.content,
required this.appointmentDate,
required this.appointmentAddress,
required this.rewardType,
required this.reward,
required this.createType,
this.createName,
required this.createDate,
});
}

@ -0,0 +1,25 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'my_task_list_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
MyTaskListModel _$MyTaskListModelFromJson(Map<String, dynamic> json) =>
MyTaskListModel(
id: json['id'] as int,
title: json['title'] as String,
status: json['status'] as int,
type: json['type'] as int,
sex: json['sex'] as int,
serviceObject: json['serviceObject'] as int,
content: json['content'] as String,
appointmentDate: json['appointmentDate'] as String,
appointmentAddress: json['appointmentAddress'] as String,
rewardType: json['rewardType'] as int,
reward: json['reward'] as int,
createType: json['createType'] as int,
createName: json['createName'] as String?,
createDate: json['createDate'] as String,
);

@ -0,0 +1,151 @@
import 'package:aku_new_community/gen/assets.gen.dart';
import 'package:aku_new_community/models/task/hall_list_model.dart';
import 'package:aku_new_community/ui/service/hall/hall_detail_page.dart';
import 'package:aku_new_community/ui/service/task_map.dart';
import 'package:aku_new_community/widget/buttons/card_bottom_button.dart';
import 'package:flustars/flustars.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:velocity_x/velocity_x.dart';
class HallCard extends StatelessWidget {
final HallListModel model;
final VoidCallback refresh;
const HallCard({Key? key, required this.model, required this.refresh})
: super(key: key);
@override
Widget build(BuildContext context) {
var head = Row(
children: [
Container(
width: 100.w,
height: 50.w,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Color(0xFFFFF7E6),
borderRadius: BorderRadius.circular(8.w),
),
child: '#${TaskMap.typeToString[model.type]}'
.text
.size(28.sp)
.color(Color(0xFFFA8C16))
.make(),
),
Spacer(),
Assets.icons.intergral.image(width: 24.w, height: 24.w),
8.w.widthBox,
'${model.reward}'.text.size(32.sp).color(Colors.red).make()
],
);
return GestureDetector(
onTap: () {
Get.to(() => HallDetailPage(model: model));
},
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.w),
),
padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 24.w),
child: Column(
children: [
head,
34.w.heightBox,
Row(
children: [
Assets.icons.clockCircle.image(width: 36.w, height: 36.w),
24.w.widthBox,
'${DateUtil.formatDateStr(model.appointmentDate)}'
.text
.size(24.sp)
.color(Colors.black.withOpacity(0.65))
.make(),
],
),
20.w.heightBox,
Row(
children: [
Assets.icons.environment.image(width: 36.w, height: 36.w),
24.w.widthBox,
'${model.appointmentAddress}'
.text
.size(24.sp)
.color(Colors.black.withOpacity(0.65))
.make(),
],
),
34.w.heightBox,
Container(
width: 638.w,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.03),
borderRadius: BorderRadius.circular(8.w)),
padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 24.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
'#${TaskMap.typeToString[model.type]}'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.85))
.make(),
16.w.heightBox,
model.content.text
.size(28.sp)
.color(Colors.black.withOpacity(0.65))
.make(),
],
),
),
40.w.heightBox,
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
40.w.heightBox,
Row(
children: [
Spacer(),
CardBottomButton.yellow(text: '领取任务', onPressed: () {}),
],
),
],
),
],
),
),
);
}
Widget _cardBottom(int) {
switch (int) {
case 1:
case 2:
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
40.w.heightBox,
CardBottomButton.white(text: '取消订单', onPressed: () {}),
CardBottomButton.yellow(text: '确认完成', onPressed: () {}),
],
);
case 4:
return Column(
children: [
32.w.heightBox,
Row(
children: [
'客户取消:暂不需要该服务'.text.size(24.sp).color(Colors.red).make(),
Spacer(),
],
),
],
);
default:
return SizedBox.shrink();
}
}
}

@ -0,0 +1,262 @@
import 'package:aku_new_community/gen/assets.gen.dart';
import 'package:aku_new_community/models/task/hall_list_model.dart';
import 'package:aku_new_community/ui/service/task_map.dart';
import 'package:aku_new_community/widget/bee_divider.dart';
import 'package:aku_new_community/widget/bee_scaffold.dart';
import 'package:flustars/flustars.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:velocity_x/velocity_x.dart';
class HallDetailPage extends StatefulWidget {
final HallListModel model;
const HallDetailPage({Key? key, required this.model}) : super(key: key);
@override
_HallDetailPageState createState() => _HallDetailPageState();
}
class _HallDetailPageState extends State<HallDetailPage> {
@override
Widget build(BuildContext context) {
return BeeScaffold(
extendBody: true,
title: '',
body: Stack(
children: [
Column(
children: [
Container(
width: double.infinity,
height: 380.w,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: widget.model.status == 4
? [
Colors.white,
Color(0xFFADACAC),
]
: [
Color(0xFFFFB737),
Color(0xFFFFD361),
]),
),
child: Column(
children: [
150.w.heightBox,
Row(
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 32.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
'${TaskMap.detailStatusToString[widget.model.status]}'
.text
.size(40.sp)
.color(Colors.black)
.bold
.make(),
'${TaskMap.subStatus[widget.model.status]}'
.text
.size(24.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
],
),
),
Spacer(),
Padding(
padding: EdgeInsets.only(right: 32.w),
child: MaterialButton(
color: Colors.white,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.w),
),
onPressed: () {},
child: '取消订单'
.text
.size(24.sp)
.color(Colors.black.withOpacity(0.65))
.make(),
),
)
],
),
],
),
),
Flexible(
child: Container(
width: double.infinity,
color: Color(0xFFE5E5E5),
),
),
],
),
Positioned(
top: 280.w,
left: 32.w,
right: 32.w,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
_content(),
24.w.heightBox,
_taskInfo(),
],
)),
],
),
);
}
Widget _taskInfo() {
return Container(
width: 686.w,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.w),
),
padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 24.w),
child: Column(
children: [
Row(
children: [
'任务信息'.text.size(28.sp).color(Colors.black).bold.make(),
Spacer(),
],
),
24.w.heightBox,
BeeDivider.horizontal(),
24.w.heightBox,
Row(
children: [
'创建时间'
.text
.size(24.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
Spacer(),
'${DateUtil.formatDateStr(widget.model.createDate)}'
.text
.size(24.sp)
.color(Colors.black.withOpacity(0.45))
.make()
],
),
],
),
);
}
Widget _content() {
var head = Row(
children: [
Container(
width: 100.w,
height: 50.w,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Color(0xFFFFF7E6),
borderRadius: BorderRadius.circular(8.w),
),
child: '#${TaskMap.typeToString[widget.model.type]}'
.text
.size(28.sp)
.color(Color(0xFFFA8C16))
.make(),
),
Spacer(),
Assets.icons.intergral.image(width: 24.w, height: 24.w),
8.w.widthBox,
'${widget.model.reward}'.text.size(32.sp).color(Colors.red).make()
],
);
return Container(
width: 686.w,
height: 500.w,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.w),
),
padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 24.w),
child: Column(
children: [
head,
34.w.heightBox,
Row(
children: [
Assets.icons.clockCircle.image(width: 36.w, height: 36.w),
24.w.widthBox,
'${DateUtil.formatDateStr(widget.model.appointmentDate)}'
.text
.size(24.sp)
.color(Colors.black.withOpacity(0.65))
.make(),
],
),
20.w.heightBox,
Row(
children: [
Assets.icons.environment.image(width: 36.w, height: 36.w),
24.w.widthBox,
'${widget.model.appointmentAddress}'
.text
.size(24.sp)
.color(Colors.black.withOpacity(0.65))
.make(),
],
),
34.w.heightBox,
Container(
width: 638.w,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.03),
borderRadius: BorderRadius.circular(8.w)),
padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 24.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
'#${TaskMap.typeToString[widget.model.type]}'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.85))
.make(),
16.w.heightBox,
widget.model.content.text
.size(28.sp)
.color(Colors.black.withOpacity(0.65))
.make(),
],
),
),
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
Row(
children: [
Assets.icons.reward.image(width: 36.w, height: 36.w),
24.w.widthBox,
'报酬'
.text
.size(26.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
Spacer(),
'¥${widget.model.reward}'
.text
.size(32.sp)
.color(Colors.red)
.make(),
],
),
],
),
);
}
}

@ -0,0 +1,49 @@
import 'package:aku_new_community/constants/api.dart';
import 'package:aku_new_community/models/task/hall_list_model.dart';
import 'package:aku_new_community/pages/things_page/widget/bee_list_view.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:velocity_x/src/extensions/num_ext.dart';
import 'hall_card.dart';
class HallView extends StatefulWidget {
const HallView({Key? key}) : super(key: key);
@override
_HallViewState createState() => _HallViewState();
}
class _HallViewState extends State<HallView> {
EasyRefreshController _refreshController = EasyRefreshController();
@override
void dispose() {
_refreshController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BeeListView(
path: API.manager.task.hallList,
controller: _refreshController,
extraParams: {},
convert: (json) =>
json.tableList!.map((e) => HallListModel.fromJson(e)).toList(),
builder: (models) {
return ListView.separated(
padding: EdgeInsets.symmetric(horizontal: 32.w, vertical: 24.w),
itemBuilder: (context, index) {
return HallCard(
model: models[index],
refresh: () => _refreshController.callRefresh());
},
separatorBuilder: (_, __) {
return 24.w.heightBox;
},
itemCount: models.length);
});
}
}

@ -0,0 +1,165 @@
import 'package:aku_new_community/gen/assets.gen.dart';
import 'package:aku_new_community/models/task/hall_list_model.dart';
import 'package:aku_new_community/ui/service/task_map.dart';
import 'package:aku_new_community/widget/bee_divider.dart';
import 'package:aku_new_community/widget/buttons/card_bottom_button.dart';
import 'package:flustars/flustars.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:velocity_x/velocity_x.dart';
class MyTakeTaskCard extends StatelessWidget {
final HallListModel model;
final VoidCallback refresh;
const MyTakeTaskCard({Key? key, required this.model, required this.refresh})
: super(key: key);
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
decoration: BoxDecoration(
color: Color(0xFFFFF7E6),
borderRadius: BorderRadius.circular(8.w),
),
padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 24.w),
child: Column(
children: [
Row(
children: [
'接单时间 ${DateUtil.formatDateStr(model.createDate)}'
.text
.size(26.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
Spacer(),
'${TaskMap.statusToString[model.status]}'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.85))
.bold
.make()
],
),
20.w.heightBox,
BeeDivider.horizontal(),
34.w.heightBox,
Row(
children: [
Assets.icons.clockCircle.image(width: 36.w, height: 36.w),
24.w.widthBox,
'${DateUtil.formatDateStr(model.appointmentDate)}'
.text
.size(24.sp)
.color(Colors.black.withOpacity(0.65))
.make(),
],
),
20.w.heightBox,
Row(
children: [
Assets.icons.environment.image(width: 36.w, height: 36.w),
24.w.widthBox,
'${model.appointmentAddress}'
.text
.size(24.sp)
.color(Colors.black.withOpacity(0.65))
.make(),
],
),
34.w.heightBox,
Container(
width: 638.w,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.03),
borderRadius: BorderRadius.circular(8.w)),
padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 24.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
'#${TaskMap.typeToString[model.type]}'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.85))
.make(),
16.w.heightBox,
model.content.text
.size(28.sp)
.color(Colors.black.withOpacity(0.65))
.make(),
],
),
),
40.w.heightBox,
Row(
children: [
Spacer(),
RichText(
text: TextSpan(
text: '实付 ',
children: model.rewardType == 2
? [
WidgetSpan(
child: Assets.icons.intergral
.image(width: 24.w, height: 24.w),
),
model.reward
.toString()
.textSpan
.size(32.sp)
.color(Colors.red)
.make(),
]
: [
'¥ ${model.reward}'
.toString()
.textSpan
.size(32.sp)
.color(Colors.red)
.make(),
],
style: TextStyle(
color: Colors.black.withOpacity(0.65), fontSize: 24.sp),
),
)
],
),
_cardBottom(model.status),
],
),
);
}
Widget _cardBottom(int) {
switch (int) {
case 1:
case 2:
return Column(
children: [
40.w.heightBox,
Row(
children: [
CardBottomButton.white(text: '取消订单', onPressed: () {}),
CardBottomButton.yellow(text: '确认完成', onPressed: () {}),
],
)
],
);
case 4:
return Column(
children: [
32.w.heightBox,
Row(
children: [
'客户取消:暂不需要该服务'.text.size(24.sp).color(Colors.red).make(),
Spacer(),
],
),
],
);
default:
return SizedBox.shrink();
}
}
}

@ -0,0 +1,48 @@
import 'package:aku_new_community/constants/api.dart';
import 'package:aku_new_community/models/task/my_take_task_list_model.dart';
import 'package:aku_new_community/pages/things_page/widget/bee_list_view.dart';
import 'package:aku_new_community/ui/service/my_take_task/my_take_task_card.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:velocity_x/velocity_x.dart';
class MyTakeTaskView extends StatefulWidget {
const MyTakeTaskView({Key? key}) : super(key: key);
@override
_MyTakeTaskViewState createState() => _MyTakeTaskViewState();
}
class _MyTakeTaskViewState extends State<MyTakeTaskView> {
EasyRefreshController _refreshController = EasyRefreshController();
@override
void dispose() {
_refreshController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BeeListView(
path: API.manager.task.myTakeTask,
controller: _refreshController,
convert: (json) => json.tableList!
.map((e) => MyTakeTaskListModel.fromJson(e))
.toList(),
builder: (models) {
return ListView.separated(
padding: EdgeInsets.symmetric(horizontal: 32.w, vertical: 24.w),
itemBuilder: (context, index) {
return MyTakeTaskCard(
model: models[index],
refresh: () => _refreshController.callRefresh());
},
separatorBuilder: (_, __) {
return 24.w.heightBox;
},
itemCount: models.length);
});
}
}

@ -0,0 +1,180 @@
import 'package:aku_new_community/gen/assets.gen.dart';
import 'package:aku_new_community/models/task/my_task_list_model.dart';
import 'package:aku_new_community/ui/service/task_map.dart';
import 'package:aku_new_community/widget/buttons/card_bottom_button.dart';
import 'package:flustars/flustars.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:velocity_x/velocity_x.dart';
class MyTaskCard extends StatelessWidget {
final MyTaskListModel model;
final VoidCallback refresh;
const MyTaskCard({Key? key, required this.model, required this.refresh})
: super(key: key);
@override
Widget build(BuildContext context) {
var head = Row(
children: [
Container(
width: 100.w,
height: 50.w,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Color(0xFFFFF7E6),
borderRadius: BorderRadius.circular(8.w),
),
child: '#${TaskMap.typeToString[model.type]}'
.text
.size(28.sp)
.color(Color(0xFFFA8C16))
.make(),
),
Spacer(),
'${TaskMap.statusToString[model.status]}'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.85))
.bold
.make()
],
);
return Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.w),
),
padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 24.w),
child: Column(
children: [
head,
34.w.heightBox,
Row(
children: [
Assets.icons.clockCircle.image(width: 36.w, height: 36.w),
24.w.widthBox,
'${DateUtil.formatDateStr(model.appointmentDate)}'
.text
.size(24.sp)
.color(Colors.black.withOpacity(0.65))
.make(),
],
),
20.w.heightBox,
Row(
children: [
Assets.icons.environment.image(width: 36.w, height: 36.w),
24.w.widthBox,
'${model.appointmentAddress}'
.text
.size(24.sp)
.color(Colors.black.withOpacity(0.65))
.make(),
],
),
34.w.heightBox,
Container(
width: 638.w,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.03),
borderRadius: BorderRadius.circular(8.w)),
padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 24.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
'#${TaskMap.typeToString[model.type]}'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.85))
.make(),
16.w.heightBox,
model.content.text
.size(28.sp)
.color(Colors.black.withOpacity(0.65))
.make(),
],
),
),
40.w.heightBox,
Row(
children: [
Spacer(),
RichText(
text: TextSpan(
text: '实付 ',
children: model.rewardType == 2
? [
WidgetSpan(
child: Assets.icons.intergral
.image(width: 24.w, height: 24.w),
),
model.reward
.toString()
.textSpan
.size(32.sp)
.color(Colors.red)
.make(),
]
: [
'¥ ${model.reward}'
.toString()
.textSpan
.size(32.sp)
.color(Colors.red)
.make(),
],
style: TextStyle(
color: Colors.black.withOpacity(0.65), fontSize: 24.sp),
),
)
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
40.w.heightBox,
Row(
children: [
Spacer(),
CardBottomButton.yellow(text: '取消订单', onPressed: () {}),
],
),
],
),
],
),
);
}
Widget _cardBottom(int) {
switch (int) {
case 1:
case 2:
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
40.w.heightBox,
CardBottomButton.white(text: '取消订单', onPressed: () {}),
CardBottomButton.yellow(text: '确认完成', onPressed: () {}),
],
);
case 4:
return Column(
children: [
32.w.heightBox,
Row(
children: [
'客户取消:暂不需要该服务'.text.size(24.sp).color(Colors.red).make(),
Spacer(),
],
),
],
);
default:
return SizedBox.shrink();
}
}
}

@ -0,0 +1,47 @@
import 'package:aku_new_community/constants/api.dart';
import 'package:aku_new_community/models/task/my_task_list_model.dart';
import 'package:aku_new_community/pages/things_page/widget/bee_list_view.dart';
import 'package:aku_new_community/ui/service/my_task/my_task_card.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:velocity_x/velocity_x.dart';
class MyTaskView extends StatefulWidget {
const MyTaskView({Key? key}) : super(key: key);
@override
_MyTaskViewState createState() => _MyTaskViewState();
}
class _MyTaskViewState extends State<MyTaskView> {
EasyRefreshController _refreshController = EasyRefreshController();
@override
void dispose() {
_refreshController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BeeListView(
path: API.manager.task.myTask,
controller: _refreshController,
convert: (json) =>
json.tableList!.map((e) => MyTaskListModel.fromJson(e)).toList(),
builder: (models) {
return ListView.separated(
padding: EdgeInsets.symmetric(horizontal: 32.w, vertical: 24.w),
itemBuilder: (context, index) {
return MyTaskCard(
model: models[index],
refresh: () => _refreshController.callRefresh());
},
separatorBuilder: (_, __) {
return 24.w.heightBox;
},
itemCount: models.length);
});
}
}

@ -0,0 +1,614 @@
import 'package:aku_new_community/base/base_style.dart';
import 'package:aku_new_community/ui/service/task_func.dart';
import 'package:aku_new_community/utils/headers.dart';
import 'package:aku_new_community/widget/bee_divider.dart';
import 'package:aku_new_community/widget/bee_scaffold.dart';
import 'package:aku_new_community/widget/picker/bee_date_picker.dart';
import 'package:aku_new_community/widget/picker/bee_picker_box.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:flustars/flustars.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:velocity_x/velocity_x.dart';
class PublishTaskPage extends StatefulWidget {
const PublishTaskPage({Key? key}) : super(key: key);
@override
_PublishTaskPageState createState() => _PublishTaskPageState();
}
class _PublishTaskPageState extends State<PublishTaskPage> {
List<String> _types = ['跑腿', '代驾', '装修', '陪玩', '家政', '维修', '搬家', '家教', '其他'];
int _type = 0;
List<String> _sexStr = ['', '', '不限'];
int _sex = 0;
int _service = 0;
List<String> _serviceObject = ['住户', '物业', '不限'];
List<String> _rewardTypes = ['赏金', '积分'];
int _rewardType = 0;
DateTime? _appointDate = DateTime.now();
TextEditingController _titleController = TextEditingController();
TextEditingController _contentController = TextEditingController();
TextEditingController _addressController = TextEditingController();
TextEditingController _rewardController = TextEditingController();
@override
void dispose() {
_titleController.dispose();
_contentController.dispose();
_addressController.dispose();
_rewardController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BeeScaffold(
title: '发布任务',
body: SafeArea(
child: ListView(
padding: EdgeInsets.symmetric(horizontal: 32.w, vertical: 24.w),
children: [
Container(
width: double.infinity,
padding: EdgeInsets.only(left: 32.w, right: 32.w, bottom: 32.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.w),
),
child: Column(
children: [
Row(
children: [
SizedBox(
width: 170.w,
child: '标题'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
),
Expanded(
child: TextField(
controller: _titleController,
onChanged: (text) => setState(() {}),
autofocus: false,
decoration: InputDecoration(
hintStyle: TextStyle(
fontSize: 28.sp,
color: Colors.black.withOpacity(0.25),
),
border: InputBorder.none,
hintText: '请输入',
),
),
),
],
),
BeeDivider.horizontal(),
32.w.heightBox,
GestureDetector(
onTap: () async {
_type = 1;
showModalBottomSheet(
context: context,
builder: (context) {
return BeePickerBox(
onPressed: () {
Get.back();
print(_type);
setState(() {});
},
child: CupertinoPicker.builder(
itemExtent: 60.w,
childCount: _types.length,
onSelectedItemChanged: (index) {
_type = index + 1;
},
itemBuilder: (context, index) {
return Center(
child: _types[index]
.text
.size(32.sp)
.isIntrinsic
.color(Colors.black.withOpacity(0.25))
.make(),
);
}));
},
);
},
child: Material(
color: Colors.transparent,
child: Row(
children: [
SizedBox(
width: 170.w,
child: '分类'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
),
'${_type == 0 ? '请选择分类' : _types[_type - 1]}'
.text
.size(28.sp)
.color(Colors.black
.withOpacity(_type == 0 ? 0.25 : 0.85))
.make(),
Spacer(),
Icon(
CupertinoIcons.chevron_right,
size: 24.w,
),
],
),
),
),
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
GestureDetector(
onTap: () async {
await Get.bottomSheet(CupertinoActionSheet(
cancelButton: CupertinoActionSheetAction(
onPressed: () {
Get.back();
},
child: '取消'
.text
.size(28.sp)
.isIntrinsic
.color(Colors.black.withOpacity(0.85))
.make()),
actions: [
CupertinoActionSheetAction(
onPressed: () {
_sex = 1;
Get.back();
setState(() {});
},
child: ''
.text
.size(28.sp)
.isIntrinsic
.color(Colors.black.withOpacity(0.85))
.make()),
CupertinoActionSheetAction(
onPressed: () {
_sex = 2;
Get.back();
setState(() {});
},
child: ''
.text
.size(28.sp)
.isIntrinsic
.color(Colors.black.withOpacity(0.85))
.make()),
CupertinoActionSheetAction(
onPressed: () {
_sex = 3;
Get.back();
setState(() {});
},
child: '不限'
.text
.size(28.sp)
.isIntrinsic
.color(Colors.black.withOpacity(0.85))
.make())
],
));
},
child: Material(
color: Colors.transparent,
child: Row(
children: [
SizedBox(
width: 170.w,
child: '性别'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
),
'${_sex == 0 ? '请选择性别' : _sexStr[_sex - 1]}'
.text
.size(28.sp)
.color(Colors.black
.withOpacity(_sex == 0 ? 0.25 : 0.85))
.make(),
Spacer(),
Icon(
CupertinoIcons.chevron_right,
size: 24.w,
),
],
),
),
),
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
GestureDetector(
onTap: () async {
await Get.bottomSheet(CupertinoActionSheet(
cancelButton: CupertinoActionSheetAction(
onPressed: () {
Get.back();
},
child: '取消'
.text
.size(28.sp)
.isIntrinsic
.color(Colors.black.withOpacity(0.85))
.make()),
actions: [
CupertinoActionSheetAction(
onPressed: () {
_service = 1;
Get.back();
setState(() {});
},
child: '住户'
.text
.size(28.sp)
.isIntrinsic
.color(Colors.black.withOpacity(0.85))
.make()),
CupertinoActionSheetAction(
onPressed: () {
_service = 2;
Get.back();
setState(() {});
},
child: '业主'
.text
.size(28.sp)
.isIntrinsic
.color(Colors.black.withOpacity(0.85))
.make()),
CupertinoActionSheetAction(
onPressed: () {
_service = 3;
Get.back();
setState(() {});
},
child: '不限'
.text
.size(28.sp)
.isIntrinsic
.color(Colors.black.withOpacity(0.85))
.make())
],
));
},
child: Material(
color: Colors.transparent,
child: Row(
children: [
SizedBox(
width: 170.w,
child: '服务人员'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
),
'${_service == 0 ? '请选择服务人员' : _serviceObject[_service - 1]}'
.text
.size(28.sp)
.color(Colors.black
.withOpacity(_service == 0 ? 0.25 : 0.85))
.make(),
Spacer(),
Icon(
CupertinoIcons.chevron_right,
size: 24.w,
),
],
),
),
),
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
'任务内容'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
],
),
32.w.heightBox,
Container(
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 24.w),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.06),
borderRadius: BorderRadius.circular(16.w)),
child: TextField(
controller: _contentController,
autofocus: false,
onChanged: (text) => setState(() {}),
minLines: 5,
maxLength: 200,
maxLines: 20,
decoration: InputDecoration(
border: InputBorder.none,
),
),
),
],
),
),
32.w.heightBox,
Container(
width: double.infinity,
padding: EdgeInsets.only(
left: 32.w, right: 32.w, bottom: 32.w, top: 32.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.w),
),
child: Column(
children: [
GestureDetector(
onTap: () async {
_appointDate =
await BeeDatePicker.timePicker(DateTime.now());
},
child: Material(
color: Colors.transparent,
child: Row(
children: [
SizedBox(
width: 170.w,
child: '预约时间'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
),
'${DateUtil.formatDate(_appointDate)}'
.text
.size(28.sp)
.color(Colors.black
.withOpacity(_type == 0 ? 0.25 : 0.85))
.make(),
Spacer(),
Icon(
CupertinoIcons.chevron_right,
size: 24.w,
),
],
),
),
),
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
Row(
children: [
SizedBox(
width: 170.w,
child: '预约地址'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
),
'${S.of(context)!.tempPlotName}'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.85))
.make(),
''
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.25))
.make(),
Expanded(
child: TextField(
autofocus: false,
controller: _addressController,
onChanged: (text) => setState(() {}),
decoration: InputDecoration(
contentPadding: EdgeInsets.zero,
isDense: true,
border: InputBorder.none,
hintText: '请输入',
hintStyle: TextStyle(
fontSize: 28.sp,
color: Colors.black.withOpacity(0.25),
)),
),
),
],
),
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
GestureDetector(
onTap: () async {
await Get.bottomSheet(CupertinoActionSheet(
cancelButton: CupertinoActionSheetAction(
onPressed: () {
Get.back();
},
child: '取消'
.text
.size(28.sp)
.isIntrinsic
.color(Colors.black.withOpacity(0.85))
.make()),
actions: [
CupertinoActionSheetAction(
onPressed: () {
_rewardType = 1;
Get.back();
setState(() {});
},
child: '赏金'
.text
.size(28.sp)
.isIntrinsic
.color(Colors.black.withOpacity(0.85))
.make()),
CupertinoActionSheetAction(
onPressed: () {
_rewardType = 2;
Get.back();
setState(() {});
},
child: '积分'
.text
.size(28.sp)
.isIntrinsic
.color(Colors.black.withOpacity(0.85))
.make()),
],
));
},
child: Material(
color: Colors.transparent,
child: Row(
children: [
SizedBox(
width: 170.w,
child: '报酬类型'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
),
'${_rewardType == 0 ? '请选择报酬类型' : _rewardTypes[_rewardType - 1]}'
.text
.size(28.sp)
.color(Colors.black
.withOpacity(_rewardType == 0 ? 0.25 : 0.85))
.make(),
Spacer(),
Icon(
CupertinoIcons.chevron_right,
size: 24.w,
),
],
),
),
),
32.w.heightBox,
BeeDivider.horizontal(),
32.w.heightBox,
Row(
children: [
SizedBox(
width: 170.w,
child: '${_rewardType == 1 ? '赏金金额' : '积分数量'}'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.45))
.make(),
),
Expanded(
child: TextField(
textAlign: TextAlign.end,
onChanged: (text) => setState(() {}),
autofocus: false,
controller: _rewardController,
style: TextStyle(color: Colors.red),
decoration: InputDecoration(
contentPadding: EdgeInsets.zero,
isDense: true,
border: InputBorder.none,
hintText: '请输入',
hintStyle: TextStyle(
fontSize: 28.sp,
color: Colors.black.withOpacity(0.25),
)),
),
),
'${_rewardType == 1 ? '' : ''}'
.text
.size(28.sp)
.color(Colors.black.withOpacity(0.85))
.make(),
],
)
],
),
),
],
),
),
bottomNavi: Padding(
padding: EdgeInsets.symmetric(horizontal: 32.w, vertical: 32.w),
child: MaterialButton(
elevation: 0,
height: 93.w,
disabledColor: Colors.black.withOpacity(0.06),
disabledTextColor: Colors.black.withOpacity(0.25),
textColor: Colors.black.withOpacity(0.85),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(65.w)),
color: kPrimaryColor,
onPressed: !canTap
? null
: () async {
var cancel = BotToast.showLoading();
var re = await TaskFunc.publish(
title: _titleController.text,
taskType: _type,
taskSex: _sex,
serviceObject: _service,
taskContent: _contentController.text,
taskDate: _appointDate.toString(),
taskAddress: _addressController.text,
rewardType: _rewardType,
reward: _rewardController.text);
if (re) {
Get.back();
}
cancel();
},
child: '确认发布'.text.size(32.sp).bold.make(),
),
),
);
}
bool get canTap {
if (_titleController.text.isEmpty) {
return false;
}
if (_type == 0) {
return false;
}
if (_rewardType == 0) {
return false;
}
if (_sex == 0) {
return false;
}
if (_appointDate == null) {
return false;
}
if (_contentController.text.isEmpty) {
return false;
}
if (_addressController.text.isEmpty) {
return false;
}
if (_rewardController.text.isEmpty) {
return false;
}
return true;
}
}

@ -0,0 +1,61 @@
import 'package:aku_new_community/constants/api.dart';
import 'package:aku_new_community/utils/network/net_util.dart';
class TaskFunc {
///
static Future<bool> publish(
{required String title,
required int taskType,
required int taskSex,
required int serviceObject,
required String taskContent,
required String taskDate,
required String taskAddress,
required int rewardType,
required String reward}) async {
var base = await NetUtil().post(API.manager.task.publish, params: {
'title': title,
'taskType': taskType,
'taskSex': taskSex,
'serviceObject': serviceObject,
'taskContent': taskContent,
'taskDate': taskDate,
'taskAddress': taskAddress,
'rewardType': rewardType,
'reward': int.parse(reward),
});
return base.status ?? false;
}
///
static Future<bool> cancel({
required int taskId,
}) async {
var base = await NetUtil().post(API.manager.task.cancel, params: {
'taskId': taskId,
});
return base.status ?? false;
}
///
static Future<bool> take({
required int taskId,
}) async {
var base = await NetUtil().post(API.manager.task.take, params: {
'taskId': taskId,
});
return base.status ?? false;
}
///
static Future<bool> finish({
required int taskId,
}) async {
var base = await NetUtil().post(API.manager.task.finish, params: {
'taskId': taskId,
});
return base.status ?? false;
}
}

@ -0,0 +1,26 @@
class TaskMap {
static Map<int, String> statusToString = {
1: '未接单',
2: '待处理',
3: '已完成',
4: '已取消'
};
static Map<int, String> typeToString = {1: '跑腿', 2: '代驾', 3: '装修', 4: '陪玩'};
static Map<int, String> serviceObject = {1: '住户', 2: '物业', 3: '不限'};
static Map<int, String> rewardType = {1: '赏金', 2: '积分'};
static Map<int, String> detailStatusToString = {
1: '已发布',
2: '待处理',
3: '已完成',
4: '已取消'
};
static Map<int, String> subStatus = {
1: '请耐心等待帮手领取任务',
2: '帮手正在为您服务中',
3: '帮手已完成任务',
4: '该任务已取消'
};
}

@ -0,0 +1,91 @@
import 'package:aku_new_community/ui/service/hall/hall_view.dart';
import 'package:aku_new_community/ui/service/my_take_task/my_take_task_view.dart';
import 'package:aku_new_community/ui/service/my_task/my_task_view.dart';
import 'package:aku_new_community/ui/service/publish_task_page.dart';
import 'package:aku_new_community/widget/bee_scaffold.dart';
import 'package:aku_new_community/widget/painter/tab_indicator.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:velocity_x/velocity_x.dart';
class TaskPage extends StatefulWidget {
const TaskPage({Key? key}) : super(key: key);
@override
_TaskPageState createState() => _TaskPageState();
}
class _TaskPageState extends State<TaskPage> with TickerProviderStateMixin {
late TabController _tabController;
List<String> _tabs = ['大厅', '我服务的', '我发布的'];
@override
void initState() {
_tabController = TabController(length: _tabs.length, vsync: this);
super.initState();
}
@override
Widget build(BuildContext context) {
return BeeScaffold(
title: '',
actions: [
IconButton(
onPressed: () {
Get.to(() => PublishTaskPage());
},
icon: Icon(
Icons.add_circle_outline,
size: 40.w,
color: Colors.black,
))
],
appBarBottom: PreferredSize(
preferredSize: Size.fromHeight(88.w),
child: Row(
children: [
..._tabs
.mapIndexed(
(currentValue, index) => _tabCard(currentValue, index))
.toList(),
],
)),
body: SafeArea(
child: TabBarView(controller: _tabController, children: [
HallView(),
MyTakeTaskView(),
MyTaskView(),
])),
);
}
Widget _tabCard(String title, int index) {
var select = index == _tabController.index;
return GestureDetector(
onTap: () {
_tabController.animateTo(index);
setState(() {});
},
child: Material(
color: Colors.transparent,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
title.text
.size(select ? 36.sp : 32.sp)
.fontWeight(select ? FontWeight.bold : FontWeight.normal)
.color(Colors.black.withOpacity(select ? 0.85 : 0.65))
.make(),
8.w.heightBox,
select ? TabIndicator() : 10.w.heightBox,
],
),
),
),
);
}
}

@ -0,0 +1,21 @@
import 'package:aku_new_community/widget/painter/tab_indicator_parinter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class TabIndicator extends StatelessWidget {
final double? width;
final double? height;
const TabIndicator({Key? key, this.width, this.height}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
width: width ?? 40.w,
height: height ?? 10.w,
child: CustomPaint(
painter: TabIndicatorPainter(),
),
);
}
}

@ -0,0 +1,27 @@
import 'package:aku_new_community/base/base_style.dart';
import 'package:flutter/material.dart';
class TabIndicatorPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = kPrimaryColor
..strokeCap = StrokeCap.round
..strokeWidth = 2
..style = PaintingStyle.stroke;
Path path = Path();
path.moveTo(0, 0);
path.quadraticBezierTo(size.width / 2, size.height, size.width, 0);
canvas.drawPath(path, paint);
}
@override
bool shouldRebuildSemantics(covariant CustomPainter oldDelegate) {
return false;
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
Loading…
Cancel
Save