新建 SterilizeWholeBoardPage 空页面
class SterilizeWholeBoardPageViewModel: BaseViewModel {
}
struct SterilizeWholeBoardPage: View {
@StateObject private var viewModel = SterilizeWholeBoardPageViewModel()
var body: some View {
PageContentView(title: "灭菌整板", viewModel: viewModel) {
EmptyView()
}
.makeToDetailPage()
}
}
添加 【灭菌批号】【栈版号】【箱号】
class SterilizeWholeBoardPageViewModel: BaseViewModel {
/// 灭菌批号
@Published var sterilizationLotNumber:String = ""
/// 栈版号
@Published var stackVersionNumber:String = ""
/// 箱号
@Published var caseNumber:String = ""
}
struct SterilizeWholeBoardPage: View {
...
var body: some View {
PageContentView(title: "灭菌整板", viewModel: viewModel) {
VStack(spacing: 0) {
Spacer()
.frame(height: 5)
VStack(spacing: 0) {
ScanTextView(title: "灭菌批号",
prompt: "请输入灭菌批号",
text: $viewModel.sterilizationLotNumber)
Divider()
.padding(.leading, 10)
ScanTextView(title: "栈版号",
prompt: "请输入栈版号",
text: $viewModel.stackVersionNumber)
Divider()
.padding(.leading, 10)
ScanTextView(title: "箱号",
prompt: "请输入箱号",
text: $viewModel.caseNumber)
}
.background(.white)
Spacer()
}
}
...
}
}
添加 【栈板序号】【物料总体积】【箱数】
struct SterilizeWholeBoardPage: View {
...
var body: some View {
PageContentView(title: "灭菌整板", viewModel: viewModel) {
VStack(spacing: 0) {
...
...
VStack {
HStack(spacing: 0) {
Text("栈板序号")
.frame(width: 100, alignment: .leading)
Text("1")
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(EdgeInsets(top: 15, leading: 22, bottom: 15, trailing: 22))
Divider()
.padding(.leading, 10)
VStack(spacing: 10) {
HStack(spacing: 0) {
Text("物料总体积")
.frame(width: 100, alignment: .leading)
Text("120.86 m³")
}
.frame(maxWidth: .infinity, alignment: .leading)
HStack(spacing: 0) {
Text("箱数")
.frame(width: 100, alignment: .leading)
Text("12")
}
.frame(maxWidth: .infinity, alignment: .leading)
}
.padding(EdgeInsets(top: 15, leading: 22, bottom: 15, trailing: 22))
}
...
}
}
...
}
}
使用 environment 规范 Title 文本的宽度
.frame(width: 100, alignment: .leading)
大量这种代码我们实在受够了,一个页面如果很多元素,或者其他界面一样的这种对齐呢?不过我们可以通过 environment 进行设置。
新增 TitleWidthEnvironmentKey
struct TitleWidthEnvironmentKey: EnvironmentKey {
/// 设置默认为100
static var defaultValue: CGFloat = 100
}
给 EnvironemtValues 扩展属性 titleWidth
extension EnvironmentValues {
var titleWidth: CGFloat {
get { self[TitleWidthEnvironmentKey.self] }
set { self[TitleWidthEnvironmentKey.self] = newValue }
}
}
将 ScanTextView 中的宽度限制 修改为 titleWidth
struct ScanTextView: View {
...
/// 默认为 100
@Environment(\.titleWidth) private var titleWidth:CGFloat
init(title:String, prompt:String, text:Binding<String>) {
...
}
...
}
封装组件 LimitLeadingWidthView
struct LimitLeadingWidthView<Leading:View, Treading:View>: View {
@Environment(\.titleWidth) private var leadingLimitWidth:CGFloat
private let leading:Leading
private let treading:Treading
init(@ViewBuilder leading:() -> Leading, @ViewBuilder treading:() -> Treading) {
self.leading = leading()
self.treading = treading()
}
var body: some View {
HStack(spacing: 0) {
leading
.frame(width: leadingLimitWidth, alignment: .leading)
treading
.frame(maxWidth: .infinity, alignment: .leading)
}
.frame(maxWidth: .infinity, alignment: .leading)
}
}
struct LimitLeadingWidthView_Previews: PreviewProvider {
static var previews: some View {
LimitLeadingWidthView(leading: {
Text("我是左侧文本")
}, treading: {
Text("我是右侧文本")
})
.previewLayout(.sizeThatFits)
}
}
将【栈板序号】【物料总体积】【箱数】更换为 LimitLeadingWidthView 组件
struct SterilizeWholeBoardPage: View {
...
var body: some View {
PageContentView(title: "灭菌整板", viewModel: viewModel) {
VStack(spacing: 0) {
...
VStack {
LimitLeadingWidthView(leading: {
Text("栈板序号")
}, treading: {
Text("1")
})
...
VStack(spacing: 10) {
LimitLeadingWidthView {
Text("物料总体积")
} treading: {
Text("120.86 m³")
}
LimitLeadingWidthView {
Text("箱数")
} treading: {
Text("12")
}
}
...
}
...
}
}
...
}
}
将 ScanTextView 内部使用 LimitLeadingWidthView 组件
struct ScanTextView: View {
...
var body: some View {
LimitLeadingWidthView {
HStack {
Text("*")
.foregroundColor(Color(uiColor: appColor.c_e68181))
Text(title)
Spacer()
}
} treading: {
HStack {
TextField(prompt, text: $text)
.frame(height:33)
Image("scan_icon", bundle: .main)
}
}
...
}
}
扩展 View 新增 limitLeadingWidth 方法
虽然默认值100已经在当前页面足够的展示左侧的内容,我们想要在当前页面根本修改全部LimitLeadingWidthView左侧宽度为110。
z
struct SterilizeWholeBoardPage: View {
...
var body: some View {
PageContentView(title: "灭菌整板", viewModel: viewModel) {
...
}
.environment(\.titleWidth, 110)
}
}
对于.environment(\.titleWidth, 110)这样的方式不是很优雅,使用者还要关心对应Key是什么?我们可以给View做一下扩展。
extension View {
func limitLeadingWidth(_ width:CGFloat) -> some View {
self.environment(\.titleWidth, width)
}
}
此时我们上面的代码就可以变成下面
struct SterilizeWholeBoardPage: View {
...
var body: some View {
PageContentView(title: "灭菌整板", viewModel: viewModel) {
...
}
.limitLeadingWidth(110)
}
}
这样的写法可以明确用意。
获取栈板序号
栈板序号的值来源于通过灭菌批号查询。
新增 @Published 栈板序号用于更新页面
class SterilizeWholeBoardPageViewModel: BaseViewModel {
...
/// 栈板序号
@Published var palletSerialNumber:String = ""
}
根据【灭菌批号】获取【栈板序号】
class SterilizeWholeBoardPageViewModel: BaseViewModel {
...
/// 请求栈板序号
func requestPalletNumber() async {
guard !sterilizationLotNumber.isEmpty else {
showHUDMessage(message: "灭菌批号为空!")
return
}
let api = GetSterilizationSequenceApi(sterilizeBatch: sterilizationLotNumber)
let model:BaseModel<Int> = await request(api: api)
guard model._isSuccess, let data = model.data else {
return
}
palletNumber = "\(data)"
}
}
输入完毕【灭菌批号】获取【栈板序号】
struct SterilizeWholeBoardPage: View {
...
var body: some View {
PageContentView(title: "灭菌整板", viewModel: viewModel) {
VStack(spacing: 0) {
...
VStack(spacing: 0) {
ScanTextView(title: "灭菌批号",
prompt: "请输入灭菌批号",
text: $viewModel.sterilizationLotNumber)
.onSubmit {
Task {
await viewModel.requestPalletNumber()
}
}
...
}
...
}
}
...
}
}
设置 TabBar 的背景颜色
突然发现,我们的TabrBar变成了这个样子,应该是我们修改SafeArea导致的。
struct TabPage: View {
...
init() {
...
UITabBar.appearance().backgroundColor = .white
}
...
}
获取【物料总体积】【箱数】
继承 PalletBindBoxNumberPageViewModel
物料总体积和箱数来源于根据栈版号获取的箱子列表拿到的数据。这个页面输入栈版号和箱号是一样的逻辑,我们不如将SterilizeWholeBoardPageViewModel继承于PalletBindBoxNumberPageViewModel。
class SterilizeWholeBoardPageViewModel: PalletBindBoxNumberPageViewModel {
/// 灭菌批号
@Published var sterilizationLotNumber:String = ""
/// 栈板序号
@Published var palletSerialNumber:String = ""
....
}
struct SterilizeWholeBoardPage: View {
...
var body: some View {
PageContentView(title: "灭菌整板", viewModel: viewModel) {
VStack(spacing: 0) {
...
VStack(spacing: 0) {
...
ScanTextView(title: "栈版号",
prompt: "请输入栈版号",
text: $viewModel.palletNumber)
...
ScanTextView(title: "箱号",
prompt: "请输入箱号",
text: $viewModel.boxNumber)
}
...
VStack {
LimitLeadingWidthView(leading: {
Text("栈板序号")
}, treading: {
Text(viewModel.palletSerialNumber)
})
...
}
}
...
}
}
新增 @Published 变量显示【箱号总体积】【箱数】
class SterilizeWholeBoardPageViewModel: PalletBindBoxNumberPageViewModel {
...
/// 总体积
@Published var totalCapacity:String = ""
/// 箱数
@Published var totalBox:String = ""
...
}
因为箱子总体积和箱数的数据来源于单条的BoxDetailModel里面的数据,我们监听boxDetailModels的变化,获取第一条元素进行获取。
class SterilizeWholeBoardPageViewModel: PalletBindBoxNumberPageViewModel {
...
/// 存储 Publisher 取消
private var cancellabels:Set<AnyCancellable> = []
override init() {
super.init()
$boxDetailModels.sink {[weak self] models in
guard let self = self else {return}
self.totalCapacity = models.first.flatMap({$0.volume}).map({"\($0)"}) ?? ""
self.totalBox = models.first.flatMap({$0.total}).map({"\($0)"}) ?? ""
}
.store(in: &cancellabels)
}
...
}
查询栈板箱子列表和新增删除箱号
struct SterilizeWholeBoardPage: View {
...
var body: some View {
PageContentView(title: "灭菌整板", viewModel: viewModel) {
VStack(spacing: 0) {
...
VStack(spacing: 0) {
...
ScanTextView(title: "栈版号",
prompt: "请输入栈版号",
text: $viewModel.palletNumber)
.onSubmit {
Task {
await viewModel.requestBoxDetailList()
}
}
...
ScanTextView(title: "箱号",
prompt: "请输入箱号",
text: $viewModel.boxNumber)
.onSubmit {
Task {
await viewModel.addOrRemoveBox()
}
}
}
...
}
}
...
}
}
提炼箱号列表
灭菌整板箱子列表和托盘绑定箱号的箱子列表是一样的,所以,我们可以将灭菌整板的箱子列表进行提炼。
struct BoxListView: View {
private let models:[BoxDetailModel]
init(models:[BoxDetailModel]) {
self.models = models
}
var body: some View {
List {
ForEach(models) { model in
BoxDetailView(model: model)
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 5, trailing: 0))
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
}
}
.listStyle(.plain)
}
}
修改托盘绑定箱号页面
struct PalletBindBoxNumberPage: View {
...
var body: some View {
PageContentView(title: "托盘绑定箱号", viewModel: viewModel) {
VStack(spacing:0) {
...
BoxListView(models: viewModel.boxDetailModels)
}
}
...
}
}
灭菌整板页面新增BoxListView
struct SterilizeWholeBoardPage: View {
...
var body: some View {
PageContentView(title: "灭菌整板", viewModel: viewModel) {
VStack(spacing: 0) {
...
Spacer()
.frame(height: 10)
BoxListView(models: viewModel.boxDetailModels)
}
}
...
}
}
添加 【重置】 【提交】按钮
打印需要调用蓝牙和硬件交互,我们就把打印替换成重置
封装 TextButton
在登录页面,我们有一个类似的登录按钮,决定按照登录按钮的样式封装按钮,方便后面的使用。
struct TextButton: View {
@StateObject private var appColor = AppColor.share
private let title:String
private let action:() -> Void
init(title:String, action:@escaping () -> Void) {
self.title = title
self.action = action
}
var body: some View {
Button(action: action) {
Text(title)
.font(.system(size: 16))
.frame(maxWidth:.infinity)
.frame(height: 45)
.background(Color(uiColor: appColor.c_209090))
.foregroundColor(.white)
.cornerRadius(5)
}
}
}
struct TextButton_Previews: PreviewProvider {
static var previews: some View {
TextButton(title: "登录", action: {})
.previewLayout(.sizeThatFits)
}
}
通过 TextButton 添加 【重置】【提交】
通过 Stack 进行叠加布局
struct SterilizeWholeBoardPage: View {
...
var body: some View {
PageContentView(title: "灭菌整板", viewModel: viewModel) {
ZStack {
...
VStack {
Spacer()
HStack {
TextButton(title: "重置") {
}
TextButton(title: "提交") {
}
}
.padding()
}
}
}
...
}
}
重置界面数据
点击重置按钮需要将界面所有的数据清空,界面恢复到刚打开的状态。
class SterilizeWholeBoardPageViewModel: PalletBindBoxNumberPageViewModel {
...
func reset() {
sterilizationLotNumber = ""
palletSerialNumber = ""
palletNumber = ""
boxNumber = ""
totalCapacity = ""
totalBox = ""
boxDetailModels = []
}
}
struct SterilizeWholeBoardPage: View {
...
var body: some View {
PageContentView(title: "灭菌整板", viewModel: viewModel) {
ZStack {
...
VStack {
...
HStack {
TextButton(title: "重置") {
viewModel.reset()
}
...
}
...
}
}
}
...
}
}