younger_times
2023-07-25 b177ecba47250faab4ead4fc2b5ed7a3f2c40696
补缴
14个文件已修改
609 ■■■■ 已修改文件
WanPai/Common/View/ChooseStoreView.swift 29 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Config/Enums.swift 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Model/CommonModels.swift 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Network/Services.swift 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Welfare/CCell/CoinStoreCCell.swift 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Welfare/CCell/CoinStoreCCell.xib 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Welfare/VC/CoinStoreCenterVC.swift 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Welfare/VC/RechargeCenterVC.swift 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Welfare/VC/RechargeRecordVC.swift 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Welfare/VC/WelfareRedeemGoodsDetailVC.swift 206 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Welfare/VC/WelfareRedeemGoodsDetailVC.xib 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Welfare/VC/WelfareVC.swift 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Welfare/View/CoinStoreHeadView.swift 82 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Root/Welfare/View/CoinStoreHeadView.xib 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WanPai/Common/View/ChooseStoreView.swift
@@ -13,7 +13,10 @@
    @IBOutlet weak var view_container: UIView!
    @IBOutlet weak var view_bottomContainer: NSLayoutConstraint!
    @IBOutlet weak var tableView: UITableView!
    private var clouse:(()->Void)!
    private var clouse:((StoreSimpleModel)->Void)!
    private var models = [StoreSimpleModel]()
    private var selectIndex = 0
    private var defaultModel:StoreSimpleModel?
    override func awakeFromNib() {
        super.awakeFromNib()
@@ -27,12 +30,22 @@
        layoutIfNeeded()
    }
    static func show(_ clouse:@escaping ()->Void){
    static func show(models:[StoreSimpleModel],defaultModel:StoreSimpleModel? = nil, clouse:@escaping (StoreSimpleModel)->Void){
        let chooseStoreView = ChooseStoreView.jq_loadNibView()
        chooseStoreView.frame = screnDelegate?.window?.frame ?? .zero
        screnDelegate?.window?.addSubview(chooseStoreView)
        chooseStoreView.view_bottomContainer.constant = 0
        chooseStoreView.defaultModel = defaultModel
        chooseStoreView.clouse = clouse
        chooseStoreView.models = models
        for (index,m) in models.enumerated(){
            if m.storeId == defaultModel?.storeId{
                chooseStoreView.selectIndex = index;break
            }
        }
        chooseStoreView.tableView.reloadData()
        UIView.animate(withDuration: 0.4) {
            chooseStoreView.alpha = 1
            chooseStoreView.layoutIfNeeded()
@@ -56,7 +69,8 @@
            self.layoutIfNeeded()
        } completion: { _ in
            self.removeFromSuperview()
            self.clouse!()
            let model = self.models[self.selectIndex]
            self.clouse!(model)
        }
    }
@@ -67,12 +81,19 @@
}
extension ChooseStoreView:UITableViewDelegate{
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        selectIndex = indexPath.row
        tableView.reloadData()
    }
}
extension ChooseStoreView:UITableViewDataSource{
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let model = models[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: "_CommonSingleTCell") as! CommonSingleTCell
        cell.label_title.text = model.storeName
        cell.img_select.image = indexPath.row == selectIndex ? UIImage(named: "btn_choose_s") : UIImage(named: "btn_choose")
        return cell
    }
@@ -81,6 +102,6 @@
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
        return models.count
    }
}
WanPai/Config/Enums.swift
@@ -152,6 +152,14 @@
    }
}
enum Sort2Type:Int,HandyJSONEnum{
    //1积分高到低 2积分从低到高 3兑换从高到低
    case coinAsc = 1
    case coinDesc = 2
    case exAsc = 3
    case exDesc = 4
}
enum GenderType:Int,HandyJSONEnum{
    case  man = 1
    case  woman = 2
@@ -266,3 +274,27 @@
    case used = 2
    case overdue = 3
}
enum ExchangeType:Int,HandyJSONEnum{
    //商品类型 1实物 2课包 3门票 4优惠券
    case goods = 1
    case course = 2
    case ticket = 3
    case coupon = 4
    var strTitle:String{
        switch self {
            case .goods:return "实物"
            case .coupon:return "优惠券"
            case .course:return "课程"
            case .ticket:return "门票"
        }
    }
}
enum ExchangePaymentType:Int,HandyJSONEnum{
    case coin = 1
    case cashAndCoin = 2
}
WanPai/Model/CommonModels.swift
@@ -78,6 +78,16 @@
    var stuWeight:Double = 0
}
struct StudentProfile2Model:HandyJSON{
    var stuAge:Int = 0
    var stuId = 0
    var stuName:String = ""
    var stuPhone:String = ""
    var storeId:Int = 0
    var storeName:String = ""
}
struct CouponInfoModel:HandyJSON{
        ///有效时间
    var effectiveTime: String = ""
@@ -398,6 +408,7 @@
    var commodityImg: String = ""
    var commodityName: String = ""
    var commodityPrice: Double = 0
    var goodsType:ExchangeType = .goods
}
struct BillingModel:HandyJSON{
@@ -430,4 +441,42 @@
    var wpGold:Int = 0
}
struct ExchangeGoodsModel:HandyJSON {
    var belongs: String = ""
    var belongsScope: RegisterAcitivyType = .allUser
    var contents: String = ""
    var cost: Int = 0
    var courseHours: Int = 0
    var endTime: String = ""
    var exchangeAddrType: CouponConditionType = .nationwide
    var exchangeType: ExchangePaymentType = .coin
    var goodId: Int = 0
    var goodName: String = ""
    var goodType: ExchangeType = .goods
    var perLimit: Int = 0
    var pics = [String]()
    var redeemedNum: Int = 0
    var integral:Int = 0
    var cash:Double = 0
    var residueNum: Int = 0
    var startTime: String = ""
}
struct StoreSimpleModel:HandyJSON{
    var storeName = ""
    var storeId = 0
}
struct MarketMdoel:HandyJSON{
    var amount: Double = 0
    var belongsType: RegisterAcitivyType = .allUser
    var condition: ExchangePaymentType = .cashAndCoin
    var goodId: Int = 0
    var goodImg: String = ""
    var goodName: String = ""
    var goodsType: ExchangeType = .goods
    var integral: Int = 0
    var nums: Int = 0
}
WanPai/Network/Services.swift
@@ -140,11 +140,13 @@
        /// 充值明细
        /// - Parameters:
        ///   - yearMonth:  记录(1充值 2扣除)
    class func voucherDetail(recordType:Int?,yearMonth:String)->Observable<BaseResponse<[BillingModel]>>{
    class func voucherDetail(recordType:Int?,yearMonth:String,page:Int,pageSize:Int = 20)->Observable<BaseResponse<[BillingModel]>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/account/api/useBenefit/voucherDetail")
            .append(key: "recordId", value: recordType)
            .append(key: "yearMonth", value: yearMonth)
            .append(key: "pageNum", value: page)
            .append(key: "pageSize", value: pageSize)
        return NetworkRequest.request(params: params, method: .post, progress: false)
    }
@@ -157,10 +159,10 @@
    }
        /// 支付
    class func useBenefitPayment(payAmount:Double,payType:PayType)->Observable<BaseResponse<SimpleModel>>{
    class func useBenefitPayment(chargeId:Int,payType:PayType)->Observable<BaseResponse<SimpleModel>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/account/api/useBenefit/payment")
            .append(key: "payAmount", value: payAmount)
            .append(key: "chargeId", value: chargeId)
            .append(key: "payType", value: payType.rawValue)
        return NetworkRequest.request(params: params, method: .post, progress: true)
    }
@@ -384,6 +386,65 @@
            .append(key: "score", value: score)
        return NetworkRequest.request(params: params, method: .post, progress: true)
    }
}
// MARK: --  商城部分
extension Services{
        /// 积分商城-商品详情
    static func UseBenefitDetail(goodsId:Int,goodsType:ExchangeType)->Observable<BaseResponse<ExchangeGoodsModel>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/account/api/useBenefit/goodsDetails")
            .append(key: "goodsId", value: goodsId)
            .append(key: "goodsType", value: goodsType.rawValue)
        return NetworkRequest.request(params: params, method: .post, progress: true)
    }
        /// 兑换门店
    static func exchangeStoreIds(id:Int,type:ExchangeType)->Observable<BaseResponse<[StoreSimpleModel]>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/account/api/useBenefit/exchangeStoreIds")
            .append(key: "goodsId", value: id)
            .append(key: "goodsType", value: type.rawValue)
        return NetworkRequest.request(params: params, method: .post, progress: false)
    }
        /// 兑换商品
    static func exchangeOperation(exchangeType:ExchangePaymentType,goodsId:Int,goodsType:ExchangeType,num:Int,payType:PayType?,stuIds:String)->Observable<BaseResponse<PaymentModel>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/account/api/useBenefit/productRedemptionOperation")
            .append(key: "exchangeType", value: exchangeType.rawValue)
            .append(key: "goodId", value: goodsId)
            .append(key: "goodsType", value: goodsType.rawValue)
            .append(key: "nums", value: num)
            .append(key: "payType", value: payType?.rawValue)
            .append(key: "stuIds", value: stuIds)
        return NetworkRequest.request(params: params, method: .post, progress: true)
    }
        /// 积分商城-实体、门票、优惠券为默认门店|课包为默认学员
    static func goodsOfCourseStore(isCourse:Bool,pointsMerId:Int)->Observable<BaseResponse<StudentProfile2Model>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/account/api/useBenefit/goodsOfCourseStore")
            .append(key: "isCourse", value: isCourse)
            .append(key: "pointsMerId", value: pointsMerId)
        return NetworkRequest.request(params: params, method: .post, progress: false)
    }
        /// 商城中心
    class func mallList(goodsType:ExchangeType?,rank:Sort2Type?,search:String?)->Observable<BaseResponse<[MarketMdoel]>>{
        let params = ParamsAppender.build(url: All_Url)
            .interface(url: "/account/api/useBenefit/integralMallList")
            .append(key: "goodsType", value: goodsType?.rawValue)
            .append(key: "rank", value: rank?.rawValue)
            .append(key: "lat", value: locationTool.currentLocation?.coordinate.latitude.string)
            .append(key: "lon", value: locationTool.currentLocation?.coordinate.longitude.string)
        return NetworkRequest.request(params: params, method: .post, progress: false)
    }
}
// MARK: -- 预约场地
WanPai/Root/Welfare/CCell/CoinStoreCCell.swift
@@ -11,6 +11,25 @@
class CoinStoreCCell: UICollectionViewCell {
    @IBOutlet weak var img: UIImageView!
    @IBOutlet weak var view_container: UIView!
    @IBOutlet weak var label_title: UILabel!
    @IBOutlet weak var label_cond: UILabel!
    @IBOutlet weak var label_price: UILabel!
    @IBOutlet weak var label_type: UILabel!
    var marketModel:MarketMdoel!{
        didSet{
            img.sd_setImage(with: URL(string: marketModel.goodImg))
            label_title.text = marketModel.goodName
            label_cond.text = marketModel.belongsType.strTitle
            label_type.text = marketModel.goodsType.strTitle
            if marketModel.condition == .coin{
                label_price.text = "\(marketModel.integral)积分"
            }else{
                label_price.text = "\(marketModel.integral)积分+\(marketModel.amount.currency())"
            }
        }
    }
    override func awakeFromNib() {
        super.awakeFromNib()
WanPai/Root/Welfare/CCell/CoinStoreCCell.xib
@@ -81,6 +81,10 @@
            <size key="customSize" width="311" height="421"/>
            <connections>
                <outlet property="img" destination="MxK-ok-XBK" id="sLv-8g-oVE"/>
                <outlet property="label_cond" destination="wiA-ab-lxq" id="XD2-Lm-gXY"/>
                <outlet property="label_price" destination="rHf-PZ-mhf" id="QN9-6l-MM6"/>
                <outlet property="label_title" destination="lhv-BK-Dvg" id="M3u-qh-jcK"/>
                <outlet property="label_type" destination="5kE-Rc-Iuu" id="HGO-nt-nth"/>
                <outlet property="view_container" destination="Seb-oU-zxq" id="U7N-WT-zNI"/>
            </connections>
            <point key="canvasLocation" x="154.96183206106869" y="117.95774647887325"/>
WanPai/Root/Welfare/VC/CoinStoreCenterVC.swift
@@ -7,10 +7,24 @@
import UIKit
import JQTools
import RxSwift
import RxRelay
class CoinStoreViewModel:RefreshModel<MarketMdoel>{
    var goodsType = BehaviorRelay<ExchangeType?>(value: nil)
    var rank = BehaviorRelay<Sort2Type?>(value: nil)
    let search = BehaviorRelay<String?>(value: nil)
    override func api() -> (Observable<BaseResponse<[MarketMdoel]>>)? {
        Services.mallList(goodsType: goodsType.value, rank: rank.value, search: search.value)
    }
}
class CoinStoreCenterVC: BaseVC {
    private lazy var collectionView:UICollectionView = {
    private let viewModel = CoinStoreViewModel()
    private lazy var collectionView:BaseCollectionView = {
        let CellW:Double = (JQ_ScreenW) / 2.0
        let CellH:Double = CellW * 1.3428
@@ -19,10 +33,10 @@
        flowLayout.minimumLineSpacing = 0
        flowLayout.minimumInteritemSpacing = 0
        flowLayout.itemSize = CGSize(width: CellW, height: CellH)
        flowLayout.headerReferenceSize = CGSize(width: JQ_ScreenW, height: 227)
        flowLayout.headerReferenceSize = CGSize(width: JQ_ScreenW, height: JQ_ScreenW * 0.5564)
        flowLayout.sectionHeadersPinToVisibleBounds = true
        let collect = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
        let collect = BaseCollectionView(frame: .zero, collectionViewLayout: flowLayout)
        collect.delegate = self
        collect.dataSource = self
        collect.contentInset = UIEdgeInsets(top: 0, left:0, bottom: 14, right: 0)
@@ -31,9 +45,15 @@
        return collect
    }()
    var benefitHomeModel:BenefitHomeModel?
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "积分商城"
        viewModel.configure(collectionView,needMore: false)
        collectionView.jq_setEmptyView()
        viewModel.beginRefresh()
    }
    override func setUI() {
@@ -48,26 +68,34 @@
extension CoinStoreCenterVC:UICollectionViewDelegate{
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
         let vc = WelfareRedeemGoodsDetailVC()
        let model = viewModel.dataSource.value[indexPath.row]
        let vc = WelfareRedeemGoodsDetailVC(commodityId: model.goodId, goodsType: model.goodsType)
        push(vc: vc)
    }
    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        let headView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "_CoinStoreHeadView", for: indexPath) as! CoinStoreHeadView
        headView.innerView = self.view
        headView.viewModel = viewModel
        headView.label_coin.text = "\(benefitHomeModel?.userIntegral ?? 0)积分"
        headView.label_username.text = benefitHomeModel?.userName ?? ""
        headView.img_cover.sd_setImage(with: URL(string: benefitHomeModel?.userHeadImg))
        headView.tf_search.rx.text.orEmpty.bind(to: viewModel.search).disposed(by: disposeBag)
        return headView
    }
}
extension CoinStoreCenterVC:UICollectionViewDataSource{
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let model = viewModel.dataSource.value[indexPath.row]
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "_CoinStoreCCell", for: indexPath) as! CoinStoreCCell
        cell.marketModel = model
        return cell
    }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 15
        return viewModel.dataSource.value.count
    }
    func numberOfSections(in collectionView: UICollectionView) -> Int {
WanPai/Root/Welfare/VC/RechargeCenterVC.swift
@@ -77,7 +77,7 @@
    @IBAction func rechargeAction(_ sender: UIButton) {
        let item = items[selectIndex]
        PaymentView.show(money: (ali:item.money,wx:item.money,coin:item.coin,course:nil)) { type in
        PaymentView.show(money: (ali:item.money,wx:item.money,coin:nil,course:nil)) { type in
//            let result:PaymentResultVC.PaymentResult = status ? .success:.fail
//            let vc = PaymentResultVC(result: result, objType: .activityApply)
WanPai/Root/Welfare/VC/RechargeRecordVC.swift
@@ -16,7 +16,7 @@
    var type = BehaviorRelay<Int?>(value: nil)
    var yearMonth = BehaviorRelay<String>(value: "")
    override func api() -> (Observable<BaseResponse<[BillingModel]>>)? {
        return Services.voucherDetail(recordType: type.value, yearMonth: yearMonth.value)
        return Services.voucherDetail(recordType: type.value, yearMonth: yearMonth.value,page: page,pageSize: pageSize)
    }
}
@@ -71,7 +71,7 @@
        viewModel.yearMonth.accept(Date().jq_format("yyyy-MM"))
        btn_date.setTitle("\(Date().jq_format("yyyy年MM月"))>", for: .normal)
        viewModel.configure(tableView,needMore: false)
        viewModel.configure(tableView)
        viewModel.beginRefresh()
    }
WanPai/Root/Welfare/VC/WelfareRedeemGoodsDetailVC.swift
@@ -8,6 +8,7 @@
import UIKit
import QMUIKit
import JQTools
import WebKit
class WelfareRedeemGoodsDetailVC: BaseVC {
@@ -15,10 +16,97 @@
    @IBOutlet weak var btn_store: QMUIButton!
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var cons_tableHei: NSLayoutConstraint!
    @IBOutlet weak var view_banner: UIView!
    @IBOutlet weak var label_title: UILabel!
    @IBOutlet weak var label_exchange: UILabel!
    @IBOutlet weak var label_limit: UILabel!
    @IBOutlet weak var label_cost: UILabel!
    @IBOutlet weak var label_redeemedNum: UILabel!
    @IBOutlet weak var label_residueNum: UILabel!
    @IBOutlet weak var label_perLimit: UILabel!
    @IBOutlet weak var label_startTime: UILabel!
    @IBOutlet weak var label_courseHours: UILabel!
    @IBOutlet weak var view_courseHours: UIView!
    @IBOutlet weak var view_exchangeStore: UIView!
    @IBOutlet weak var webView: WKWebView!
    @IBOutlet weak var label_storeName: UILabel!
    @IBOutlet weak var cons_webHei: NSLayoutConstraint!
    @IBOutlet weak var btn_exchange: UIButton!
    private var bannerView:CommonBannerView = {
        let banner = CommonBannerView()
        return banner
    }()
//    private var model:BenefitHomeCommonditiesModel!
    private var id:Int!
    private var goodsType:ExchangeType!
    private var exchangeGoodsModel:ExchangeGoodsModel?
    private var storeModels = [StoreSimpleModel]()
    private var selectStoreModel:StoreSimpleModel?
    private var studentModels = [CourseDetailStudentModel]()
    init(commodityId:Int,goodsType:ExchangeType) {
        super.init(nibName: nil, bundle: nil)
        self.id = commodityId
        self.goodsType = goodsType
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "商品详情"
        Services.UseBenefitDetail(goodsId: id, goodsType: goodsType).subscribe(onNext: {[weak self] data in
            guard let weakSelf = self else { return }
            if let model = data.data{
                self?.exchangeGoodsModel = model
                self?.label_title.text = model.goodName
                self?.label_limit.text = String(format: "%@|%@", model.belongsScope.strTitle,model.exchangeAddrType.titleRaw)
                self?.label_cost.text = String(format: "价值:%ld", model.cost)
                self?.label_redeemedNum.text = "\(model.redeemedNum)"
                self?.label_residueNum.text = "\(model.residueNum)"
                self?.label_perLimit.text = "\(model.perLimit)"
                self?.label_startTime.text = "\(model.startTime)-\(model.endTime)"
                self?.label_courseHours.text = "\(model.courseHours)课时"
                self?.view_courseHours.isHidden = model.courseHours == 0
                self?.view_exchangeStore.isHidden = model.exchangeAddrType != .store
                switch model.exchangeType{
                    case .coin:
                        self?.label_exchange.text = String(format: "%ld积分", model.integral)
                    case .cashAndCoin:
                        self?.label_exchange.text = String(format: "%ld积分+%@", model.integral,model.cash.currency())
                }
                    //加载门店
                if model.exchangeAddrType == .store{
                    Services.exchangeStoreIds(id: model.goodId, type: model.goodType).subscribe(onNext: {[weak self] data in
                        if let models = data.data{
                            self?.storeModels = models
                            self?.selectStoreModel = models.first
                            self?.label_storeName.text = models.first?.storeName ?? "未知门店"
                        }
                    }).disposed(by: weakSelf.disposeBag)
                }
                if model.contents.isEmpty{
                    self?.webView.loadHTMLString("暂无说明".jq_wrapHtml(), baseURL: nil)
                }else{
                    self?.webView.loadHTMLString(model.contents.jq_wrapHtml(), baseURL: nil)
                }
            }
        }).disposed(by: disposeBag)
        bannerView.setImages(images: exchangeGoodsModel?.pics ?? [], type: .URL) { index in
        }
        updateStudenTable()
    }
    override func setUI() {
@@ -33,34 +121,112 @@
        tableView.isScrollEnabled = false
        tableView.separatorStyle = .none
        tableView.register(UINib(nibName: "StudentInfoTCell", bundle: nil), forCellReuseIdentifier: "_StudentInfoTCell")
        view_banner.addSubview(bannerView)
        bannerView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
    }
    override func setRx() {
        self.webView.scrollView.rx.observe(CGSize.self, "contentSize").map { (size) -> CGFloat? in
            if let size = size{
                return size.height
            }
            return nil
        }.subscribe(onNext: { [unowned self](height) in
            if let height = height{
                self.cons_webHei.constant = height
            }
        }).disposed(by: disposeBag)
    }
    private func updateStudenTable(){
        cons_tableHei.constant = Double(studentModels.count) * 100
        tableView.reloadData()
    }
    @IBAction func chooseAction(_ sender: QMUIButton) {
        StudentChooseView.show(itemType: .course) { studs in
        } needAddClouse: {
        guard exchangeGoodsModel != nil else {return}
        StudentChooseView.show(itemType: .course, defaultStu: studentModels) {[weak self] studs in
            guard let weakSelf = self else { return }
            if studs.count > weakSelf.exchangeGoodsModel!.perLimit{
                alert(msg: "最多选择\(weakSelf.exchangeGoodsModel!.perLimit)位学员");return
            }
            self?.studentModels = studs as! [CourseDetailStudentModel]
            self?.updateStudenTable()
        } needAddClouse: { [weak self] in
            let vc = ActivityStudentListVC()
            self.push(vc: vc)
            self?.push(vc: vc)
        }
    }
    @IBAction func chooseStoreAction(_ sender: QMUIButton) {
        ChooseStoreView.show {
            ChooseNumberView.show(maxNumber: 5) { num in
                let attribute = AttributedStringbuilder()
                attribute.add(string: "确认消耗", withFont: UIFont.systemFont(ofSize: 16, weight: .medium), withColor: .black.withAlphaComponent(0.9))
                    .add(string: "0积分和¥0\n", withFont: UIFont.systemFont(ofSize: 16, weight: .medium), withColor: UIColor(hexStr: "#E41818").withAlphaComponent(0.8))
                    .add(string: "兑换此商品吗?", withFont: UIFont.systemFont(ofSize: 16, weight: .medium), withColor: .black.withAlphaComponent(0.9))
                CommonAlertView.show(title: "兑换商品", attribute: attribute.mutableAttributedString) { state in
                    PaymentView.show(money: (ali:1,wx:2,coin:2,course:2)) { status in
//                        let result:PaymentResultVC.PaymentResult = status ? .success:.fail
//                        let vc = PaymentResultVC(result: result, objType: .activityApply)
//                        vc.modalPresentationStyle = .fullScreen
//                        self.present(vc, animated: true)
        guard storeModels.count != 0 else {return}
        ChooseStoreView.show(models: storeModels,defaultModel: selectStoreModel) {[weak self] m in
            self?.selectStoreModel = m
            self?.label_storeName.text = m.storeName
        }
    }
    @IBAction func exchangeAction(_ sender: UIButton) {
        guard exchangeGoodsModel != nil else {return}
        guard exchangeGoodsModel!.residueNum != 0 else {alert(msg: "已兑换光啦");return}
        guard studentModels.count != 0 else {alert(msg: "请选择学员");return}
        ChooseNumberView.show(maxNumber: exchangeGoodsModel!.perLimit) {[weak self] num in
            guard let weakSelf = self else { return }
            let attribute = AttributedStringbuilder()
            attribute.add(string: "确认消耗", withFont: UIFont.systemFont(ofSize: 16, weight: .medium), withColor: .black.withAlphaComponent(0.9))
            if weakSelf.exchangeGoodsModel!.exchangeType == .coin{
                attribute.add(string: "\(weakSelf.exchangeGoodsModel!.cost * weakSelf.studentModels.count)积分", withFont: UIFont.systemFont(ofSize: 16, weight: .medium), withColor: UIColor(hexStr: "#E41818").withAlphaComponent(0.8))
            }else{
                attribute.add(string: String(format: "%ld积分和%@", weakSelf.exchangeGoodsModel!.integral * weakSelf.studentModels.count,(weakSelf.exchangeGoodsModel!.cash * Double(weakSelf.studentModels.count)).currency()), withFont: UIFont.systemFont(ofSize: 16, weight: .medium), withColor: UIColor(hexStr: "#E41818").withAlphaComponent(0.8))
            }
            attribute.add(string: "兑换此商品吗?", withFont: UIFont.systemFont(ofSize: 16, weight: .medium), withColor: .black.withAlphaComponent(0.9))
            CommonAlertView.show(title: "兑换商品", attribute: attribute.mutableAttributedString) { state in
                if weakSelf.exchangeGoodsModel!.exchangeType == .coin{
                    Services.exchangeOperation(exchangeType: .coin, goodsId: weakSelf.exchangeGoodsModel!.goodId, goodsType: weakSelf.exchangeGoodsModel!.goodType, num: num, payType: nil, stuIds: weakSelf.studentModels.map({"\($0.id)"}).joined(separator: ",")).subscribe(onNext: {data in
                        alertSuccess(msg: "兑换成功")
                        weakSelf.exchangeSuccessUI()
                    }).disposed(by: weakSelf.disposeBag)
                }else {
                        //支付金额
                    let cash = weakSelf.exchangeGoodsModel!.cash
                    PaymentView.show(money: (ali:cash,wx:cash,coin:nil,course:nil)) { payType in
                        Services.exchangeOperation(exchangeType: .cashAndCoin, goodsId: weakSelf.exchangeGoodsModel!.goodId, goodsType: weakSelf.exchangeGoodsModel!.goodType, num: num, payType: payType, stuIds: weakSelf.studentModels.map({"\($0.id)"}).joined(separator: ",")).subscribe(onNext: {data in
                            if let m = data.data{
                                switch payType {
                                    case .aliPay:
                                        YYPaymentManager.shared.sendPaymentRequest(YYAlipayRequest(orderString: m.orderString)) { result in
                                            switch result {
                                                case .success:alertSuccess(msg: "兑换成功")
                                                    weakSelf.exchangeSuccessUI()
                                                case .cancel:
                                                    alert(msg: "已取消兑换")
                                                case .failure(let error):
                                                    alertError(msg: error.localizedDescription)
                                            }
                                        }
                                    case .wechat:break
                                    case .coin:break
                                    case .courseNum:break
                                }
                            }
                        }).disposed(by: weakSelf.disposeBag)
                    }
                }
            }
        }
    }
    private func exchangeSuccessUI(){
        btn_exchange.setTitle("已兑换", for: .normal)
        btn_exchange.isEnabled = false
        label_redeemedNum.text = "\(exchangeGoodsModel!.redeemedNum + 1)"
        label_residueNum.text = "\(exchangeGoodsModel!.residueNum - 1)"
    }
}
@@ -71,10 +237,16 @@
extension WelfareRedeemGoodsDetailVC:UITableViewDataSource{
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "_StudentInfoTCell") as! StudentInfoTCell
        cell.indexPath = indexPath
        cell.studentModel = studentModels[indexPath.row]
        cell.deleClouse = {[weak self] index in
            self?.studentModels.remove(at: index)
            self?.updateStudenTable()
        }
        return cell
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
        return studentModels.count
    }
}
WanPai/Root/Welfare/VC/WelfareRedeemGoodsDetailVC.xib
@@ -12,11 +12,27 @@
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="WelfareRedeemGoodsDetailVC" customModule="WanPai" customModuleProvider="target">
            <connections>
                <outlet property="btn_exchange" destination="R3A-cj-kzU" id="zYY-kt-Uxt"/>
                <outlet property="btn_store" destination="DK1-7I-Zgs" id="P4s-8p-Srp"/>
                <outlet property="btn_student" destination="NfN-7G-XM4" id="Heh-WX-eDd"/>
                <outlet property="cons_tableHei" destination="2Vo-tY-Rnk" id="1xt-su-irf"/>
                <outlet property="cons_webHei" destination="bhR-O6-N5b" id="pLq-LA-JB3"/>
                <outlet property="label_cost" destination="7Oz-EC-ypg" id="mAM-ff-ZBK"/>
                <outlet property="label_courseHours" destination="FgM-YE-waa" id="vSp-bJ-SaS"/>
                <outlet property="label_exchange" destination="wai-5S-si5" id="6Ah-wX-zHO"/>
                <outlet property="label_limit" destination="Lm4-og-vup" id="a4n-h0-WgY"/>
                <outlet property="label_perLimit" destination="HyU-Ki-Lwv" id="Eiy-oR-rMF"/>
                <outlet property="label_redeemedNum" destination="Nun-Hi-Ba8" id="Bf7-w1-Ysg"/>
                <outlet property="label_residueNum" destination="DpQ-7A-Y6o" id="wV8-M0-a7H"/>
                <outlet property="label_startTime" destination="RwQ-MS-2sL" id="n3f-g9-OqW"/>
                <outlet property="label_storeName" destination="4dK-Zl-Jdj" id="yAy-e3-kqY"/>
                <outlet property="label_title" destination="Xbv-xb-Opx" id="wSK-g7-wYb"/>
                <outlet property="tableView" destination="Iqj-NB-Sdv" id="whY-na-FVo"/>
                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
                <outlet property="view_banner" destination="Qqf-lq-tQb" id="nPC-xS-Gbj"/>
                <outlet property="view_courseHours" destination="FLV-Kf-Avt" id="oDU-BH-bZj"/>
                <outlet property="view_exchangeStore" destination="PF8-aV-ew9" id="x4R-3l-zbD"/>
                <outlet property="webView" destination="tQn-lc-7cb" id="xcY-cg-bKR"/>
            </connections>
        </placeholder>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
@@ -24,11 +40,24 @@
            <rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
            <subviews>
                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="R3A-cj-kzU">
                    <rect key="frame" x="0.0" y="770" width="393" height="48"/>
                    <color key="backgroundColor" name="FE6E0D"/>
                    <constraints>
                        <constraint firstAttribute="height" constant="48" id="bSI-1u-taE"/>
                    </constraints>
                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="18"/>
                    <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
                    <state key="normal" title="立即兑换"/>
                    <connections>
                        <action selector="exchangeAction:" destination="-1" eventType="touchUpInside" id="NPs-3e-YIi"/>
                    </connections>
                </button>
                <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="L61-7B-reh">
                    <rect key="frame" x="0.0" y="59" width="393" height="759"/>
                    <rect key="frame" x="0.0" y="59" width="393" height="711"/>
                    <subviews>
                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gbh-Le-CoL">
                            <rect key="frame" x="0.0" y="0.0" width="393" height="872"/>
                            <rect key="frame" x="0.0" y="0.0" width="393" height="829"/>
                            <subviews>
                                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Qqf-lq-tQb">
                                    <rect key="frame" x="0.0" y="0.0" width="393" height="221.66666666666666"/>
@@ -362,26 +391,30 @@
                                    <nil key="textColor"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Zp9-nM-vpb">
                                    <rect key="frame" x="0.0" y="724" width="393" height="100"/>
                                <wkWebView contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tQn-lc-7cb">
                                    <rect key="frame" x="0.0" y="719" width="393" height="100"/>
                                    <constraints>
                                        <constraint firstAttribute="height" constant="100" id="XNx-ob-i8c"/>
                                        <constraint firstAttribute="height" constant="100" id="bhR-O6-N5b"/>
                                    </constraints>
                                </imageView>
                                    <wkWebViewConfiguration key="configuration">
                                        <audiovisualMediaTypes key="mediaTypesRequiringUserActionForPlayback" none="YES"/>
                                        <wkPreferences key="preferences"/>
                                    </wkWebViewConfiguration>
                                </wkWebView>
                            </subviews>
                            <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                            <constraints>
                                <constraint firstItem="37m-yk-F6F" firstAttribute="top" secondItem="Qqf-lq-tQb" secondAttribute="bottom" id="7XC-I0-EDS"/>
                                <constraint firstItem="Qqf-lq-tQb" firstAttribute="leading" secondItem="gbh-Le-CoL" secondAttribute="leading" id="88i-86-LCE"/>
                                <constraint firstItem="Zp9-nM-vpb" firstAttribute="top" secondItem="eGT-qY-7F5" secondAttribute="bottom" constant="15" id="8Jo-IW-w6Q"/>
                                <constraint firstItem="eGT-qY-7F5" firstAttribute="top" secondItem="37m-yk-F6F" secondAttribute="bottom" constant="15" id="8g1-AM-BJ7"/>
                                <constraint firstAttribute="bottom" secondItem="tQn-lc-7cb" secondAttribute="bottom" constant="10" id="HoY-bM-nev"/>
                                <constraint firstItem="37m-yk-F6F" firstAttribute="leading" secondItem="gbh-Le-CoL" secondAttribute="leading" id="Kai-3Z-AgF"/>
                                <constraint firstItem="Zp9-nM-vpb" firstAttribute="leading" secondItem="gbh-Le-CoL" secondAttribute="leading" id="Ual-bZ-2mE"/>
                                <constraint firstItem="Qqf-lq-tQb" firstAttribute="top" secondItem="gbh-Le-CoL" secondAttribute="top" id="VuQ-fm-LhH"/>
                                <constraint firstAttribute="bottom" secondItem="Zp9-nM-vpb" secondAttribute="bottom" constant="48" id="jId-7F-KSB"/>
                                <constraint firstItem="tQn-lc-7cb" firstAttribute="top" secondItem="eGT-qY-7F5" secondAttribute="bottom" constant="10" id="ZbZ-JC-YHg"/>
                                <constraint firstAttribute="trailing" secondItem="tQn-lc-7cb" secondAttribute="trailing" id="ic1-2v-l5U"/>
                                <constraint firstAttribute="trailing" secondItem="37m-yk-F6F" secondAttribute="trailing" id="mq2-n6-vUt"/>
                                <constraint firstItem="tQn-lc-7cb" firstAttribute="leading" secondItem="gbh-Le-CoL" secondAttribute="leading" id="qOA-YH-0DD"/>
                                <constraint firstItem="eGT-qY-7F5" firstAttribute="leading" secondItem="gbh-Le-CoL" secondAttribute="leading" constant="15" id="qc4-es-fxP"/>
                                <constraint firstAttribute="trailing" secondItem="Zp9-nM-vpb" secondAttribute="trailing" id="ueX-OG-jV3"/>
                                <constraint firstAttribute="trailing" secondItem="Qqf-lq-tQb" secondAttribute="trailing" id="yKT-7i-2oY"/>
                            </constraints>
                        </view>
@@ -394,16 +427,6 @@
                        <constraint firstAttribute="trailing" secondItem="gbh-Le-CoL" secondAttribute="trailing" id="m4d-PS-M4I"/>
                    </constraints>
                </scrollView>
                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="R3A-cj-kzU">
                    <rect key="frame" x="0.0" y="770" width="393" height="48"/>
                    <color key="backgroundColor" name="FE6E0D"/>
                    <constraints>
                        <constraint firstAttribute="height" constant="48" id="bSI-1u-taE"/>
                    </constraints>
                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="18"/>
                    <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
                    <state key="normal" title="立即兑换"/>
                </button>
            </subviews>
            <viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
            <color key="backgroundColor" systemColor="systemBackgroundColor"/>
@@ -411,7 +434,7 @@
                <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="L61-7B-reh" secondAttribute="trailing" id="NCa-KY-ZtU"/>
                <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="R3A-cj-kzU" secondAttribute="trailing" id="bv0-9J-Ggi"/>
                <constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="R3A-cj-kzU" secondAttribute="bottom" id="gf4-mg-AOH"/>
                <constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="L61-7B-reh" secondAttribute="bottom" id="iyb-hB-0p6"/>
                <constraint firstItem="R3A-cj-kzU" firstAttribute="top" secondItem="L61-7B-reh" secondAttribute="bottom" id="hSI-4x-b80"/>
                <constraint firstItem="L61-7B-reh" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" id="nwi-Ue-UD8"/>
                <constraint firstItem="R3A-cj-kzU" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="p40-L8-Qdh"/>
                <constraint firstItem="L61-7B-reh" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="peu-JR-Hp4"/>
WanPai/Root/Welfare/VC/WelfareVC.swift
@@ -129,6 +129,7 @@
    @IBAction func storeAction(_ sender: Any) {
        let vc = CoinStoreCenterVC()
        vc.benefitHomeModel = benefitHomeModel
        push(vc: vc)
    }
@@ -178,7 +179,7 @@
extension WelfareVC:UICollectionViewDelegate{
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let model = benefitHomeModel!.commodities[indexPath.row]
        let vc = WelfareRedeemGoodsDetailVC()
        let vc = WelfareRedeemGoodsDetailVC(commodityId: model.commodityId, goodsType: model.goodsType)
        push(vc: vc)
    }
}
WanPai/Root/Welfare/View/CoinStoreHeadView.swift
@@ -8,14 +8,23 @@
import UIKit
import JQTools
import QMUIKit
import RxSwift
import RxRelay
class CoinStoreHeadView: UICollectionReusableView {
    @IBOutlet weak var btn_sort: QMUIButton!
    @IBOutlet weak var btn_type: QMUIButton!
    @IBOutlet weak var shadowView: UIView!
    @IBOutlet weak var img_cover: UIImageView!
    @IBOutlet weak var label_username: UILabel!
    @IBOutlet weak var label_coin: UILabel!
    @IBOutlet weak var tf_search: UITextField!
    private var resortSubTypeView:CourseSubTypeView?
    private var typeSubTypeView:CourseSubTypeView?
    private var disposeBag = DisposeBag()
    var viewModel:CoinStoreViewModel!
    var innerView:UIView!
    override func awakeFromNib() {
@@ -25,31 +34,70 @@
        btn_type.imagePosition = .right
        btn_sort.spacingBetweenImageAndTitle = 5
        btn_type.spacingBetweenImageAndTitle = 5
        tf_search.delegate = self
        tf_search.returnKeyType = .search
    }
    @IBAction func resortAction(_ sender: QMUIButton) {
        guard !sender.isSelected else {return}
        hiddenAction()
        sender.isSelected = true
        let items = Array<NormalSimpleModel>()
        CourseSubTypeView.show(inView: self.innerView, afterView: self, items: items) { m in
        var items = Array<NormalSimpleModel>()
        items.append(NormalSimpleModel(id: 0, name: "默认排序"))
        items.append(NormalSimpleModel(id: 1, name: "积分从高到低"))
        items.append(NormalSimpleModel(id: 2, name: "积分从低到高"))
        items.append(NormalSimpleModel(id: 3, name: "兑换从高到低"))
        let model = items.filter({$0.id == viewModel.rank.value?.rawValue})
        resortSubTypeView = CourseSubTypeView.show(inView: self.innerView, afterView: self, items: items, selectModel: model.first) {[weak self] m in
            if m.id == 0{
                self?.viewModel.rank.accept(nil)
            }else{
                self?.viewModel.rank.accept(Sort2Type(rawValue: m.id))
            }
            sender.setTitle(m.name, for: .normal)
            self?.viewModel.beginRefresh()
            sender.isSelected = false
        } closeClouse: {
            sender.isSelected = false
        }
    }
    @IBAction func searchAction(_ sender: Any) {
        viewModel.beginRefresh()
    }
    @IBAction func typeAction(_ sender: UIButton) {
        guard !sender.isSelected else {return}
        hiddenAction()
        sender.isSelected = true
        var items = Array<NormalSimpleModel>()
        items.append(NormalSimpleModel(id: 0, name: "商品类型"))
        items.append(NormalSimpleModel(id: 1, name: "实物"))
        items.append(NormalSimpleModel(id: 2, name: "课包"))
        items.append(NormalSimpleModel(id: 3, name: "门票"))
        items.append(NormalSimpleModel(id: 4, name: "优惠券"))
        let model = items.filter({$0.id == viewModel.goodsType.value?.rawValue})
        typeSubTypeView = CourseSubTypeView.show(inView: self.innerView, afterView: self, items: items, selectModel: model.first) {[weak self] m in
            sender.setTitle(m.name, for: .normal)
            if m.id == 0{
                self?.viewModel.goodsType.accept(nil)
            }else{
                self?.viewModel.goodsType.accept(ExchangeType(rawValue: m.id))
            }
            self?.viewModel.beginRefresh()
            sender.isSelected = false
        } closeClouse: {
            sender.isSelected = false
        }
    }
    @IBAction func typeAction(_ sender: UIButton) {
        guard !sender.isSelected else {return}
        sender.isSelected = true
        let items = Array<NormalSimpleModel>()
        CourseSubTypeView.show(inView: self.innerView, afterView: self, items: items) {m in
            sender.isSelected = false
        } closeClouse: {
            sender.isSelected = false
        }
    private func hiddenAction(){
        btn_sort.isSelected = false
        btn_type.isSelected = false
        typeSubTypeView?.removeFromSuperview()
        resortSubTypeView?.removeFromSuperview()
    }
    @IBAction func recoredAction(_ sender: UIButton) {
@@ -66,3 +114,11 @@
    }
}
extension CoinStoreHeadView:UITextFieldDelegate{
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        viewModel.beginRefresh()
        return true
    }
}
WanPai/Root/Welfare/View/CoinStoreHeadView.xib
@@ -145,6 +145,9 @@
                    <state key="normal" title="搜索">
                        <color key="titleColor" name="FE6E0D"/>
                    </state>
                    <connections>
                        <action selector="searchAction:" destination="U6b-Vx-4bR" eventType="touchUpInside" id="XIv-oq-WeY"/>
                    </connections>
                </button>
                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="8CB-nR-iEe">
                    <rect key="frame" x="0.0" y="164" width="457" height="45"/>
@@ -212,7 +215,11 @@
            <connections>
                <outlet property="btn_sort" destination="tGC-9B-kBe" id="gUc-bK-5ep"/>
                <outlet property="btn_type" destination="CSW-RY-Hpe" id="AQt-Lm-d0P"/>
                <outlet property="img_cover" destination="Ut2-N8-z8a" id="At4-si-HJQ"/>
                <outlet property="label_coin" destination="dFh-bC-k5U" id="nrg-pP-kR3"/>
                <outlet property="label_username" destination="E2A-yI-sez" id="nQQ-0t-IaW"/>
                <outlet property="shadowView" destination="8CB-nR-iEe" id="Lhn-LX-roE"/>
                <outlet property="tf_search" destination="kj9-Ot-DUR" id="IBN-9O-U07"/>
            </connections>
            <point key="canvasLocation" x="167.17557251908397" y="79.929577464788736"/>
        </collectionReusableView>