需求说明:根据JSON数据来配置页面中的组件
数据部分:
[
{
"formId":"titleInput",
"genre":"schemeName",
"value":"高蛋白减重饮食方案",
"label":"名称",
"placeholder":"请输入方案名称",
"max":"",
"min":""
},
{
"formId":"assignTime",
"genre":"executionTime",
"type":"2",
"value":"0"
},
{
"formId":"checkBox",
"genre":"feedbackMode",
"label":"反馈方式",
"value":[
],
"options":[
{
"title":"打卡反馈",
"value":"clockInFeedback",
"enable":1,
"checked":1
},
{
"title":"图片反馈",
"value":"pictureFeedback",
"enable":1,
"checked":1
},
{
"title":"文字反馈",
"value":"textFeedback",
"enable":1,
"checked":1
},
{
"title":"视频反馈",
"value":"videoFeedback",
"enable":1,
"checked":1
},
{
"title":"记录饮食",
"value":"dietFeedback",
"enable":1,
"checked":1
},
{
"title":"记录运动",
"value":"exerciseFeedback",
"enable":0,
"checked":0
},
{
"title":"记录血糖",
"value":"sugarFeedback",
"enable":0,
"checked":0
},
{
"title":"记录血压/心率",
"value":"pressureFeedback",
"enable":0,
"checked":0
},
{
"title":"记录体重",
"value":"weightFeedback",
"enable":0,
"checked":0
},
{
"title":"记录睡眠",
"value":"sleepFeedback",
"enable":0,
"checked":0
},
{
"title":"记录用药",
"value":"drugFeedback",
"enable":0,
"checked":0
},
{
"title":"记录体温",
"value":"animalHeatFeedback",
"enable":0,
"checked":0
},
{
"title":"提交问卷",
"value":"questionnaireFeedback",
"enable":0,
"checked":0
}
]
},
{
"formId":"dietAdvice",
"genre":"dietAdvice",
"options":[
{
"itemName":"早餐",
"advice":"饮食要求:xxx",
"enable":1,
"checked":1,
"foodList":[
{
"foodName":"乳清蛋白粉",
"foodCount":"10",
"foodUnit":"克"
},
{
"foodName":"可溶性膳食纤维",
"foodCount":"10",
"foodUnit":"克"
},
{
"foodName":"温水",
"foodCount":"200",
"foodUnit":"毫升"
},
{
"foodName":"多种营养素制剂",
"foodCount":"1",
"foodUnit":"粒"
},
{
"foodName":"鱼油胶囊(1克)",
"foodCount":"1",
"foodUnit":"粒"
}
]
},
{
"itemName":"午餐",
"advice":"饮食要求:xxx ",
"enable":1,
"checked":1,
"foodList":[
{
"foodName":"主食(粗细搭配)",
"foodCount":"50",
"foodUnit":"克"
},
{
"foodName":"蛋白质类食物(瘦肉50克=1个鸡蛋或豆腐100克或豆干50克)",
"foodCount":"50",
"foodUnit":"克"
},
{
"foodName":"蔬菜(合计)",
"foodCount":"100",
"foodUnit":"克"
},
{
"foodName":"新鲜叶类蔬菜",
"foodCount":"50",
"foodUnit":"克"
},
{
"foodName":"新鲜菇类",
"foodCount":"50",
"foodUnit":"克"
}
]
},
{
"itemName":"晚餐",
"advice":"饮食要求:xxx ",
"enable":1,
"checked":1,
"foodList":[
{
"foodName":"主食(粗细搭配)",
"foodCount":"50",
"foodUnit":"克"
},
{
"foodName":"蛋白质类食物(瘦肉50克=1个鸡蛋或豆腐100克或豆干50克)",
"foodCount":"50",
"foodUnit":"克"
},
{
"foodName":"蔬菜(合计)",
"foodCount":"100",
"foodUnit":"克"
},
{
"foodName":"新鲜叶类蔬菜",
"foodCount":"50",
"foodUnit":"克"
},
{
"foodName":"新鲜菇类",
"foodCount":"50",
"foodUnit":"克"
},
{
"foodName":"多种营养素制剂",
"foodCount":"1",
"foodUnit":"粒"
},
{
"foodName":"鱼油胶囊(1克)",
"foodCount":"1",
"foodUnit":"粒"
}
]
}
]
},
{
"formId":"upload",
"genre":"imageTask",
"label":"图片任务",
"value":[
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fs1.sinaimg.cn%2Forignal%2F48ae37a6285f3d6e96840&refer=http%3A%2F%2Fs1.sinaimg.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1621837959&t=0bb081b98fe8ecaa89f3037dfcdbfa9b",
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_bt%2F0%2F13446502320%2F1000&refer=http%3A%2F%2Finews.gtimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1621838030&t=5e89a1bbbb62e2a491a64c9a0df4dcf9"
],
"uploadType":"image",
"minCount":"",
"maxCount":"",
"minSize":"",
"maxSize":""
},
{
"formId":"upload",
"genre":"videoTask",
"label":"视频任务",
"value":[
"https://vod.pule.com/6c992c3bvodcq1500003583/4b4fd9cc5285890813365762540/f0.mp4"
],
"uploadType":"video",
"minCount":"",
"maxCount":"",
"minSize":"",
"maxSize":""
},
{
"formId":"messageNotice",
"genre":"messageNotice",
"label":"消息通知",
"timeLabel":"发送时间",
"messageValue":"",
"timeValue":"",
"placeholder":"请输入通知内容",
"maxLine":"",
"maxCount":""
}
]
组件工厂:
import 'package:doctor_admin/pages/group/carePlan/schemeComponents/assignTime.dart';
import 'package:doctor_admin/pages/group/carePlan/schemeComponents/checkBox.dart';
import 'package:doctor_admin/pages/group/carePlan/schemeComponents/checkBoxWrap.dart';
import 'package:doctor_admin/pages/group/carePlan/schemeComponents/dietAdvice.dart';
import 'package:doctor_admin/pages/group/carePlan/schemeComponents/drugArray.dart';
import 'package:doctor_admin/pages/group/carePlan/schemeComponents/itemArray.dart';
import 'package:doctor_admin/pages/group/carePlan/schemeComponents/messageNotice.dart';
import 'package:doctor_admin/pages/group/carePlan/schemeComponents/radioBox.dart';
import 'package:doctor_admin/pages/group/carePlan/schemeComponents/textarea.dart';
import 'package:doctor_admin/pages/group/carePlan/schemeComponents/timePeriod.dart';
import 'package:doctor_admin/pages/group/carePlan/schemeComponents/titleInput.dart';
import 'package:doctor_admin/pages/group/carePlan/schemeComponents/upload.dart';
import 'package:flutter/material.dart';
componentFactor (config) {
if(config['formId'] == 'titleInput') {
var _key = GlobalKey<TitleInputState>();
return {
'widget': TitleInput(key: _key, config: config,),
'widgetName': 'titleInput',
'getResult': () => _key.currentState.result,
};
} else if (config['formId'] == 'assignTime') {
var _key = GlobalKey<AssignTimeState>();
return {
'widget': AssignTime(key: _key, config: config,),
'widgetName': 'assignTime',
'getResult': () => _key.currentState.result,
};
} else if (config['formId'] == 'checkBox') {
var _key = GlobalKey<CheckBoxState>();
return {
'widget': CheckBox(key: _key, config: config,),
'widgetName': 'checkBox',
'getResult': () => _key.currentState.result,
};
} else if (config['formId'] == 'checkBoxWrap') {
var _key = GlobalKey<CheckBoxWrapState>();
return {
'widget': CheckBoxWrap(key: _key, config: config,),
'widgetName': 'checkBoxWrap',
'getResult': () => _key.currentState.result,
};
} else if (config['formId'] == 'radio') {
var _key = GlobalKey<RadioBoxState>();
return {
'widget': RadioBox(key: _key, config: config,),
'widgetName': 'radio',
'getResult': () => _key.currentState.result,
};
} else if (config['formId'] == 'dietAdvice') {
var _key = GlobalKey<DietAdviceState>();
return {
'widget': DietAdvice(key: _key, config: config,),
'widgetName': 'checkBox',
'getResult': () => _key.currentState.result,
};
} else if (config['formId'] == 'textarea') {
var _key = GlobalKey<TextareaState>();
return {
'widget': Textarea(key: _key, config: config,),
'widgetName': 'textarea',
'getResult': () => _key.currentState.result,
};
} else if (config['formId'] == 'messageNotice') {
var _key = GlobalKey<MessageNoticeState>();
return {
'widget': MessageNotice(key: _key, config: config,),
'widgetName': 'messageNotice',
'getResult': () => _key.currentState.result,
};
} else if (config['formId'] == 'upload') {
var _key = GlobalKey<UploadState>();
return {
'widget': Upload(key: _key, config: config,),
'widgetName': 'upload',
'getResult': () => _key.currentState.result,
};
} else if (config['formId'] == 'itemArray') {
var _key = GlobalKey<ItemArrayState>();
return {
'widget': ItemArray(key: _key, config: config,),
'widgetName': 'itemArray',
'getResult': () => _key.currentState.result,
};
} else if (config['formId'] == 'drugArray') {
var _key = GlobalKey<DrugArrayState>();
return {
'widget': DrugArray(key: _key, config: config,),
'widgetName': 'drugArray',
'getResult': () => _key.currentState.result,
};
} else if (config['formId'] == 'timePeriod') {
var _key = GlobalKey<TimePeriodState>();
return {
'widget': TimePeriod(key: _key, config: config,),
'widgetName': 'timePeriod',
'getResult': () => _key.currentState.result,
};
}else {
return {
'widget': Center(child: Text('暂无对应组件', style: TextStyle(fontSize: 18, color: Color(0xff666666)),),),
};
}
}
根据数据生成组件:
workComponents(configJson) {
components = [];
configJson.forEach((value) {
components.add(componentFactor(value));
});
setState(() {});
}
渲染组件:
Column(
children: <Widget>[
for(int i = 0; i < components.length; i++) components[i]['widget'],
]
)
获取组件中的表单数据:
var result = [];
for(int i = 0; i < components.length; i++) {
if(components[i]['getResult'] != null) {
var value = components[i]['getResult']();
var tip = checkParams(value); // 检查数据是否完整
if(tip != 'success') {
showMsg(context, tip);
return;
}
result.add(value);
}
}
组件内容,这里例举其中1个:
import 'dart:convert';
import 'package:doctor_admin/config/common.dart';
import 'package:flutter/material.dart';
class TitleInput extends StatefulWidget {
final config;
TitleInput({Key key, @required this.config}):super(key: key);
TitleInputState createState() => TitleInputState();
}
class TitleInputState extends State<TitleInput> {
TextEditingController _ctrl =TextEditingController(text: '');
FocusNode _node = FocusNode();
var result;
@override
void initState() {
super.initState();
_ctrl = TextEditingController(text: widget.config['value']??'');
setState(() {
result = jsonDecode(jsonEncode(widget.config));
});
}
@override
Widget build(BuildContext context) {
return result == null ? SizedBox() : Container(
color: Color(0xffffffff),
margin: EdgeInsets.only(bottom: setSize(20)),
padding: EdgeInsets.fromLTRB(setSize(36), setSize(40), setSize(36), setSize(40)),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
result['label'].isEmpty ? SizedBox() : Container(
padding: EdgeInsets.symmetric(vertical: setSize(20)),
child: Text.rich(
TextSpan(
children: [
// TextSpan(text: '* ', style: TextStyle(color: Color(0xffF76565))),
TextSpan(text: result['label'], style: TextStyle(color: Color(0xff4c4c4c))),
]
),
style: TextStyle(fontSize: setFont(28)),
),
),
SizedBox(width: setSize(40)),
Expanded(
child: Container(
height: setSize(80),
decoration: BoxDecoration(
border: Border(bottom: BorderSide(width: setSize(1), color: Color(0xffe2e2e2))),
),
alignment: Alignment.centerLeft,
child: TextField(
style: TextStyle(fontSize: setFont(28), color: Color(0xff222222), fontWeight: FontWeight.w400, height: 1, textBaseline: TextBaseline.alphabetic),
scrollPadding: EdgeInsets.zero,
decoration: InputDecoration(
contentPadding: EdgeInsets.zero,
isDense: true,
border: InputBorder.none,
hintText: result['placeholder']??'',
hintStyle: TextStyle(fontSize: setFont(28), color: Color(0xffCCCCCC), height: 1, textBaseline: TextBaseline.alphabetic),
counterText: '',
),
controller: _ctrl,
focusNode: _node,
keyboardType: TextInputType.text,
autocorrect: false,
maxLength: ('${result['max']??''}').isEmpty ? 10000 : result['max'],
maxLines: 1,
textInputAction: TextInputAction.done,
onChanged: (value) => {
result['value'] = value
},
),
),
)
],
),
);
}
}