Commit 3d7a531d7384a70adb39bc5eba4928196dc604e8

Authored by weixin_45529955
1 parent 688b07fd

语音控制设置

... ... @@ -20,19 +20,19 @@ if (flutterRoot == null) {
def flutterVersionCode = "707"
def flutterVersionCode = "710"
if (flutterVersionCode == null) {
flutterVersionCode = '707'
flutterVersionCode = '710'
}
def flutterVersionName = "7.0.7"
def flutterVersionName = "7.1.0"
if (flutterVersionName == null) {
flutterVersionName = '7.0.7'
flutterVersionName = '7.1.0'
}
... ...
/**
* 商家语音欢迎致辞配置
* 对应接口:App.Seller.GetVoiceWelcomeConfig / App.Seller.SaveVoiceWelcomeConfig
*/
class VoiceWelcomeConfigModel {
String? isVoiceWelcome; //是否开启语音欢迎致辞 0/1
String? welcomeContent; //预订人语音欢迎致辞模板
String? inviteeSameAsReserver; //被请人播报是否与预订人一致 0/1
String? inviteeDefaultContent; //被请人默认语音欢迎致辞模板
String? inviteeSpecialContent; //被请人特殊用餐类型语音欢迎致辞模板
String? isInviteeSpecialEnabled; //是否启用特殊用餐类型语音播报 0/1
List<String>? specialReserveTypes; //已选特殊用餐类型
List<String>? reserveTypeOptions; //全部用餐类型选项
List<VoiceWelcomePlaceholderModel>? placeholderButtons; //可变字段按钮
VoiceWelcomeConfigModel(
{this.isVoiceWelcome,
this.welcomeContent,
this.inviteeSameAsReserver,
this.inviteeDefaultContent,
this.inviteeSpecialContent,
this.isInviteeSpecialEnabled,
this.specialReserveTypes,
this.reserveTypeOptions,
this.placeholderButtons});
VoiceWelcomeConfigModel.fromJson(Map<String, dynamic> json) {
isVoiceWelcome = json['is_voice_welcome']?.toString();
welcomeContent = json['welcome_content']?.toString();
inviteeSameAsReserver = json['invitee_same_as_reserver']?.toString();
inviteeDefaultContent = json['invitee_default_content']?.toString();
inviteeSpecialContent = json['invitee_special_content']?.toString();
isInviteeSpecialEnabled =
json['is_invitee_special_enabled']?.toString();
if (json['special_reserve_types'] is List) {
specialReserveTypes = (json['special_reserve_types'] as List)
.map((e) => e.toString())
.toList();
}
if (json['reserve_type_options'] is List) {
reserveTypeOptions =
(json['reserve_type_options'] as List).map((e) => e.toString()).toList();
}
if (json['placeholder_buttons'] is List) {
placeholderButtons = [];
(json['placeholder_buttons'] as List).forEach((v) {
placeholderButtons!.add(
VoiceWelcomePlaceholderModel.fromJson(v as Map<String, dynamic>));
});
}
}
}
///可变字段按钮(如 年月日 -> {预订日期})
class VoiceWelcomePlaceholderModel {
String? name;
String? placeholder;
VoiceWelcomePlaceholderModel({this.name, this.placeholder});
VoiceWelcomePlaceholderModel.fromJson(Map<String, dynamic> json) {
name = json['name']?.toString();
placeholder = json['placeholder']?.toString();
}
}
... ...
... ... @@ -507,6 +507,11 @@ class HttpUrl {
static const String get_reserve_type_field =
"?service=App.Seller.GetReserveTypeField"; // 获取用餐类型
static const String get_voice_welcome_config =
"?service=App.Seller.GetVoiceWelcomeConfig"; //获取商家语音欢迎致辞配置
static const String save_voice_welcome_config =
"?service=App.Seller.SaveVoiceWelcomeConfig"; //保存商家语音欢迎致辞配置
static const String set_reserve_deposit =
"?service=App.Reserve.SetReserveDeposit"; // 取消订单设置订金走向
... ...
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:one_key/constant/constant.dart';
import 'package:one_key/models/get_reserve_type_field_model.dart';
import 'package:one_key/models/voice_welcome_config_model.dart';
import 'package:one_key/net/base_resp.dart';
import 'package:one_key/net/dio_util.dart';
import 'package:one_key/net/http_url.dart';
import 'package:one_key/provider/user_model.dart';
import 'package:one_key/res/colors.dart';
import 'package:one_key/utils/screen_util.dart';
import 'package:one_key/utils/utils.dart';
import 'package:one_key/widgets/MyDivider.dart';
import 'package:one_key/widgets/round_button.dart';
import 'package:one_key/widgets/system_app_bar.dart';
import 'package:one_key/widgets/v_empty_view.dart';
import 'package:provider/provider.dart';
/***
* 语音欢迎致辞设置
*/
class VoiceWelcomeSettingPage extends StatefulWidget {
VoiceWelcomeSettingPage({Key? key}) : super(key: key);
@override
_VoiceWelcomeSettingPageState createState() =>
_VoiceWelcomeSettingPageState();
}
class _VoiceWelcomeSettingPageState extends State<VoiceWelcomeSettingPage> {
bool addVoiceInfo = false; //预订安排中附加语音欢迎致辞
bool guestVoiceSame = true; //被请人语音播报与预订人一致
bool specialVoiceEnabled = false; //是否启用特殊用餐类型语音播报
TextEditingController voiceIncoC = TextEditingController(); //预订人语音播报
TextEditingController guestDefaultC = TextEditingController(); //被请人默认
TextEditingController guestSpecialC = TextEditingController(); //被请人特殊
FocusNode voiceIncoNode = FocusNode();
FocusNode guestDefaultNode = FocusNode();
FocusNode guestSpecialNode = FocusNode();
List<VoiceWelcomePlaceholderModel> changeFieldData = []; //可变字段标签
List<GetReserveTypeFieldsSunModel>? mealTypes = []; //用餐类型
bool mealTypesError = false; //用餐类型接口加载失败
static const String defaultVoiceText =
'尊敬的贵宾,您好!\n欢迎您选择本店。\n您的就餐安排在{预订日期},{餐段},坐席位于{桌位}。\n预祝您用餐愉快,期待您的光临!';
@override
void initState() {
super.initState();
voiceIncoC.text = defaultVoiceText;
guestDefaultC.text = defaultVoiceText;
guestSpecialC.text = defaultVoiceText;
WidgetsBinding.instance.addPostFrameCallback((_) {
_getData();
});
}
@override
void dispose() {
voiceIncoC.dispose();
guestDefaultC.dispose();
guestSpecialC.dispose();
voiceIncoNode.dispose();
guestDefaultNode.dispose();
guestSpecialNode.dispose();
super.dispose();
}
_getData() async {
try {
String? sid =
Provider.of<UserModel>(context, listen: false).user?.sellerid;
BaseResp<dynamic> baseResp = await DioUtil().request<dynamic>(
context, Method.post, HttpUrl.get_voice_welcome_config,
data: {'sid': sid}, showLoading: false);
if (baseResp.code == Constant.status_success &&
baseResp.data != null &&
baseResp.data is Map) {
VoiceWelcomeConfigModel model = VoiceWelcomeConfigModel.fromJson(
baseResp.data as Map<String, dynamic>);
addVoiceInfo = model.isVoiceWelcome == '1' ? true : false;
guestVoiceSame =
model.inviteeSameAsReserver == '1' ? true : false;
voiceIncoC.text = (model.welcomeContent != null &&
model.welcomeContent!.isNotEmpty)
? model.welcomeContent!
: defaultVoiceText;
guestDefaultC.text = (model.inviteeDefaultContent != null &&
model.inviteeDefaultContent!.isNotEmpty)
? model.inviteeDefaultContent!
: defaultVoiceText;
guestSpecialC.text = (model.inviteeSpecialContent != null &&
model.inviteeSpecialContent!.isNotEmpty)
? model.inviteeSpecialContent!
: defaultVoiceText;
specialVoiceEnabled =
model.isInviteeSpecialEnabled == '1' ? true : false;
//可变字段按钮
changeFieldData = model.placeholderButtons ?? [];
//用餐类型及已选状态
mealTypes = [];
model.reserveTypeOptions?.forEach((v) {
GetReserveTypeFieldsSunModel temp =
GetReserveTypeFieldsSunModel(name: v, select: false);
if (model.specialReserveTypes != null &&
model.specialReserveTypes!.contains(v)) {
temp.select = true;
}
mealTypes!.add(temp);
});
mealTypesError = false;
} else {
mealTypesError = true;
if (baseResp.msg != null && baseResp.msg!.isNotEmpty) {
Utils.showToast(baseResp.msg!);
}
}
} catch (error) {
print(error.toString());
mealTypesError = true;
}
if (mounted) {
setState(() {});
}
}
///在光标处插入可变字段
_insertField(
TextEditingController controller, VoiceWelcomePlaceholderModel field) {
FocusScope.of(context).requestFocus(FocusNode()); //隐藏键盘
int cursorPosition = controller.selection.baseOffset;
if (cursorPosition != -1) {
controller.text = controller.text.substring(0, cursorPosition) +
(field.placeholder ?? '') +
controller.text.substring(cursorPosition);
controller.selection = TextSelection.fromPosition(
TextPosition(
offset: cursorPosition + field.placeholder!.length,
affinity: TextAffinity.downstream));
} else {
controller.text += field.placeholder ?? '';
}
setState(() {});
}
///可变字段标签(全部青绿实底白字)
Widget _fieldChip(
TextEditingController controller, VoiceWelcomePlaceholderModel field) {
return InkWell(
onTap: () {
_insertField(controller, field);
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: w(8), vertical: w(5)),
decoration: BoxDecoration(
color: MyColours.color_529EA4,
borderRadius: BorderRadius.circular(r(5)),
),
child: Text(
field.name!,
style: TextStyle(
color: MyColours.color_ffffff,
fontSize: font(12),
fontWeight: FontWeight.bold),
),
),
);
}
Widget _chipsWrap(
TextEditingController controller, List<VoiceWelcomePlaceholderModel> data) {
return Padding(
padding: EdgeInsets.only(left: w(30)),
child: Wrap(
spacing: w(10),
runSpacing: w(10),
children:
data.map((e) => _fieldChip(controller, e)).toList(),
),
);
}
Widget _sectionHeader(String title, {double? left}) {
return Padding(
padding: EdgeInsets.only(left: left ?? w(16)),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
title,
style: TextStyle(
color: MyColours.color_666666,
fontSize: font(12)),
),
),
);
}
///特殊用餐类型标题行(右侧带启用复选框)
Widget _specialHeader() {
return InkWell(
onTap: () {
setState(() {
specialVoiceEnabled = !specialVoiceEnabled;
});
},
child: Padding(
padding: EdgeInsets.only(left: w(30), right: w(16)),
child: Row(
children: [
Expanded(
child: Text(
'被请人语音播报设置(特殊用餐类型)',
style: TextStyle(
color: MyColours.color_666666, fontSize: font(12)),
),
),
Image.asset(
Utils.getImgPath(
specialVoiceEnabled ? 'f_select' : 'f_select_not'),
width: w(22),
),
],
),
),
);
}
Widget _divider() {
return Padding(
padding: EdgeInsets.only(left: w(16), right: w(12)),
child: MyDivider(double.infinity, w(0.5),
color: MyColours.color_E7E7E7),
);
}
Widget _textArea(TextEditingController controller, String hint) {
return Container(
width: double.infinity,
margin: EdgeInsets.symmetric(horizontal: w(30)),
padding: EdgeInsets.symmetric(horizontal: w(10), vertical: w(10)),
alignment: Alignment.topLeft,
decoration: BoxDecoration(
color: MyColours.color_ffffff,
border: Border.all(color: MyColours.color_DBDBDB, width: w(1)),
borderRadius: BorderRadius.circular(r(10)),
),
child: TextField(
controller: controller,
style: TextStyle(
color: MyColours.color_777777,
fontSize: font(14),
textBaseline: TextBaseline.alphabetic),
textAlignVertical: TextAlignVertical.center,
maxLines: 7,
decoration: InputDecoration(
hintText: hint,
hintStyle: TextStyle(
color: MyColours.color_999999,
fontSize: font(14),
),
contentPadding: EdgeInsets.zero,
border: OutlineInputBorder(borderSide: BorderSide.none),
),
keyboardType: TextInputType.multiline,
),
);
}
Widget _hintText() {
return Padding(
padding: EdgeInsets.only(left: w(30)),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
'*{预订日期}、{餐段}、{桌位}不能修改,可以删除。',
style: TextStyle(color: MyColours.color_B0B0B0, fontSize: font(12)),
),
),
);
}
Widget _radioRow(String title, bool selected, VoidCallback onTap) {
return InkWell(
onTap: onTap,
child: Container(
width: double.infinity,
padding: EdgeInsets.only(
left: w(16), right: w(16), top: w(20), bottom: w(20)),
child: Row(
children: [
Expanded(
child: Text(
title,
style: TextStyle(
color: MyColours.color_666666, fontSize: font(14)),
),
),
Image.asset(
Utils.getImgPath(selected ? 'f_radio_sel' : 'f_radio_un'),
width: w(20),
),
],
),
),
);
}
Widget _mealChipsWrap() {
if (mealTypes == null || mealTypes!.isEmpty) {
return InkWell(
onTap: () {
_getData();
},
child: Padding(
padding: EdgeInsets.only(left: w(30)),
child: Row(
children: [
Text(
'暂无用餐类型数据,点击重试',
style: TextStyle(
color: MyColours.color_666666, fontSize: font(12)),
),
],
),
),
);
}
return Padding(
padding: EdgeInsets.only(left: w(30)),
child: Wrap(
spacing: w(10),
runSpacing: w(10),
children: mealTypes!.map((item) {
bool selected = item.select ?? false;
return InkWell(
onTap: () {
setState(() {
item.select = !selected;
});
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: w(10), vertical: w(5)),
decoration: BoxDecoration(
color: selected
? MyColours.color_529EA4
: MyColours.color_ffffff,
borderRadius: BorderRadius.circular(r(5)),
border: Border.all(
width: w(1),
color: selected
? MyColours.color_529EA4
: MyColours.color_B7B7B7),
),
child: Text(
item.name ?? '',
style: TextStyle(
color: selected
? MyColours.color_ffffff
: MyColours.color_B0B0B0,
fontSize: font(12),
),
),
),
);
}).toList(),
),
);
}
_save() async {
if (addVoiceInfo && voiceIncoC.text.trim().isEmpty) {
Utils.showToast('请输入语音欢迎致辞!');
return;
}
List<String> selectedMealTypes = [];
mealTypes?.forEach((item) {
if (item.select ?? false) {
selectedMealTypes.add(item.name ?? '');
}
});
Map<String, String?> params = {
'sid': Provider.of<UserModel>(context, listen: false).user?.sellerid,
'is_voice_welcome': addVoiceInfo ? '1' : '0',
'welcome_content': voiceIncoC.text,
'invitee_same_as_reserver': guestVoiceSame ? '1' : '0',
'invitee_default_content': guestDefaultC.text,
'invitee_special_content': guestSpecialC.text,
'special_reserve_types': json.encode(selectedMealTypes),
'is_invitee_special_enabled': specialVoiceEnabled ? '1' : '0',
};
try {
BaseResp<dynamic> baseResp = await DioUtil().request<dynamic>(
context, Method.post, HttpUrl.save_voice_welcome_config,
data: params, showLoading: true);
if (baseResp.code == Constant.status_success) {
Utils.showToast('保存成功');
if (Navigator.canPop(context)) {
Navigator.pop(context);
}
} else {
if (baseResp.msg != null && baseResp.msg!.isNotEmpty) {
Utils.showToast(baseResp.msg!);
}
}
} catch (error) {
print(error.toString());
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: MyColours.color_ffffff,
appBar: SystemAppBar('语音欢迎致辞设置'),
body: Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//预订安排中附加语音欢迎致辞
InkWell(
onTap: () {
setState(() {
addVoiceInfo = !addVoiceInfo;
});
},
child: Container(
width: double.infinity,
margin: EdgeInsets.only(left: w(16), right: w(16)),
padding:
EdgeInsets.symmetric(vertical: w(24)),
child: Row(
children: [
Text(
'预订安排中附加语音欢迎致辞',
style: TextStyle(
color: MyColours.color_666666,
fontSize: font(16)),
),
Spacer(),
Image.asset(
Utils.getImgPath(
addVoiceInfo ? 'swich_on' : 'swich_off'),
width: w(44),
),
],
),
),
),
_divider(),
if (addVoiceInfo) ...[
VEmptyView(8),
_sectionHeader('预订人语音播报设置'),
VEmptyView(16),
_textArea(voiceIncoC, '点击录入语音欢迎致辞'),
VEmptyView(16),
_hintText(),
VEmptyView(16),
_chipsWrap(voiceIncoC, changeFieldData),
VEmptyView(24),
_divider(),
VEmptyView(24),
_sectionHeader('被请人语音播报设置'),
VEmptyView(24),
_radioRow('被请人语音播报与预订人一致', guestVoiceSame, () {
setState(() {
guestVoiceSame = true;
});
}),
_divider(),
_radioRow('被请人语音播报与预订人不一致', !guestVoiceSame, () {
setState(() {
guestVoiceSame = false;
});
}),
if (!guestVoiceSame) ...[
_divider(),
VEmptyView(16),
_sectionHeader('被请人语音播报设置(默认)', left: w(30)),
VEmptyView(16),
_textArea(guestDefaultC, '点击录入被请人语音播报'),
VEmptyView(16),
_hintText(),
VEmptyView(16),
_chipsWrap(guestDefaultC, changeFieldData),
VEmptyView(24),
_specialHeader(),
if (specialVoiceEnabled) ...[
VEmptyView(16),
_textArea(guestSpecialC, '点击录入特殊用餐类型语音播报'),
VEmptyView(16),
_hintText(),
VEmptyView(16),
_chipsWrap(guestSpecialC, changeFieldData),
VEmptyView(24),
Padding(
padding: EdgeInsets.only(left: w(30)),
child: Text(
'请选择该语音播报适用的用餐类型',
style: TextStyle(
color: MyColours.color_666666,
fontSize: font(12)),
),
),
VEmptyView(16),
_mealChipsWrap(),
],
],
VEmptyView(32),
],
],
),
),
),
Container(
color: MyColours.color_ffffff,
padding: EdgeInsets.only(
left: w(24), right: w(24), top: w(12), bottom: w(25)),
child: RoundButton(
text: '保存',
gradientStart: MyColours.color_529EA4,
gradientEnd: MyColours.color_529EA4,
radius: r(5),
fontSize: 34,
height: w(40),
isBold: true,
onPressed: () {
_save();
},
),
),
],
),
);
}
}
... ...
... ... @@ -600,6 +600,9 @@ class _CustomerNoticeSettingPageState extends State<CustomerNoticeSettingPage> {
_item('预订信息模块设置', onTap: () {
NavigatorUtil.goBookInfoPage(context);
}),
_item('语音欢迎致辞设置', onTap: () {
NavigatorUtil.goVoiceWelcomeSettingPage(context);
}),
_item('店铺介绍模块设置', onTap: () {
NavigatorUtil.goStoreIntroducePage(context);
}),
... ...
... ... @@ -168,4 +168,5 @@ class MyColours {
static const Color color_BA9953 = Color(0xffBA9953);
static const Color color_D7F7F7 = Color(0xffD7F7F7);
static const Color color_2AB5B7 = Color(0xff2AB5B7);
static const Color color_529EA4 = Color(0xff529EA4);
}
... ...
... ... @@ -1702,6 +1702,15 @@ class NavigatorUtil {
return _navigateTo(context, "${Routes.book_info_page}", replace: replace);
}
///预订安排通知定制------语音欢迎致辞设置
static Future<dynamic> goVoiceWelcomeSettingPage(
BuildContext context, {
replace = false,
}) {
return _navigateTo(context, "${Routes.voice_welcome_setting_page}",
replace: replace);
}
///预订安排通知定制------预订信息展示
static Future<dynamic> goBookInfoPageSim(
BuildContext context, {
... ...
... ... @@ -265,6 +265,7 @@ import '../pages/my/marketing_center/book_notification/first_image_page.dart';
import '../pages/my/marketing_center/book_notification/marking_coupon_select_page.dart';
import '../pages/my/marketing_center/book_notification/marking_preview_page.dart';
import '../pages/my/marketing_center/book_notification/marking_recharge_select_page.dart';
import '../pages/my/marketing_center/book_notification/voice_welcome_setting_page.dart';
import '../pages/my/marketing_center/book_notification/park_info_page.dart';
import '../pages/my/marketing_center/book_notification/store_introduce_page.dart';
import '../pages/my/marketing_center/comments_setting_page.dart';
... ... @@ -3195,8 +3196,14 @@ var storeIntroducePageHandle = new Handler(
// .decode(FluroConvertUtils.fluroCnParamsDecode(params["detail"].first)));
return ChangeNotifierProvider<MarketingCenterProvider>(
create: (_) => MarketingCenterProvider(),
child: ChangeNotifierProvider<StoreBaseIndoProvider>(
create: (_) => StoreBaseIndoProvider(), child: StoreIntroducePage()));
child: ChangeNotifierProvider<StoreBaseIndoProvider>(
create: (_) => StoreBaseIndoProvider(), child: StoreIntroducePage()));
});
//我的----营销中心-语音欢迎致辞设置
var voiceWelcomeSettingPageHandle = new Handler(
handlerFunc: (BuildContext? context, Map<dynamic, List<Object>> params) {
return VoiceWelcomeSettingPage();
});
//我的----营销中心-主厨介绍
... ...
... ... @@ -240,6 +240,8 @@ class Routes {
static String book_info_page = "/book_info_page"; //预订安排通知定制------预订信息展示
static String book_info_page_sim =
"/book_info_page_sim"; //预订安排通知定制------预订信息展示
static String voice_welcome_setting_page =
"/voice_welcome_setting_page"; //预订安排通知定制------语音欢迎致辞设置
static String store_introduce_page =
"/store_introduce_page"; //预订安排通知定制------店铺介绍
... ... @@ -707,6 +709,8 @@ class Routes {
router.define(book_info_page, handler: bookInfoPageHandle);
router.define(book_info_page_sim, handler: bookInfoPageSimHandle);
router.define(voice_welcome_setting_page,
handler: voiceWelcomeSettingPageHandle);
router.define(store_introduce_page, handler: storeIntroducePageHandle);
router.define(chef_introduce_page, handler: chefIntroducePageHandle);
... ...