├── .gitignore ├── go_api_server ├── main ├── global │ └── global.go ├── uploads │ └── file │ │ ├── 2022_04_03_21_26_39_51file.png │ │ ├── 2022_04_03_21_26_39_821file.png │ │ └── 2022_04_03_21_26_39_937file.png ├── model │ ├── common │ │ ├── request │ │ │ ├── common.go │ │ │ └── meeting.go │ │ └── response │ │ │ ├── common.go │ │ │ ├── meeting.go │ │ │ └── response.go │ ├── upload_download.go │ ├── base_model.go │ ├── message.go │ ├── sys_user.go │ └── meeting.go ├── service │ ├── enter.go │ ├── sys_user.go │ ├── message.go │ ├── upload_download.go │ └── meeting.go ├── config │ └── application.yml ├── router │ ├── sys_user.go │ ├── message.go │ ├── meeting.go │ ├── upload_download.go │ └── enter.go ├── api │ ├── enter.go │ ├── sys_user.go │ ├── upload_download.go │ ├── message.go │ └── meeting.go ├── main.go ├── common │ └── database.go ├── go.mod ├── utils │ └── transition.go ├── go.sum └── sql │ └── testpro.sql ├── ZYSwiftUIFrame ├── ZYSwiftUIFrame │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── head.imageset │ │ │ ├── 鹿.png │ │ │ └── Contents.json │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Preview Content │ │ └── Preview Assets.xcassets │ │ │ └── Contents.json │ ├── UI │ │ ├── User │ │ │ ├── UserAPI.swift │ │ │ ├── User.swift │ │ │ ├── UserDetailView.swift │ │ │ ├── UserVM.swift │ │ │ └── UserListView.swift │ │ ├── Meeting │ │ │ ├── MeetingAPI.swift │ │ │ ├── MeetingVM.swift │ │ │ ├── Meeting.swift │ │ │ ├── MeetingListView.swift │ │ │ └── MeetingDetailView.swift │ │ ├── Message │ │ │ ├── MessageAPI.swift │ │ │ ├── MessageVM.swift │ │ │ ├── Message.swift │ │ │ ├── MessageDetailView.swift │ │ │ └── MessageListView.swift │ │ ├── Map │ │ │ ├── MapNavigation.swift │ │ │ ├── LocationViewModel.swift │ │ │ └── MapDemo.swift │ │ ├── ZYSwiftUIFrameApp.swift │ │ ├── Upload │ │ │ └── Upload.swift │ │ ├── About │ │ │ └── AboutView.swift │ │ ├── ContentView.swift │ │ └── Notification │ │ │ └── NotificationView.swift │ ├── Global │ │ ├── Constants.swift │ │ └── ImageUtil.swift │ ├── Api │ │ ├── ServerResponse.swift │ │ ├── UploadApi.swift │ │ ├── CommonApiObj.swift │ │ ├── BaseApi.swift │ │ ├── NetworkManager.swift │ │ └── CommonVM.swift │ └── UIFrame │ │ ├── Enhance │ │ ├── CodableDefault.swift │ │ └── Extensions.swift │ │ ├── Refresh │ │ ├── ZYRefreshView.swift │ │ └── ZYListView.swift │ │ ├── Common │ │ ├── CommonText.swift │ │ ├── ButtonView.swift │ │ └── ImageShowView.swift │ │ ├── ImagePick │ │ ├── MultipleImagePickView.swift │ │ └── ImagePickerView.swift │ │ └── ZYNavBarView.swift └── ZYSwiftUIFrame.xcodeproj │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ └── yusael.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved │ ├── xcuserdata │ └── yusael.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ └── xcschememanagement.plist │ └── project.pbxproj └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | 3 | -------------------------------------------------------------------------------- /go_api_server/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/szluyu99/ZYSwiftUIFrame/HEAD/go_api_server/main -------------------------------------------------------------------------------- /go_api_server/global/global.go: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | import "gorm.io/gorm" 4 | 5 | var ( 6 | DB *gorm.DB 7 | ) 8 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /go_api_server/uploads/file/2022_04_03_21_26_39_51file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/szluyu99/ZYSwiftUIFrame/HEAD/go_api_server/uploads/file/2022_04_03_21_26_39_51file.png -------------------------------------------------------------------------------- /go_api_server/uploads/file/2022_04_03_21_26_39_821file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/szluyu99/ZYSwiftUIFrame/HEAD/go_api_server/uploads/file/2022_04_03_21_26_39_821file.png -------------------------------------------------------------------------------- /go_api_server/uploads/file/2022_04_03_21_26_39_937file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/szluyu99/ZYSwiftUIFrame/HEAD/go_api_server/uploads/file/2022_04_03_21_26_39_937file.png -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/Assets.xcassets/head.imageset/鹿.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/szluyu99/ZYSwiftUIFrame/HEAD/ZYSwiftUIFrame/ZYSwiftUIFrame/Assets.xcassets/head.imageset/鹿.png -------------------------------------------------------------------------------- /go_api_server/model/common/request/common.go: -------------------------------------------------------------------------------- 1 | package request 2 | 3 | type PageInfo struct { 4 | Page int `json:"page"` // 页码 5 | PageSize int `json:"pageSize"` // 每页大小 6 | 7 | Keyword string `json:"keyword"` // 搜索关键字 8 | } 9 | -------------------------------------------------------------------------------- /go_api_server/service/enter.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | type ServiceGroup struct { 4 | UserService 5 | MeetingService 6 | MessageService 7 | UploadAndDownloadService 8 | } 9 | 10 | var ServiceGroupApp = new(ServiceGroup) 11 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame.xcodeproj/xcuserdata/yusael.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /go_api_server/config/application.yml: -------------------------------------------------------------------------------- 1 | #server: 2 | # port: 1016 3 | datasource: 4 | driverName: mysql 5 | host: 127.0.0.1 6 | port: 3306 7 | database: testpro # 修改成你的数据库名 8 | username: root # 修改成你自己的数据库用户名 9 | password: lzy123456 # 修改成你自己的数据库密码 10 | -------------------------------------------------------------------------------- /go_api_server/model/common/response/common.go: -------------------------------------------------------------------------------- 1 | package response 2 | 3 | type PageResult struct { 4 | Total interface{} `json:"total"` 5 | Page int `json:"page"` 6 | PageSize int `json:"pageSize"` 7 | Records interface{} `json:"records"` 8 | } 9 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/User/UserAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserAPI.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/4/2. 6 | // 7 | 8 | import Foundation 9 | 10 | class UserAPIObj: CommonApiObj { 11 | // 在这里添加基础 API 中没有的 API 12 | } 13 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/Meeting/MeetingAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MeetingAPI.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import Foundation 9 | 10 | class MeetingApiObj: CommonApiObj { 11 | // 在这里添加基础 API 中没有的 API 12 | } 13 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/Message/MessageAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessageAPI.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import Foundation 9 | 10 | class MessageAPIObj: CommonApiObj { 11 | // 在这里添加基础 API 中没有的 API 12 | } 13 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame.xcodeproj/project.xcworkspace/xcuserdata/yusael.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/szluyu99/ZYSwiftUIFrame/HEAD/ZYSwiftUIFrame/ZYSwiftUIFrame.xcodeproj/project.xcworkspace/xcuserdata/yusael.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/Message/MessageVM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessageVM.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import Foundation 9 | 10 | class MessageVM: CommonVM { 11 | init() { 12 | super.init(item: Message(), apiObj: MessageAPIObj(moduleUrl: "message")) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /go_api_server/model/upload_download.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type UploadAndDownload struct { 4 | BaseModel 5 | Name string `json:"name" gorm:"comment:文件名"` // 文件名 6 | Url string `json:"url" gorm:"comment:文件地址"` // 文件地址 7 | Tag string `json:"tag" gorm:"comment:文件标签"` // 文件标签 8 | Key string `json:"key" gorm:"comment:编号"` // 编号 9 | 10 | MeetingID int 11 | } 12 | -------------------------------------------------------------------------------- /go_api_server/router/sys_user.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/yusael/go_api_server/api" 6 | ) 7 | 8 | type UserRouter struct{} 9 | 10 | func (r *UserRouter) InitUserRouter(router *gin.Engine) { 11 | userRouter := router.Group("/user") 12 | 13 | userRouter.POST("/getPageList", api.ApiGroupApp.UserApi.GetPageList) 14 | } 15 | -------------------------------------------------------------------------------- /go_api_server/model/base_model.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type BaseModel struct { 8 | ID uint `json:"id" gorm:"primarykey"` // 主键ID 9 | CreatedAt time.Time `json:"createdAt"` // 创建时间 10 | UpdatedAt time.Time `json:"updatedAt"` // 更新时间 11 | Remark string `json:"remark" gorm:"comment:备注"` // 备注 12 | } 13 | -------------------------------------------------------------------------------- /go_api_server/model/message.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Message struct { 4 | BaseModel 5 | Theme string `json:"theme" gorm:"comment:消息标题"` 6 | Content string `json:"content" gorm:"comment:消息内容"` 7 | IsRead int `json:"isRead" gorm:"comment:是否已读"` 8 | ReceiveUser int `json:"receiveUser" gorm:"comment:接收人id"` 9 | SendUser int `json:"sendUser" gorm:"comment:发送人id"` 10 | } 11 | -------------------------------------------------------------------------------- /go_api_server/model/sys_user.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type SysUser struct { 4 | BaseModel 5 | Username string `json:"username" gorm:"comment:用户登录名"` 6 | Password string `json:"password" gorm:"comment:用户登录密码"` 7 | Nickname string `json:"nickname" gorm:"comment:用户昵称"` 8 | Phone string `json:"phone" gorm:"comment:用户手机号码"` 9 | HeaderImg string `json:"headerImg" gorm:"default:https://qmplusimg.henrongyi.top/gva_header.jpg;comment:用户头像"` 10 | } 11 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/Assets.xcassets/head.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "鹿.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/Global/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import SwiftUI 9 | 10 | /** 11 | * 全局常量 12 | */ 13 | 14 | // 下拉刷新延时时间 15 | public let refreshTime: Double = 0.4 16 | // 加载更多延时时间 17 | public let loadMoreTime: Double = 0.3 18 | 19 | // 默认的列表条目内边距 20 | public let defaultListItemPadding: EdgeInsets = EdgeInsets(top: 15, leading: 15, bottom: 5, trailing: 15) 21 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame.xcodeproj/xcuserdata/yusael.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ZYSwiftUIFrame.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /go_api_server/router/message.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/yusael/go_api_server/api" 6 | ) 7 | 8 | type MessageRouter struct{} 9 | 10 | func (r *MessageRouter) InitMessageRouter(router *gin.Engine) { 11 | messageRouter := router.Group("/message") 12 | 13 | messageApi := api.ApiGroupApp.MessageApi 14 | { 15 | messageRouter.POST("/getPageList", messageApi.GetPageList) 16 | messageRouter.GET("/detail", messageApi.GetDetail) 17 | messageRouter.GET("/delete", messageApi.Delete) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/Api/ServerResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ServerResponse.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | /** 9 | * 通用响应实体 10 | */ 11 | struct ServerResponse: Codable { 12 | var code: Int 13 | var message: String 14 | var data: Model? 15 | var time: String 16 | } 17 | 18 | /* 19 | * 通用列表数据实体 20 | */ 21 | struct DataList: Codable { 22 | let total: Int 23 | var records: [Model] 24 | let page: Int 25 | let pageSize: Int 26 | } 27 | -------------------------------------------------------------------------------- /go_api_server/router/meeting.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/yusael/go_api_server/api" 6 | ) 7 | 8 | type MeetingRouter struct{} 9 | 10 | func (r *MeetingRouter) InitMeetingRouter(router *gin.Engine) { 11 | meetingRouter := router.Group("/meeting") 12 | 13 | meetingApi := api.ApiGroupApp.MeetingApi 14 | { 15 | meetingRouter.POST("/getPageList", meetingApi.GetPageList) 16 | meetingRouter.GET("/detail", meetingApi.GetDetail) 17 | meetingRouter.GET("/delete", meetingApi.Delete) 18 | meetingRouter.POST("/saveOrUpdate", meetingApi.SaveOrUpdate) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /go_api_server/router/upload_download.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/yusael/go_api_server/api" 6 | ) 7 | 8 | type uploadAndDownloadRouter struct{} 9 | 10 | func (f *uploadAndDownloadRouter) InitUploadAndDownloadRouter(router *gin.Engine) { 11 | fileUploadAndDownloadRouter := router.Group("/uploadAndDownload") 12 | 13 | uploadAndDownloadApi := api.ApiGroupApp.UploadAndDownloadApi 14 | { 15 | fileUploadAndDownloadRouter.POST("upload", uploadAndDownloadApi.UploadFile) 16 | fileUploadAndDownloadRouter.GET("delete", uploadAndDownloadApi.DeleteFile) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /go_api_server/api/enter.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import "github.com/yusael/go_api_server/service" 4 | 5 | type ApiGroup struct { 6 | UserApi UserApi 7 | MeetingApi MeetingApi 8 | MessageApi MessageApi 9 | UploadAndDownloadApi UploadAndDownloadApi 10 | } 11 | 12 | var ApiGroupApp = new(ApiGroup) 13 | 14 | var ( 15 | userService = service.ServiceGroupApp.UserService 16 | meetingService = service.ServiceGroupApp.MeetingService 17 | messageService = service.ServiceGroupApp.MessageService 18 | UploadAndDownloadService = service.ServiceGroupApp.UploadAndDownloadService 19 | ) 20 | -------------------------------------------------------------------------------- /go_api_server/router/enter.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | type RouterGroup struct { 6 | UserRouter 7 | MeetingRouter 8 | MessageRouter 9 | uploadAndDownloadRouter // 文件上传、下载 10 | } 11 | 12 | var RouterGroupApp = new(RouterGroup) 13 | 14 | func CollectionRoutes(r *gin.Engine) *gin.Engine { 15 | RouterGroupApp.InitUserRouter(r) // 注册用户路由 16 | RouterGroupApp.InitMeetingRouter(r) // 注册会议路由 17 | RouterGroupApp.InitMessageRouter(r) // 注册消息路由 18 | RouterGroupApp.InitUploadAndDownloadRouter(r) // 文件上传和下载 19 | 20 | // 允许访问本地文件 21 | r.Static("/uploads/file", "./uploads/file") 22 | 23 | return r 24 | } 25 | -------------------------------------------------------------------------------- /go_api_server/model/common/request/meeting.go: -------------------------------------------------------------------------------- 1 | package request 2 | 3 | type ChangeMeetingInfo struct { 4 | ID uint `json:"id" gorm:"primarykey"` 5 | MtName string `json:"mtName" gorm:"comment:会议名称"` 6 | MtTheme string `json:"mtTheme" gorm:"comment:会议主题"` 7 | MtSummary string `json:"mtSummary" gorm:"comment:会议概要"` 8 | MtContent string `json:"mtContent" gorm:"comment:会议内容"` 9 | MtMember string `json:"mtMember" gorm:"comment:参会人员"` 10 | MtTime string `json:"mtTime" gorm:"comment:开会时间"` 11 | CreateUser int `json:"createUser" gorm:"comment:创建人"` 12 | Remark string `json:"remark" gorm:"comment:备注"` // 备注 13 | // 1 个会议可以有多个 图片 14 | AnnexIds []int `json:"annexIds"` 15 | } 16 | -------------------------------------------------------------------------------- /go_api_server/model/common/response/meeting.go: -------------------------------------------------------------------------------- 1 | package response 2 | 3 | import "github.com/yusael/go_api_server/model" 4 | 5 | type MeetingResp struct { 6 | ID uint `json:"id" gorm:"primarykey"` 7 | // model.BaseModel 8 | MtName string `json:"mtName" gorm:"comment:会议名称"` 9 | MtTheme string `json:"mtTheme" gorm:"comment:会议主题"` 10 | MtSummary string `json:"mtSummary" gorm:"comment:会议概要"` 11 | MtContent string `json:"mtContent" gorm:"comment:会议内容"` 12 | MtMember string `json:"mtMember" gorm:"comment:参会人员"` 13 | MtTime string `json:"mtTime" gorm:"comment:开会时间"` 14 | CreateUser int `json:"createUser" gorm:"comment:创建人"` 15 | // 1 个会议可以有多个 图片 16 | AnList []model.UploadAndDownload `json:"anList" gorm:"foreignKey:MeetingID"` 17 | } 18 | -------------------------------------------------------------------------------- /go_api_server/api/sys_user.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/gin-gonic/gin" 7 | "github.com/yusael/go_api_server/model/common/request" 8 | "github.com/yusael/go_api_server/model/common/response" 9 | ) 10 | 11 | type UserApi struct{} 12 | 13 | // 分页获取用户列表 14 | func (u *UserApi) GetPageList(c *gin.Context) { 15 | var pageInfo request.PageInfo 16 | _ = c.ShouldBindJSON(&pageInfo) 17 | 18 | records, total, err := userService.GetUserInfoList(pageInfo) 19 | if err != nil { 20 | fmt.Println("分页获取用户列表失败!") 21 | response.FailWithMessage("获取失败", c) 22 | return 23 | } 24 | response.OkWithDetail(response.PageResult{ 25 | Records: records, 26 | Total: total, 27 | Page: pageInfo.Page, 28 | PageSize: pageInfo.PageSize, 29 | }, "获取成功", c) 30 | } 31 | -------------------------------------------------------------------------------- /go_api_server/model/meeting.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | ) 6 | 7 | type Meeting struct { 8 | BaseModel 9 | MtName string `json:"mtName" gorm:"comment:会议名称"` 10 | MtTheme string `json:"mtTheme" gorm:"comment:会议主题"` 11 | MtSummary string `json:"mtSummary" gorm:"comment:会议概要"` 12 | MtContent string `json:"mtContent" gorm:"comment:会议内容"` 13 | MtMember string `json:"mtMember" gorm:"comment:参会人员"` 14 | MtTime string `json:"mtTime" gorm:"comment:开会时间"` 15 | CreateUser int `json:"createUser" gorm:"comment:创建人"` 16 | // 1 个会议可以有多个 图片 17 | // AnList string `json:"anList" gorm:"commit:附件列表"` 18 | AnList []UploadAndDownload `json:"anList"` // 外键 19 | } 20 | 21 | // 钩子函数: 在更新时进行调用 22 | func (m *Meeting) BeforeUpdate(scope *gorm.DB) (err error) { 23 | return nil 24 | } 25 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/Api/UploadApi.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UploadApi.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/4/2. 6 | // 7 | 8 | import Alamofire 9 | import UIKit 10 | 11 | class UploadApi: BaseAPI { 12 | // 上传图片 13 | static func uploadImage(image: UIImage, completion: @escaping (Result, Error>) -> Void) { 14 | NetworkManager.shared.uploadImg(image: image, to: "uploadAndDownload/upload", params: [:]) { result in 15 | switch result { 16 | case let .success(data): 17 | let parseResult: Result, Error> = super.parseData(data) 18 | completion(parseResult) 19 | case let .failure(error): 20 | completion(.failure(error)) 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /go_api_server/service/sys_user.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/yusael/go_api_server/global" 7 | "github.com/yusael/go_api_server/model" 8 | "github.com/yusael/go_api_server/model/common/request" 9 | ) 10 | 11 | type UserService struct{} 12 | 13 | func (u *UserService) GetUserInfoList(info request.PageInfo) (records interface{}, total int64, err error) { 14 | limit := info.PageSize 15 | offset := info.PageSize * (info.Page - 1) 16 | db := global.DB.Model(&model.SysUser{}) 17 | if err = db.Count(&total).Error; err != nil { 18 | fmt.Println("GetUserInfoList Service Error!") 19 | return 20 | } 21 | var userRecords []model.SysUser 22 | // Limit 指定获取记录的最大数量 Offset 指定在开始返回记录之前要跳过的记录数量 23 | err = db.Limit(limit).Offset(offset).Find(&userRecords).Error 24 | return userRecords, total, err 25 | } 26 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/Message/Message.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Message.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | /** 9 | * 消息实体类 10 | */ 11 | struct Message: Codable, Identifiable, Equatable { 12 | static func == (lhs: Message, rhs: Message) -> Bool { 13 | return lhs.content == rhs.content 14 | && lhs.theme == rhs.theme 15 | } 16 | 17 | @Default var id: Int 18 | @Default var theme: String // 标题 19 | @Default var content: String // 内容 20 | @Default var receiveUser: Int // 接收人id 21 | @Default var sendUser: Int // 发送人id 22 | @Default var isRead: Int // 已读 0否1是 23 | @Default var createdAt: String // 创建时间 24 | 25 | init() { 26 | self.id = -1 27 | self.receiveUser = -1 28 | self.sendUser = -1 29 | self.theme = "" 30 | self.content = "" 31 | self.isRead = 0 32 | self.createdAt = "暂时没有时间数据......" 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /go_api_server/api/upload_download.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/gin-gonic/gin" 7 | "github.com/yusael/go_api_server/model/common/response" 8 | ) 9 | 10 | type UploadAndDownloadApi struct{} 11 | 12 | // 上传文件 13 | func (u *UploadAndDownloadApi) UploadFile(c *gin.Context) { 14 | fileHeader, err := c.FormFile("file") 15 | if err != nil { 16 | response.FailWithMessage("接收文件失败!", c) 17 | return 18 | } 19 | file, err := UploadAndDownloadService.UploadFile(fileHeader, c) 20 | if err != nil { 21 | response.FailWithMessage("修改数据库链接失败", c) 22 | return 23 | } 24 | response.OkWithDetail(file, "上传成功", c) 25 | } 26 | 27 | // 删除文件 28 | func (u *UploadAndDownloadApi) DeleteFile(c *gin.Context) { 29 | id, err := strconv.Atoi(c.Query("id")) 30 | if err != nil { 31 | response.FailWithMessage("获取参数信息失败", c) 32 | return 33 | } 34 | if err := UploadAndDownloadService.DeleteFile(uint(id)); err != nil { 35 | response.FailWithMessage("删除文件失败", c) 36 | return 37 | } 38 | response.OkWithMessage("操作成功", c) 39 | } 40 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/Map/MapNavigation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MapNavigation.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/4/4. 6 | // 7 | 8 | import Foundation 9 | import StoreKit 10 | 11 | // 跳转高德地图 12 | struct MapNavigation { 13 | // 根据经纬度、名称,打开高德地图导航进行跳转 14 | static func showLocation(_ name: String, lat: String, lng: String) { 15 | 16 | let urlStr = "iosamap://viewMap?sourceApplication=application&poiname=\(name)&lat=\(lat)&lon=\(lng)&dev=1" 17 | .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) 18 | 19 | let url = URL(string: urlStr!) 20 | 21 | if UIApplication.shared.canOpenURL(url!) { 22 | // 跳转高德地图 23 | UIApplication.shared.open(url!, options: [:], completionHandler: nil) 24 | } else { 25 | // 跳转应用商店 26 | let urlString = URL(string:"itms-apps://itunes.apple.com/app/id461703208") 27 | UIApplication.shared.open(urlString!, options: [:], completionHandler: nil) 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /go_api_server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/gin-gonic/gin" 8 | "github.com/spf13/viper" 9 | "github.com/yusael/go_api_server/common" 10 | "github.com/yusael/go_api_server/router" 11 | "github.com/yusael/go_api_server/service" 12 | ) 13 | 14 | func main() { 15 | // 初始化 Viper 的配置文件 16 | InitViperConfig() 17 | 18 | // 初始化数据库 19 | common.InitDB() 20 | // 初始化数据库数据 21 | InitDBData() 22 | 23 | r := gin.Default() 24 | r = router.CollectionRoutes(r) // 注册路由 25 | 26 | r.Run() // 监听并在 0.0.0.0:8080 上启动服务 27 | } 28 | 29 | // 读取配置文件 30 | func InitViperConfig() { 31 | workDir, _ := os.Getwd() 32 | viper.SetConfigName("application") // 文件名 33 | viper.SetConfigType("yml") // 文件类型 34 | viper.AddConfigPath(workDir + "/config") // 文件路径 35 | if err := viper.ReadInConfig(); err != nil { 36 | fmt.Println("configuration reading failed: ", err) 37 | panic(err) // 程序终止运行 38 | } 39 | fmt.Println("configuration reading successed!") 40 | } 41 | 42 | // 初始化数据库数据 43 | func InitDBData() { 44 | service.ServiceGroupApp.InitMessageData() 45 | service.ServiceGroupApp.InitMeetingData() 46 | } 47 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/ZYSwiftUIFrameApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ZYSwiftUIFrameApp.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import SwiftUI 9 | 10 | class AppDelegate: NSObject, UIApplicationDelegate { 11 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { 12 | // 设置消息推送可以在前台显示 ① 13 | UNUserNotificationCenter.current().delegate = self 14 | return true 15 | } 16 | } 17 | extension AppDelegate: UNUserNotificationCenterDelegate { 18 | func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { 19 | completionHandler([.alert, .badge, .sound]) // 设置消息推送可以在前台显示 ② 20 | } 21 | } 22 | 23 | @main 24 | struct ZYSwiftUIFrameApp: App { 25 | // 设置消息推送可以在前台显示 ③ 26 | @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate 27 | 28 | var body: some Scene { 29 | WindowGroup { 30 | ContentView() 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/Upload/Upload.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Upload.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/4/2. 6 | // 7 | 8 | // 文件上传对象(图片) 9 | struct Upload: Codable, Identifiable { 10 | @Default var id: Int 11 | @Default var name: String 12 | @Default var url: String 13 | @Default var tag: String 14 | @Default var key: String 15 | 16 | // enum CodingKeys: String, CodingKey { 17 | // case id, name, url, tag, key 18 | // } 19 | 20 | init() { 21 | self.id = 0 22 | self.name = "" 23 | self.url = "" 24 | self.tag = "" 25 | self.key = "" 26 | } 27 | 28 | // init(from decoder: Decoder) throws { 29 | // let container = try decoder.container(keyedBy: CodingKeys.self) 30 | // id = try container.decodeIfPresent(Int.self, forKey: .id) ?? 0 31 | // name = try container.decodeIfPresent(String.self, forKey: .name) ?? "" 32 | // url = try container.decodeIfPresent(String.self, forKey: .url) ?? "" 33 | // tag = try container.decodeIfPresent(String.self, forKey: .tag) ?? "" 34 | // key = try container.decodeIfPresent(String.self, forKey: .key) ?? "" 35 | // } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/User/User.swift: -------------------------------------------------------------------------------- 1 | // 2 | // User.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/4/2. 6 | // 7 | 8 | import Foundation 9 | 10 | struct User: Codable, Identifiable, Equatable { 11 | static func == (lhs: User, rhs: User) -> Bool { 12 | return lhs.username == rhs.username 13 | && lhs.nickname == rhs.nickname 14 | && lhs.phone == rhs.phone 15 | } 16 | 17 | var id: Int? // id 可以为 nil 是为了区分 新增 和 更新 18 | @Default var username: String 19 | @Default var password: String 20 | @Default var nickname: String 21 | @Default var phone: String 22 | @Default var headerImg: String 23 | 24 | init() { 25 | self.username = "" 26 | self.password = "" 27 | self.nickname = "" 28 | self.phone = "" 29 | self.headerImg = "" 30 | } 31 | 32 | init(username: String, password: String, nickname: String, phone: String, headerImg: String) { 33 | self.id = Int.random(in: 1...100000) // 随机数模拟 ID 34 | self.username = username 35 | self.password = password 36 | self.nickname = nickname 37 | self.phone = phone 38 | self.headerImg = headerImg 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/Message/MessageDetailView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessageDetailView.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct MessageDetailView: View { 11 | @StateObject var viewModel: MessageVM 12 | let id: Int 13 | 14 | var body: some View { 15 | List { 16 | Text(viewModel.item.theme) 17 | .font(.system(size: 24)) 18 | .padding(.vertical, 7) 19 | VStack(alignment: .leading) { 20 | Text(viewModel.item.createdAt.prefix(10)) 21 | .font(.subheadline) 22 | .opacity(0.5) 23 | Text(viewModel.item.content) 24 | .font(.system(size: 18)) 25 | .fixedSize(horizontal: false, vertical: true) 26 | .padding(.vertical) 27 | } 28 | } 29 | .navigationBarTitle("消息详情", displayMode: .inline) 30 | .onAppear { 31 | // 获取数据详情 32 | viewModel.fetchDetail(id: id) {} 33 | } 34 | } 35 | } 36 | 37 | //struct MessageDetailView_Previews: PreviewProvider { 38 | // static var previews: some View { 39 | // MessageDetailView() 40 | // } 41 | //} 42 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/Meeting/MeetingVM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MeetingVM.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import Foundation 9 | 10 | class MeetingVM: CommonVM { 11 | // 搜索条件 12 | @Published var mtName: String = "" 13 | 14 | init() { 15 | super.init(item: Meeting(), apiObj: MeetingApiObj(moduleUrl: "meeting")) 16 | } 17 | 18 | func filterData() { 19 | filterParams = [:] 20 | if !mtName.isBlank { 21 | filterParams["keyword"] = mtName 22 | } 23 | 24 | // 每次筛选重置页数 25 | filterParams["pageIndex"] = 1 26 | 27 | print(filterParams) 28 | 29 | super.thisAPI.list(parameters: filterParams) { result in 30 | switch result { 31 | case let .success(data): 32 | print(data) 33 | guard let res = data.data else { 34 | return 35 | } 36 | self.items = res.records 37 | print(res.records) 38 | self.page = res.page + 1 39 | self.total = res.total 40 | case let .failure(error): 41 | print("获取组织架构列表失败 \(error.localizedDescription)") 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /go_api_server/model/common/response/response.go: -------------------------------------------------------------------------------- 1 | package response 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/gin-gonic/gin" 7 | ) 8 | 9 | type Response struct { 10 | Code int `json:"code"` 11 | Msg string `json:"message"` 12 | Data interface{} `json:"data"` 13 | Time string `json:"time"` 14 | } 15 | 16 | const ( 17 | ERROR = 7 18 | SUCCESS = 0 19 | ) 20 | 21 | func Result(code int, data interface{}, msg string, c *gin.Context) { 22 | c.JSON(SUCCESS, Response{code, msg, data, time.Now().Format("2006-01-02 15:04:05")}) 23 | } 24 | 25 | func Ok(c *gin.Context) { 26 | Result(SUCCESS, nil, "操作成功", c) 27 | } 28 | 29 | func OkWithMessage(message string, c *gin.Context) { 30 | Result(SUCCESS, nil, message, c) 31 | } 32 | 33 | func OkWithData(data interface{}, c *gin.Context) { 34 | Result(SUCCESS, data, "操作成功", c) 35 | } 36 | 37 | func OkWithDetail(data interface{}, message string, c *gin.Context) { 38 | Result(SUCCESS, data, message, c) 39 | } 40 | 41 | func Fail(c *gin.Context) { 42 | Result(ERROR, map[string]interface{}{}, "操作失败", c) 43 | } 44 | 45 | func FailWithMessage(message string, c *gin.Context) { 46 | Result(ERROR, map[string]interface{}{}, message, c) 47 | } 48 | 49 | func FailWithDetail(data interface{}, message string, c *gin.Context) { 50 | Result(ERROR, data, message, c) 51 | } 52 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UIFrame/Enhance/CodableDefault.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CodableDefault.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | // 用于给 Codable 协议添加默认值 9 | protocol DefaultValue { 10 | associatedtype Value: Codable 11 | static var defaultValue: Value { get } 12 | } 13 | 14 | @propertyWrapper 15 | struct Default { 16 | var wrappedValue: T.Value 17 | } 18 | 19 | extension Default: Codable { 20 | init(from decoder: Decoder) throws { 21 | let container = try decoder.singleValueContainer() 22 | wrappedValue = (try? container.decode(T.Value.self)) ?? T.defaultValue 23 | } 24 | } 25 | 26 | extension KeyedDecodingContainer { 27 | func decode(_ type: Default.Type, forKey key: Key) throws -> Default where T: DefaultValue { 28 | // 判断 key 缺失的情况,提供默认值 29 | (try decodeIfPresent(type, forKey: key)) ?? Default(wrappedValue: T.defaultValue) 30 | } 31 | } 32 | extension KeyedEncodingContainer { 33 | mutating func encode(_ value: Default, forKey key: Key) throws where T : DefaultValue { 34 | try encodeIfPresent(value.wrappedValue, forKey: key) 35 | } 36 | } 37 | 38 | extension Int: DefaultValue { 39 | static var defaultValue = -1 40 | } 41 | 42 | extension String: DefaultValue { 43 | static var defaultValue = "" 44 | } 45 | -------------------------------------------------------------------------------- /go_api_server/api/message.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/gin-gonic/gin" 7 | "github.com/yusael/go_api_server/model/common/request" 8 | "github.com/yusael/go_api_server/model/common/response" 9 | ) 10 | 11 | type MessageApi struct{} 12 | 13 | // 分页获取消息列表 14 | func (m *MessageApi) GetPageList(c *gin.Context) { 15 | var pageInfo request.PageInfo 16 | _ = c.ShouldBindJSON(&pageInfo) 17 | 18 | records, total, err := messageService.GetMessageList(pageInfo) 19 | if err != nil { 20 | response.FailWithMessage("获取失败", c) 21 | return 22 | } 23 | response.OkWithDetail(response.PageResult{ 24 | Total: total, 25 | Page: pageInfo.Page, 26 | PageSize: pageInfo.PageSize, 27 | Records: records, 28 | }, "获取成功", c) 29 | } 30 | 31 | // 获取消息详情 32 | func (m *MessageApi) GetDetail(c *gin.Context) { 33 | id, _ := strconv.Atoi(c.Query("id")) 34 | message, err := messageService.GetMessageDetail(id) 35 | if err != nil { 36 | response.FailWithMessage("数据不存在", c) 37 | return 38 | } 39 | response.OkWithDetail(message, "操作成功", c) 40 | } 41 | 42 | // 删除消息 43 | func (m *MessageApi) Delete(c *gin.Context) { 44 | id, _ := strconv.Atoi(c.Query("id")) 45 | if err := messageService.DeleteMessageDetail(id); err != nil { 46 | response.FailWithMessage("操作失败", c) 47 | return 48 | } 49 | response.OkWithMessage("操作成功", c) 50 | } 51 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/Meeting/Meeting.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Meeting.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | /** 9 | * 会议实体类 10 | */ 11 | struct Meeting: Codable, Identifiable, Equatable { 12 | static func == (lhs: Meeting, rhs: Meeting) -> Bool { 13 | return lhs.mtName == rhs.mtName 14 | && lhs.mtSummary == rhs.mtSummary 15 | && lhs.mtTheme == rhs.mtTheme 16 | && lhs.mtTime == rhs.mtTime 17 | } 18 | 19 | var id: Int? // id 可以为 nil 是为了区分 新增 和 更新 20 | @Default var mtName: String 21 | @Default var mtTheme: String 22 | @Default var mtSummary: String 23 | @Default var mtContent: String 24 | @Default var mtMember: String 25 | @Default var mtTime: String 26 | @Default var remark: String 27 | @Default var createUser: Int 28 | 29 | var anList: [Upload] // 附件列表 30 | // 新增参数 31 | var annexIds: [Int]? // 附件Id数组 32 | 33 | init() { 34 | self.mtName = "" 35 | self.mtTheme = "" 36 | self.mtSummary = "" 37 | self.mtContent = "" 38 | self.mtMember = "" 39 | self.mtTime = "" 40 | self.remark = "" 41 | self.createUser = -1 42 | self.anList = [] 43 | 44 | self.annexIds = [] 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /go_api_server/common/database.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/viper" 7 | "github.com/yusael/go_api_server/global" 8 | "github.com/yusael/go_api_server/model" 9 | "gorm.io/driver/mysql" 10 | "gorm.io/gorm" 11 | "gorm.io/gorm/schema" 12 | ) 13 | 14 | func InitDB() *gorm.DB { 15 | // 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情 16 | // dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local" 17 | // db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) 18 | 19 | host := viper.GetString("datasource.host") 20 | port := viper.GetString("datasource.port") 21 | database := viper.GetString("datasource.database") 22 | username := viper.GetString("datasource.username") 23 | password := viper.GetString("datasource.password") 24 | 25 | dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", 26 | username, password, host, port, database) 27 | DB, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ 28 | SkipDefaultTransaction: true, // 跳过默认事务 29 | NamingStrategy: schema.NamingStrategy{ 30 | SingularTable: true, // 使用单数表名, `User` 的表名为 `user` 31 | }, 32 | DisableForeignKeyConstraintWhenMigrating: true, // 禁用外键, 使用逻辑外键 33 | }) 34 | if err != nil { 35 | panic("failed to connect database, err: " + err.Error()) 36 | } 37 | fmt.Println("connect database successfully!") 38 | 39 | DB.AutoMigrate(&model.UploadAndDownload{}, &model.SysUser{}, &model.Meeting{}, &model.Message{}) 40 | global.DB = DB // 注册到全局对象 41 | return DB 42 | } 43 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UIFrame/Refresh/ZYRefreshView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ZYRefreshView.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import SwiftUI 9 | import BBSwiftUIKit 10 | 11 | // 通用的 刷新页面 12 | struct ZYRefreshView: View 13 | where Model: Equatable, Model: Identifiable { 14 | // 通用 ViewModel 15 | @StateObject var viewModel: CommonVM 16 | 17 | // 列表条目 18 | @ViewBuilder var listItem: (Model) -> ListItem 19 | 20 | var body: some View { 21 | if viewModel.total != 0 { 22 | BBTableView(viewModel.items) { item in 23 | listItem(item) 24 | } 25 | .bb_reloadData($viewModel.isReloadData) 26 | .bb_pullDownToRefresh(isRefreshing: $viewModel.isRefreshing) { 27 | DispatchQueue.main.asyncAfter(deadline: .now() + refreshTime) { 28 | viewModel.fetchData { 29 | viewModel.isRefreshing = false 30 | } 31 | } 32 | } 33 | .bb_pullUpToLoadMore(bottomSpace: 40) { 34 | if viewModel.isLoadingMore{ return } 35 | viewModel.isLoadingMore = true 36 | DispatchQueue.main.asyncAfter(deadline: .now() + loadMoreTime) { 37 | viewModel.fetchMoreData { 38 | viewModel.isLoadingMore = false 39 | } 40 | } 41 | } 42 | } else { 43 | Text("当前没有数据!") 44 | } 45 | 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/About/AboutView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // About.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/4/2. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct AboutView: View { 11 | var body: some View { 12 | List { 13 | HeadRow() 14 | Link(destination: URL(string: "https://luzhenyu.blog.csdn.net")!) { 15 | Text("个人博客") 16 | } 17 | Link(destination: URL(string: "https://github.com/szluyu99")!) { 18 | Text("GitHub: https://github.com/szluyu99") 19 | } 20 | Link(destination: URL(string: "https://gitee.com/szluyu99")!) { 21 | Text("Gitee: https://gitee.com/szluyu99") 22 | } 23 | Text("联系作者:可以通过博客私信我~") 24 | } 25 | .listStyle(GroupedListStyle()) 26 | .navigationBarTitle("个人信息", displayMode: .inline) 27 | } 28 | 29 | struct HeadRow: View { 30 | var body: some View { 31 | HStack { 32 | Image("head") 33 | .resizable() 34 | .frame(width: 100, height: 100) 35 | .padding(8) 36 | .clipShape(Circle()) 37 | VStack(alignment: .leading) { 38 | Text("萌宅鹿") 39 | .font(.title) 40 | Text("学校:江苏大学") 41 | .font(.subheadline).opacity(0.5) 42 | Text("专业:计算机研一") 43 | .font(.subheadline).opacity(0.5) 44 | Text("本职:后端开发 + 前端开发 ") 45 | .font(.subheadline).opacity(0.5) 46 | } 47 | } 48 | } 49 | } 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/Map/LocationViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocationViewModel.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/4/4. 6 | // 7 | 8 | import Foundation 9 | import CoreLocation 10 | 11 | class LocationViewModel: NSObject, ObservableObject, CLLocationManagerDelegate { 12 | @Published var authorizationStatus: CLAuthorizationStatus 13 | @Published var lastSeenLocation: CLLocation? 14 | @Published var currentPlacemark: CLPlacemark? 15 | 16 | private let locationManager: CLLocationManager 17 | 18 | override init() { 19 | locationManager = CLLocationManager() 20 | authorizationStatus = locationManager.authorizationStatus 21 | 22 | super.init() 23 | locationManager.delegate = self 24 | locationManager.desiredAccuracy = kCLLocationAccuracyBest 25 | locationManager.distanceFilter = 0.4 26 | locationManager.startUpdatingLocation() 27 | } 28 | 29 | func requestPermission() { 30 | locationManager.requestWhenInUseAuthorization() 31 | } 32 | 33 | func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { 34 | authorizationStatus = manager.authorizationStatus 35 | } 36 | 37 | func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { 38 | lastSeenLocation = locations.first 39 | fetchCountryAndCity(for: locations.first) 40 | } 41 | 42 | func fetchCountryAndCity(for location: CLLocation?) { 43 | guard let location = location else { return } 44 | let geocoder = CLGeocoder() 45 | geocoder.reverseGeocodeLocation(location) { (placemarks, error) in 46 | self.currentPlacemark = placemarks?.first 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /go_api_server/service/message.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/yusael/go_api_server/global" 8 | "github.com/yusael/go_api_server/model" 9 | "github.com/yusael/go_api_server/model/common/request" 10 | ) 11 | 12 | type MessageService struct{} 13 | 14 | func (m *MessageService) GetMessageList(info request.PageInfo) (records interface{}, total int64, err error) { 15 | limit := info.PageSize 16 | offset := info.PageSize * (info.Page - 1) 17 | db := global.DB.Model(&model.Message{}) 18 | if err = db.Count(&total).Error; err != nil { 19 | fmt.Println("GetMessageList Service Error!") 20 | return 21 | } 22 | var messageRecords []model.Message 23 | err = db.Limit(limit).Offset(offset).Find(&messageRecords).Error 24 | return messageRecords, total, err 25 | } 26 | 27 | func (m *MessageService) GetMessageDetail(id int) (message model.Message, err error) { 28 | err = global.DB.Where("id = ?", id).First(&message).Error 29 | return message, err 30 | } 31 | 32 | func (m *MessageService) DeleteMessageDetail(id int) (err error) { 33 | err = global.DB.Where("id = ?", id).Delete(&model.Message{}).Error 34 | return err 35 | } 36 | 37 | // 初始化数据库数据: 有数据就不初始化, 没有数据则增加 50 条数据 38 | func (m *MessageService) InitMessageData() { 39 | var count int64 40 | if global.DB.Model(&model.Message{}).Count(&count); count != 0 { 41 | return 42 | } 43 | 44 | messageList := make([]model.Message, 0) 45 | for i := 0; i < 50; i++ { 46 | messageList = append(messageList, model.Message{ 47 | Theme: fmt.Sprintf("消息主题%v", i), 48 | Content: strings.Repeat(fmt.Sprintf("这是消息的具体内容%v", i), 5), 49 | IsRead: 0, 50 | ReceiveUser: 0, 51 | SendUser: 0, 52 | }) 53 | } 54 | if err := global.DB.Create(&messageList).Error; err != nil { 55 | fmt.Println("InitMessageData Error!") 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UIFrame/Common/CommonText.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CommonText.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import SwiftUI 9 | 10 | // 多行文本输入框 using... 11 | struct CommonTextEditor: View { 12 | let text: String 13 | @Binding var value: String 14 | 15 | var body: some View { 16 | HStack { 17 | Text("\(text):") 18 | .frame(height: 40, alignment: .leading) 19 | .minimumScaleFactor(0.5) 20 | TextEditor(text: $value) 21 | } 22 | } 23 | } 24 | 25 | // 单行文本输入框 using... 26 | struct CommonTextField: View { 27 | let text: String 28 | @Binding var value: String 29 | 30 | var body: some View { 31 | HStack { 32 | Text("\(text):") 33 | .frame(width: 100, alignment: .leading) 34 | TextField(text, text: $value) 35 | } 36 | } 37 | } 38 | 39 | // 日期选择框 using... 40 | struct CommonDatePicker: View { 41 | let text: String 42 | @Binding var value: Date 43 | 44 | var body: some View { 45 | HStack { 46 | DatePicker(selection: $value, displayedComponents: [.date]) { 47 | Text("\(text):") 48 | .frame(height: 40) 49 | } 50 | .environment(\.locale, Locale.init(identifier: "zh_CN")) 51 | } 52 | } 53 | } 54 | 55 | // 多行文本(备注) 56 | struct RemarkField: View { 57 | @Binding var remark: String 58 | @ViewBuilder var content: Content 59 | 60 | var body: some View { 61 | HStack { 62 | content 63 | TextEditor(text: $remark) 64 | .frame(minHeight: 100) 65 | .overlay(RoundedRectangle(cornerRadius: 10).stroke(lineWidth: 1)) 66 | } 67 | .padding(.vertical) 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /go_api_server/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/yusael/go_api_server 2 | 3 | go 1.17 4 | 5 | require gorm.io/gorm v1.23.3 6 | 7 | require ( 8 | github.com/fsnotify/fsnotify v1.5.1 // indirect 9 | github.com/go-sql-driver/mysql v1.6.0 // indirect 10 | github.com/hashicorp/hcl v1.0.0 // indirect 11 | github.com/magiconair/properties v1.8.5 // indirect 12 | github.com/mitchellh/mapstructure v1.4.3 // indirect 13 | github.com/pelletier/go-toml v1.9.4 // indirect 14 | github.com/spf13/afero v1.6.0 // indirect 15 | github.com/spf13/cast v1.4.1 // indirect 16 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 17 | github.com/spf13/pflag v1.0.5 // indirect 18 | github.com/subosito/gotenv v1.2.0 // indirect 19 | gopkg.in/ini.v1 v1.66.2 // indirect 20 | ) 21 | 22 | require ( 23 | github.com/gin-contrib/sse v0.1.0 // indirect 24 | github.com/gin-gonic/gin v1.7.7 // indirect 25 | github.com/go-playground/locales v0.14.0 // indirect 26 | github.com/go-playground/universal-translator v0.18.0 // indirect 27 | github.com/go-playground/validator/v10 v10.10.1 // indirect 28 | github.com/golang/protobuf v1.5.2 // indirect 29 | github.com/jinzhu/inflection v1.0.0 // indirect 30 | github.com/jinzhu/now v1.1.4 // indirect 31 | github.com/json-iterator/go v1.1.12 // indirect 32 | github.com/leodido/go-urn v1.2.1 // indirect 33 | github.com/mattn/go-isatty v0.0.14 // indirect 34 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 35 | github.com/modern-go/reflect2 v1.0.2 // indirect 36 | github.com/spf13/viper v1.10.1 37 | github.com/ugorji/go/codec v1.2.7 // indirect 38 | golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 // indirect 39 | golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886 // indirect 40 | golang.org/x/text v0.3.7 // indirect 41 | google.golang.org/protobuf v1.28.0 // indirect 42 | gopkg.in/yaml.v2 v2.4.0 // indirect 43 | gorm.io/driver/mysql v1.3.2 44 | ) 45 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/Api/CommonApiObj.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CommonApiObj.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | /** 9 | * 实例变量的方式使用 API 10 | */ 11 | import Alamofire 12 | 13 | class CommonApiObj where T : Codable { 14 | 15 | var moduleUrl: String 16 | 17 | // 传入模块名 18 | init(moduleUrl: String) { 19 | self.moduleUrl = moduleUrl 20 | } 21 | 22 | // 获取基本信息列表 23 | func list(parameters: Parameters, 24 | completion: @escaping (Result>, Error>) -> Void) { 25 | BaseAPI.getList(path: "\(self.moduleUrl)/getPageList", parameters: parameters, completion: completion) 26 | } 27 | 28 | // 获取基本信息详情 29 | func detail(id: Int, completion: @escaping (Result, Error>) -> Void) { 30 | BaseAPI.getDetail(path: "\(self.moduleUrl)/detail?id=\(id)", id: id, completion: completion) 31 | } 32 | 33 | // 新增 34 | func save(obj: T, completion: @escaping (Result, Error>) -> Void) { 35 | BaseAPI.saveOrUpdate(path: "\(self.moduleUrl)/saveOrUpdate", obj: obj, completion: completion) 36 | } 37 | 38 | // 更新 39 | func update(obj: T, completion: @escaping(Result, Error>) -> Void) { 40 | BaseAPI.saveOrUpdate(path: "\(self.moduleUrl)/saveOrUpdate", obj: obj, completion: completion) 41 | } 42 | 43 | // // 新增 / 更新 44 | // func saveOrUpdate(obj: T, completion: @escaping (Result, Error>) -> Void) { 45 | // BaseAPI.saveOrUpdate(path: "\(self.moduleUrl)/saveOrUpdate", obj: obj, completion: completion) 46 | // } 47 | // 48 | // 删除 49 | func delete(id: Int, completion: @escaping(Result, Error>) -> Void) { 50 | BaseAPI.delete(path: "\(self.moduleUrl)/delete?id=\(id)", id: id, completion: completion) 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /go_api_server/api/meeting.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | 7 | "github.com/gin-gonic/gin" 8 | "github.com/yusael/go_api_server/model/common/request" 9 | "github.com/yusael/go_api_server/model/common/response" 10 | ) 11 | 12 | type MeetingApi struct{} 13 | 14 | // 分页获取会议列表 15 | func (m *MeetingApi) GetPageList(c *gin.Context) { 16 | var pageInfo request.PageInfo 17 | 18 | _ = c.ShouldBindJSON(&pageInfo) 19 | 20 | records, total, err := meetingService.GetMeetingList(pageInfo) 21 | if err != nil { 22 | response.FailWithMessage("获取失败", c) 23 | return 24 | } 25 | response.OkWithDetail(response.PageResult{ 26 | Total: total, 27 | Page: pageInfo.Page, 28 | PageSize: pageInfo.PageSize, 29 | Records: records, 30 | }, "获取成功", c) 31 | } 32 | 33 | // 获取详情 34 | func (m *MeetingApi) GetDetail(c *gin.Context) { 35 | id, _ := strconv.Atoi(c.Query("id")) 36 | meeting, err := meetingService.GetMeetingDetail(id) 37 | if err != nil { 38 | response.FailWithMessage("操作失败", c) 39 | return 40 | } 41 | response.OkWithDetail(meeting, "操作成功", c) 42 | } 43 | 44 | // 删除 45 | func (m *MeetingApi) Delete(c *gin.Context) { 46 | id, _ := strconv.Atoi(c.Query("id")) 47 | 48 | if _, err := meetingService.GetMeetingDetail(id); err != nil { 49 | response.FailWithMessage("删除失败,没有这条数据", c) 50 | return 51 | } 52 | if err := meetingService.DeleteMeeting(id); err != nil { 53 | response.FailWithMessage(fmt.Sprintf("删除失败:%v", err), c) 54 | return 55 | } 56 | response.OkWithMessage("删除成功", c) 57 | } 58 | 59 | // 新增 / 更新 60 | func (m *MeetingApi) SaveOrUpdate(c *gin.Context) { 61 | var meetingReq request.ChangeMeetingInfo 62 | if err := c.ShouldBindJSON(&meetingReq); err != nil { 63 | response.FailWithMessage(fmt.Sprintf("传递参数有误:%s", err), c) 64 | return 65 | } 66 | if err := meetingService.SaveOrUpdateMeeting(&meetingReq); err != nil { 67 | response.FailWithMessage(fmt.Sprintf("操作失败:%s", err), c) 68 | return 69 | } 70 | response.OkWithMessage("操作成功", c) 71 | } 72 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ContentView: View { 11 | var body: some View { 12 | NavigationView { 13 | List { 14 | NavigationLink(destination: MessageListView()) { 15 | HStack { 16 | Text("消息列表") 17 | Spacer() 18 | Text("(需要开启服务端)") 19 | .foregroundColor(.red) 20 | } 21 | } 22 | NavigationLink(destination: MeetingListView()) { 23 | HStack { 24 | Text("会议列表") 25 | Spacer() 26 | Text("(需要开启服务端)") 27 | .foregroundColor(.red) 28 | } 29 | } 30 | NavigationLink(destination: UserListView()) { 31 | HStack { 32 | Text("用户列表") 33 | Spacer() 34 | Text("(无需开启服务端)") 35 | } 36 | } 37 | NavigationLink(destination: MapDemo()) { 38 | HStack { 39 | Text("高德地图示例") 40 | Spacer() 41 | } 42 | } 43 | NavigationLink(destination: NotificationView()) { 44 | HStack { 45 | Text("本地消息推送") 46 | Spacer() 47 | } 48 | } 49 | NavigationLink(destination: AboutView()) { 50 | Text("关于作者") 51 | } 52 | } 53 | .navigationTitle("萌宅鹿的 IOS 框架") 54 | } 55 | } 56 | } 57 | 58 | struct ContentView_Previews: PreviewProvider { 59 | static var previews: some View { 60 | ContentView() 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "Alamofire", 6 | "repositoryURL": "https://gitee.com/idoing/Alamofire.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "f82c23a8a7ef8dc1a49a8bfc6a96883e79121864", 10 | "version": "5.5.0" 11 | } 12 | }, 13 | { 14 | "package": "BBSwiftUIKit", 15 | "repositoryURL": "https://gitee.com/RDCenter/BBSwiftUIKit.git", 16 | "state": { 17 | "branch": "master", 18 | "revision": "79acb0849c303be8bf955d1d1eea7893cdd52b2d", 19 | "version": null 20 | } 21 | }, 22 | { 23 | "package": "SDWebImage", 24 | "repositoryURL": "https://github.com/SDWebImage/SDWebImage.git", 25 | "state": { 26 | "branch": null, 27 | "revision": "2e63d0061da449ad0ed130768d05dceb1496de44", 28 | "version": "5.12.5" 29 | } 30 | }, 31 | { 32 | "package": "SDWebImageSwiftUI", 33 | "repositoryURL": "https://gitee.com/szluyu99/SDWebImageSwiftUI.git", 34 | "state": { 35 | "branch": "master", 36 | "revision": "336d3f6d3b53729c1f274bf6b75f4532ada116eb", 37 | "version": null 38 | } 39 | }, 40 | { 41 | "package": "SwiftUIImageViewer", 42 | "repositoryURL": "https://gitee.com/wei_wen_yue/swiftui-image-viewer", 43 | "state": { 44 | "branch": "master", 45 | "revision": "5e6d08be4d9fb7d417d902342b395be1c87e5bbb", 46 | "version": null 47 | } 48 | }, 49 | { 50 | "package": "URLImage", 51 | "repositoryURL": "https://gitee.com/wei_wen_yue/url-image.git", 52 | "state": { 53 | "branch": null, 54 | "revision": "ccab89ad1cedb04f25dd4df1776dd8c8583b914a", 55 | "version": "2.2.5" 56 | } 57 | } 58 | ] 59 | }, 60 | "version": 1 61 | } 62 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/User/UserDetailView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserDetailView.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/4/2. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct UserDetailView: View { 11 | @StateObject var viewModel: UserVM 12 | 13 | @Environment(\.presentationMode) var presentationMode: Binding 14 | 15 | // 根据传入 id 是否为 nil 判断新增还是更新 16 | var id: Int? 17 | 18 | var disableForm: Bool { 19 | viewModel.item.username.isBlank || viewModel.item.nickname.isBlank || viewModel.item.phone.isBlank 20 | } 21 | 22 | var body: some View { 23 | List { 24 | CommonTextField(text: "用户名", value: $viewModel.item.username) 25 | CommonTextField(text: "用户昵称", value: $viewModel.item.nickname) 26 | CommonTextField(text: "手机号", value: $viewModel.item.phone) 27 | submitButton(disableForm: disableForm) { saveOrUpdate() } 28 | } 29 | .onAppear { 30 | echoData() 31 | } 32 | .navigationTitle(id != nil ? "用户详情" : "新增用户") 33 | } 34 | 35 | // 更新界面需要回显数据 36 | private func echoData() { 37 | if let id = id { // 更新 - 回显数据 38 | viewModel.fetchDetail(id: id) { 39 | // 可以对一些特殊数据提前进行处理... 40 | } 41 | } else { // 新增 - 初始化数据 42 | viewModel.item = User() 43 | } 44 | } 45 | 46 | private func saveOrUpdate() { 47 | let item = viewModel.item 48 | 49 | // 本地项目不做过于真实的模拟, 仅仅演示出效果 50 | if self.id == nil { // 新增 51 | viewModel.addData(item: item) { result in 52 | self.presentationMode.wrappedValue.dismiss() 53 | } 54 | } else { // 更新 55 | viewModel.updateData(item: item) { result in 56 | self.presentationMode.wrappedValue.dismiss() 57 | } 58 | } 59 | } 60 | 61 | 62 | } 63 | 64 | //struct UserDetailView_Previews: PreviewProvider { 65 | // static var previews: some View { 66 | // UserDetailView() 67 | // } 68 | //} 69 | -------------------------------------------------------------------------------- /go_api_server/service/upload_download.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "mime/multipart" 7 | "os" 8 | "time" 9 | 10 | "github.com/gin-gonic/gin" 11 | "github.com/yusael/go_api_server/global" 12 | "github.com/yusael/go_api_server/model" 13 | "github.com/yusael/go_api_server/model/common/request" 14 | ) 15 | 16 | type UploadAndDownloadService struct{} 17 | 18 | // 创建文件上传记录 19 | func (u *UploadAndDownloadService) Upload(file *model.UploadAndDownload) error { 20 | return global.DB.Create(&file).Error 21 | } 22 | 23 | // 查询文件上传记录 24 | func (u *UploadAndDownloadService) FindFile(id uint) (model.UploadAndDownload, error) { 25 | var file model.UploadAndDownload 26 | err := global.DB.Where("id = ?", id).First(&file).Error 27 | return file, err 28 | } 29 | 30 | // 删除文件上传记录 31 | func (u *UploadAndDownloadService) DeleteFile(id uint) (err error) { 32 | var fileFromDB model.UploadAndDownload 33 | // 找不到文件则没法删除 34 | fileFromDB, err = u.FindFile(id) 35 | if err != nil { 36 | return 37 | } 38 | // 删除本地文件 39 | os.Remove(fileFromDB.Url) 40 | // 删除数据库中记录 41 | return global.DB.Where("id = ?", id).Delete(&model.UploadAndDownload{}).Error 42 | } 43 | 44 | // 分页获取文件列表 45 | func (u *UploadAndDownloadService) GetFileRecordList(info request.PageInfo) (list interface{}, total int64, err error) { 46 | limit := info.PageSize 47 | offset := info.PageSize * (info.Page - 1) 48 | db := global.DB.Model(&model.UploadAndDownload{}) 49 | var fileList []model.UploadAndDownload 50 | if err = db.Count(&total).Error; err != nil { 51 | return 52 | } 53 | err = db.Limit(limit).Offset(offset).Order("updated_at desc").Find(&fileList).Error 54 | return fileList, total, err 55 | } 56 | 57 | // 文件上传到本地 58 | func (u *UploadAndDownloadService) UploadFile(fileHeader *multipart.FileHeader, c *gin.Context) (file model.UploadAndDownload, err error) { 59 | // 上传文件到指定路径 60 | fileName := time.Now().Format("2006_01_02_15_04_05_") + fmt.Sprintf("%v", rand.Int63n(1000)) + fileHeader.Filename 61 | dst := "uploads/file/" + fileName 62 | if err = c.SaveUploadedFile(fileHeader, dst); err != nil { 63 | fmt.Println("uploadService uploadFile Error: ", err) 64 | return 65 | } 66 | 67 | f := model.UploadAndDownload{ 68 | Name: fileName, 69 | Url: dst, 70 | Tag: "普通文件", 71 | Key: "普通文件", 72 | } 73 | err = u.Upload(&f) 74 | return f, err 75 | } 76 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UIFrame/ImagePick/MultipleImagePickView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MultipleImagePickView.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/4/2. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct MultipleImagePickView: View { 11 | let text: String 12 | @Binding var imgList: [Upload] 13 | 14 | @State private var showImagePicker: Bool = false // 展示图片选择 15 | 16 | var body: some View { 17 | HStack { 18 | Text("\(text):") 19 | Spacer() 20 | // 选择图片 21 | Button { showImagePicker = true } label: { 22 | VStack { Image(systemName: "photo.fill") } 23 | } 24 | .buttonStyle(BorderlessButtonStyle()) 25 | .sheet(isPresented: $showImagePicker) { 26 | ImagePickerView(filter: .any(of: [.images, .livePhotos]), selectionLimit: 9, delegate: ImagePickerView.Delegate( 27 | isPresented: $showImagePicker, 28 | // 取消的回调 29 | didCancel: { phPickerViewController in 30 | print("Did Cancel: \(phPickerViewController)") 31 | }, 32 | // 选择图片后的回调 33 | didSelect: { result in 34 | let images = result.images 35 | for img in images { 36 | uploadImg(img: img) {} 37 | } 38 | }, 39 | // 失败的回调 40 | didFail: { (imagePickerError) in 41 | let phPickerViewController = imagePickerError.picker 42 | let error = imagePickerError.error 43 | print("Did Fail with error: \(error) in \(phPickerViewController)") 44 | })) 45 | } 46 | } 47 | } 48 | 49 | // 上传图片 50 | private func uploadImg(img: UIImage, complete: @escaping () -> Void) { 51 | UploadApi.uploadImage(image: img) { result in 52 | switch result { 53 | case let .success(data): 54 | print(data.data!) 55 | self.imgList.append(data.data!) 56 | complete() 57 | case let .failure(error): 58 | print("图片上传失败 \(error.localizedDescription)") 59 | } 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UIFrame/Common/ButtonView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ButtonView.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import SwiftUI 9 | 10 | // 提交按钮 using 11 | struct submitButton: View { 12 | var disableForm: Bool 13 | var action: () -> Void 14 | 15 | init (action: @escaping () -> Void) { 16 | self.action = action 17 | self.disableForm = false 18 | } 19 | 20 | init (disableForm: Bool, action: @escaping () -> Void) { 21 | self.action = action 22 | self.disableForm = disableForm 23 | } 24 | 25 | var body: some View { 26 | Button(action: { 27 | action() 28 | }) { 29 | HStack { 30 | Spacer() 31 | Text("提交") 32 | .foregroundColor(.white) 33 | .frame(width: UIScreen.main.bounds.width - 125, height: 45) 34 | Spacer() 35 | } 36 | .background(disableForm ? .gray : .orange) 37 | .cornerRadius(5) 38 | } 39 | .padding() 40 | .disabled(disableForm) 41 | .buttonStyle(BorderlessButtonStyle()) 42 | } 43 | } 44 | 45 | // 查看详情按钮 using 46 | struct detailButton: View { 47 | 48 | let content: Content 49 | @State var openDetail: Bool = false 50 | 51 | init (@ViewBuilder content: () -> Content) { 52 | self.content = content() 53 | } 54 | 55 | var body: some View { 56 | // 导航栏跳转 57 | NavigationLink(destination: content, isActive: $openDetail) { 58 | Button(action: { openDetail = true }) { 59 | Text("查看详情") 60 | .font(.system(size: 14)) 61 | .padding(8) 62 | .border(Color.blue) 63 | .cornerRadius(2) 64 | } 65 | .buttonStyle(BorderlessButtonStyle()) 66 | } 67 | 68 | // sheet 弹窗 69 | // Button(action: { openDetail = true }) { 70 | // Text("查看详情") 71 | // .font(.system(size: 14)) 72 | // .padding(8) 73 | // .border(Color.blue) 74 | // .cornerRadius(2) 75 | // } 76 | // .buttonStyle(BorderlessButtonStyle()) 77 | // .sheet(isPresented: $openDetail) { 78 | // content 79 | // } 80 | } 81 | } 82 | 83 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/Message/MessageListView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessageListView.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct MessageListView: View { 11 | @StateObject var viewModel = MessageVM() 12 | 13 | var body: some View { 14 | ZYRefreshView( 15 | viewModel: viewModel, 16 | listItem: { item in ListItem(viewModel: viewModel, item: item)} 17 | ) 18 | .navigationBarTitle("消息列表", displayMode: .inline) 19 | } 20 | 21 | // 刷新列表的具体条目需要自定义 22 | struct ListItem: View { 23 | @StateObject var viewModel: MessageVM 24 | var item: Message 25 | 26 | var body: some View { 27 | NavigationLink(destination: MessageDetailView(viewModel: viewModel, id: item.id)) { 28 | HStack { 29 | Image(systemName: "bell.circle") 30 | .resizable() 31 | .frame(width: 50, height: 50) 32 | VStack(alignment: .leading, spacing: 15) { 33 | HStack { 34 | Text(item.theme) 35 | .font(.headline) 36 | Spacer() 37 | Text(item.createdAt.prefix(10)) 38 | .font(.subheadline) 39 | .opacity(0.5) 40 | } 41 | VStack { 42 | Text(item.content) 43 | .font(.subheadline) 44 | .opacity(0.5) 45 | .lineLimit(1) 46 | Spacer() 47 | } 48 | } 49 | } 50 | .padding(defaultListItemPadding) 51 | } 52 | .contextMenu { 53 | Button { 54 | viewModel.deleteData(item: item) {} 55 | } label: { 56 | Label("删除此消息", systemImage: "xmark.circle") 57 | } 58 | } 59 | .buttonStyle(.borderless) 60 | .foregroundColor(.black) // 消去 NavigationLink 的覆盖颜色样式 61 | } 62 | } 63 | } 64 | 65 | struct MessageListView_Previews: PreviewProvider { 66 | static var previews: some View { 67 | MessageListView() 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/Global/ImageUtil.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageUtil.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/4/2. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | // 网络图片工具类 12 | class ImageUtil { 13 | /* 14 | * URL -> UIImage 15 | */ 16 | static func downloadWebImage(urLStr: String, completion: @escaping (UIImage) -> Void) { 17 | guard let url = URL(string: urLStr) else { 18 | print("Invalid URL...") 19 | return 20 | } 21 | URLSession.shared.dataTask(with: url) { (data, response, error) in 22 | if let data = data, let image = UIImage(data: data) { 23 | completion(image) 24 | } else { 25 | print("error: \(String(describing: error))") 26 | } 27 | }.resume() 28 | } 29 | 30 | /** 31 | * URL ---> 相册 32 | */ 33 | static func saveImageToAlbumFromURL(urlStr: String, 34 | successHandler: (() -> Void)?, 35 | errorHandler: ((Error) -> Void)?) { 36 | let imageServer = ImageSaver() 37 | imageServer.successHandler = successHandler 38 | imageServer.errorHandler = errorHandler 39 | 40 | downloadWebImage(urLStr: urlStr) { image in 41 | imageServer.writeToPhotoAlbum(image: image) 42 | } 43 | } 44 | 45 | /** 46 | * UIImage ---> 相册 47 | */ 48 | private func saveImageToAlbum(image: UIImage, 49 | successHandler: (() -> Void)?, 50 | errorHandler: ((Error) -> Void)?) { 51 | let imageServer = ImageSaver() 52 | imageServer.successHandler = successHandler 53 | imageServer.errorHandler = errorHandler 54 | imageServer.writeToPhotoAlbum(image: image) 55 | } 56 | } 57 | 58 | 59 | /** 60 | * 保存图片到本地 61 | */ 62 | class ImageSaver: NSObject { 63 | var successHandler: (() -> Void)? 64 | var errorHandler: ((Error) -> Void)? 65 | 66 | func writeToPhotoAlbum(image: UIImage) { 67 | UIImageWriteToSavedPhotosAlbum(image, self, #selector(saveComplete), nil) 68 | } 69 | 70 | @objc func saveComplete(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) { 71 | if let error = error { 72 | errorHandler?(error) 73 | } else { 74 | successHandler?() 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/Notification/NotificationView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationView.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/4/4. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct NotificationView: View { 11 | @State var timeInterval = 1 // 设置消息推送时间 12 | 13 | @State var showHelp: Bool = false // 显示帮助页面 14 | 15 | var body: some View { 16 | Group { 17 | List { 18 | 19 | Section(header: Text("本地的前台消息推送")) { 20 | Stepper(value: $timeInterval, in: 1...5, step: 1) { 21 | Text("消息推送延时:\(timeInterval)秒") 22 | } 23 | Button(action: { 24 | sendNotification(msg: Int.random(in: 1...4) > 2 ? "今天的需求改完了吗?客户催着明天要" : "小伙子好好干,升职加薪在等着你!") 25 | }, label: { 26 | Text("发送消息推送!") 27 | }) 28 | } 29 | } 30 | } 31 | .navigationTitle("本地消息推送") 32 | .navigationBarTitleDisplayMode(.inline) 33 | .toolbar(content: { 34 | Button(action: { self.showHelp = true }) { 35 | Image(systemName: "questionmark.circle") 36 | .resizable() 37 | .aspectRatio(contentMode: .fit) 38 | .frame(width: 22) 39 | .foregroundColor(.black) 40 | } 41 | .sheet(isPresented: $showHelp) { 42 | Text(""" 43 | 该页面主要是对消息中心的使用: 44 | 45 | 本地消息推送一般只有在后台生效 46 | 但是通过在 @main 界面进行一些配置 47 | 可以使得消息中心的推送在前台也生效... 48 | (不确定未来何时会修复这个问题) 49 | """) 50 | .padding() 51 | } 52 | }) 53 | 54 | } 55 | 56 | // 发送消息到消息中心 57 | func sendNotification(msg: String){ 58 | let content = UNMutableNotificationContent() 59 | content.title = "萌宅鹿给你发来一条消息:" 60 | content.body = msg 61 | content.sound = .default 62 | 63 | let trigger = UNTimeIntervalNotificationTrigger(timeInterval: Double(self.timeInterval), repeats: false) 64 | let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger) 65 | 66 | UNUserNotificationCenter.current().requestAuthorization(options: [.alert,.sound,.badge]) { (success, error) in 67 | if let error = error { 68 | print("消息推送失败:\(error) ") 69 | } 70 | } 71 | 72 | UNUserNotificationCenter.current().add(request) {error in 73 | if error != nil { 74 | print("无法添加到通知中心:\(error!)") 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/User/UserVM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserVM.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/4/2. 6 | // 7 | 8 | import Foundation 9 | 10 | // 这个模块是本地生成的数据,无需向服务端发送请求 11 | class UserVM: CommonVM { 12 | init() { 13 | super.init(item: User(), apiObj: UserAPIObj(moduleUrl: "user")) 14 | } 15 | 16 | // 由于 User 用于无服务端的演示, 因此不会发送网络请求, 本地重写其基本方法 17 | // 以下操作全部为模拟行为, 真实网络请求请参考 "会议列表" 18 | 19 | @Published var nickname: String = "" 20 | 21 | // 获取数据 22 | override func fetchData(completion: @escaping () -> Void) { 23 | print("生成用户数据") 24 | var list: [User] = [] 25 | for i in 0..<15 { 26 | list.append(User(username: "user00\(i)", password: "123456", nickname: "用户00\(i)", phone: "12345678999", headerImg: "")) 27 | } 28 | self.items = list 29 | super.total = 15 30 | completion() 31 | } 32 | 33 | // 获取数据详情 34 | override func fetchDetail(id: Int, completion: @escaping () -> Void) { 35 | print("获取数据详情") 36 | if let user = super.items.first(where: { $0.id == id}) { 37 | super.item = user 38 | completion() 39 | } 40 | } 41 | 42 | // 新增数据 43 | override func addData(item: User, completion: @escaping (Result) -> Void) { 44 | print("新增用户数据") 45 | super.items.insert(item, at: 0) // 往前添加元素 46 | self.total += 1 47 | completion(Result(catching: { return "" })) 48 | } 49 | 50 | // 更新数据 51 | override func updateData(item: User, completion: @escaping (Result) -> Void) { 52 | print("更新用户数据") 53 | if let idx = self.items.firstIndex(where: { $0.id == item.id }) { 54 | super.items[idx] = item 55 | completion(Result(catching: { return "" })) 56 | } 57 | } 58 | 59 | // 删除数据 60 | override func deleteData(item: User, completion: @escaping () -> Void) { 61 | print("删除用户数据") 62 | if let idx = super.items.firstIndex(of: item) { 63 | super.items.remove(at: idx) 64 | super.total -= 1 65 | completion() 66 | } 67 | } 68 | 69 | // 获取更多数据 70 | override func fetchMoreData(completion: @escaping () -> Void) { 71 | if (super.total >= 50) { return } 72 | print("获取更多用户数据") 73 | for i in 0..<10 { 74 | super.items.append(User(username: "newUser00\(self.total + i)", password: "123456", nickname: "新用户00\(self.total + i)", phone: "987654321", headerImg: "")) 75 | } 76 | super.total += 10 77 | completion() 78 | } 79 | 80 | // 搜索数据(模拟操作, 只能搜索一次, 真实效果参考 "会议列表") 81 | func filterData() { 82 | if nickname.isBlank { 83 | self.fetchData {} 84 | } 85 | super.items = super.items.filter { 86 | $0.nickname.contains(self.nickname) 87 | } 88 | self.total = self.items.count 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /go_api_server/utils/transition.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | ) 8 | 9 | // Transition 将ref的数据填充到target 10 | // ref {"id": 1, "username": "renhj", "age": 11, "password": "password"} 11 | // transition after 12 | // target {"id": 1, "username": "renhj"} 13 | func Transition(ref interface{}, target interface{}) error { 14 | tt := reflect.TypeOf(target) // target 类型 15 | tv := reflect.ValueOf(target) // target 值 16 | tk := tt.Kind() // target 种类 17 | 18 | if tk != reflect.Ptr { 19 | return errors.New("target must be ptr type! ") 20 | } 21 | tfn := tt.Elem().NumField() // target fields 数量 22 | 23 | rt := reflect.TypeOf(ref) // ref 类型 24 | rv := reflect.ValueOf(ref) // ref 值 25 | rk := rt.Kind() // ref 种类 26 | rkm := map[string]interface{}{} 27 | rvm := map[string]interface{}{} 28 | 29 | // 2、遍历ref,放到map里 30 | if rk == reflect.Ptr { 31 | rfn := rt.Elem().NumField() 32 | for i := 0; i < rfn; i++ { 33 | name := rt.Elem().Field(i).Name 34 | kind := rv.Elem().Field(i).Kind() 35 | value := rv.Elem().Field(i) 36 | rkm[name] = kind 37 | rvm[name] = value 38 | } 39 | } else { 40 | rfn := rt.NumField() 41 | for i := 0; i < rfn; i++ { 42 | name := rt.Field(i).Name 43 | kind := rv.Field(i).Kind() 44 | value := rv.Field(i) 45 | rkm[name] = kind 46 | rvm[name] = value 47 | } 48 | } 49 | 50 | // 3、遍历target,获取map里同名的值 51 | for i := 0; i < tfn; i++ { 52 | if tv.Elem().Field(i).Kind() != rkm[tt.Elem().Field(i).Name] { 53 | // 判断同名的成员属性类型是否一致 54 | // return fmt.Errorf("[%s:%s] mismatch type [%s:%s]", tt.Name(), tt.Elem().Field(i).Name, rt.Name(), rt.Field(i).Name) 55 | continue 56 | } 57 | tv.Elem().Field(i).Set(rvm[tt.Elem().Field(i).Name].(reflect.Value)) 58 | } 59 | 60 | return nil 61 | } 62 | 63 | func SimpleCopyProperties(dst, src interface{}) (err error) { 64 | // 防止意外panic 65 | defer func() { 66 | if e := recover(); e != nil { 67 | err = errors.New(fmt.Sprintf("%v", e)) 68 | } 69 | }() 70 | 71 | dstType, dstValue := reflect.TypeOf(dst), reflect.ValueOf(dst) 72 | srcType, srcValue := reflect.TypeOf(src), reflect.ValueOf(src) 73 | 74 | // dst必须结构体指针类型 75 | if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct { 76 | return errors.New("dst type should be a struct pointer") 77 | } 78 | 79 | // src必须为结构体或者结构体指针 80 | if srcType.Kind() == reflect.Ptr { 81 | srcType, srcValue = srcType.Elem(), srcValue.Elem() 82 | } 83 | if srcType.Kind() != reflect.Struct { 84 | return errors.New("src type should be a struct or a struct pointer") 85 | } 86 | 87 | // 取具体内容 88 | dstType, dstValue = dstType.Elem(), dstValue.Elem() 89 | 90 | // 属性个数 91 | propertyNums := dstType.NumField() 92 | 93 | for i := 0; i < propertyNums; i++ { 94 | // 属性 95 | property := dstType.Field(i) 96 | // 待填充属性值 97 | propertyValue := srcValue.FieldByName(property.Name) 98 | 99 | // 无效,说明src没有这个属性 || 属性同名但类型不同 100 | if !propertyValue.IsValid() || property.Type != propertyValue.Type() { 101 | continue 102 | } 103 | 104 | if dstValue.Field(i).CanSet() { 105 | dstValue.Field(i).Set(propertyValue) 106 | } 107 | } 108 | 109 | return nil 110 | } 111 | -------------------------------------------------------------------------------- /go_api_server/service/meeting.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/yusael/go_api_server/global" 8 | "github.com/yusael/go_api_server/model" 9 | "github.com/yusael/go_api_server/model/common/request" 10 | "github.com/yusael/go_api_server/utils" 11 | ) 12 | 13 | type MeetingService struct{} 14 | 15 | // 分页获取会议列表 16 | func (meetingService *MeetingService) GetMeetingList(info request.PageInfo) (records interface{}, total int64, err error) { 17 | limit := info.PageSize 18 | offset := info.PageSize * (info.Page - 1) 19 | db := global.DB.Model(&model.Meeting{}) 20 | if err = db.Where("mt_name LIKE ?", fmt.Sprintf("%%%s%%", info.Keyword)).Count(&total).Error; err != nil { 21 | fmt.Println("GetMeetingList Service Error!") 22 | return 23 | } 24 | var meetingRecords []model.Meeting 25 | 26 | err = db.Preload("AnList").Limit(limit).Offset(offset). 27 | Where("mt_name LIKE ?", fmt.Sprintf("%%%s%%", info.Keyword)).Order("created_at desc"). 28 | Find(&meetingRecords).Error 29 | return meetingRecords, total, err 30 | } 31 | 32 | // 删除会议 33 | func (meetingService *MeetingService) DeleteMeeting(id int) (err error) { 34 | return global.DB.Where("id = ?", id).Delete(&model.Meeting{}).Error 35 | } 36 | 37 | // 获取会议详情 38 | func (meetingServicem *MeetingService) GetMeetingDetail(id int) (meeting *model.Meeting, err error) { 39 | err = global.DB.Preload("AnList").Where("id = ?", id).First(&meeting).Error 40 | return meeting, err 41 | } 42 | 43 | // 新增 或 更新 会议 44 | func (meetingService *MeetingService) SaveOrUpdateMeeting(meetingReq *request.ChangeMeetingInfo) (err error) { 45 | var meeting model.Meeting 46 | fmt.Println(meetingReq) 47 | // po -> vo 48 | utils.SimpleCopyProperties(&meeting, meetingReq) 49 | meeting.ID = meetingReq.ID 50 | meeting.Remark = meetingReq.Remark 51 | 52 | // 更新 文件记录 53 | global.DB.Model(model.UploadAndDownload{}). 54 | Where("meeting_id = ?", meetingReq.ID).Updates(map[string]interface{}{"meeting_id": 0}) 55 | global.DB.Model(model.UploadAndDownload{}). 56 | Where("id IN ?", meetingReq.AnnexIds).Updates(map[string]interface{}{"meeting_id": meetingReq.ID}) 57 | 58 | if meeting.ID == 0 { // 新增 59 | if err := global.DB.Create(&meeting).Error; err != nil { 60 | return err 61 | } 62 | } else { // 更新 63 | if _, err := meetingService.GetMeetingDetail(int(meeting.ID)); err != nil { 64 | return err 65 | } 66 | if err := global.DB.Model(&meeting).Where("id = ?", meeting.ID).Updates(meeting).Error; err != nil { 67 | return err 68 | } 69 | } 70 | return nil 71 | } 72 | 73 | // 初始化数据库数据: 有数据就不初始化, 没有数据则增加 20 条数据 74 | func (meetingService *MeetingService) InitMeetingData() { 75 | var count int64 76 | if global.DB.Model(&model.Meeting{}).Count(&count); count != 0 { 77 | return 78 | } 79 | 80 | meetingList := make([]model.Meeting, 0) 81 | for i := 0; i < 30; i++ { 82 | meetingList = append(meetingList, model.Meeting{ 83 | MtName: fmt.Sprintf("会议名称%v", i), 84 | MtTheme: fmt.Sprintf("会议主题%v", i), 85 | MtSummary: fmt.Sprintf("会议概要%v", i), 86 | MtContent: fmt.Sprintf("会议内容%v", i), 87 | MtMember: fmt.Sprintf("成员%v", i), 88 | MtTime: time.Now().Format("2006-01-02"), 89 | CreateUser: 0, 90 | AnList: nil, 91 | }) 92 | } 93 | if err := global.DB.Create(&meetingList).Error; err != nil { 94 | fmt.Println("InitMeetingData Error", err) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UIFrame/Enhance/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | // 增强日期, 添加默认时间, 以及通用日期格式转换 12 | extension Date { 13 | static var defaultDateStr: String { 14 | "1970-01-01 00:00:01" 15 | } 16 | static var defaultDate: Date { 17 | string2Date(defaultDateStr) 18 | } 19 | } 20 | 21 | // Date -> String 22 | // 默认转换格式为 yyyy-MM-dd HH:mm:ss 23 | func date2String(_ date:Date, dateFormat:String = "yyyy-MM-dd HH:mm:ss") -> String { 24 | let formatter = DateFormatter() 25 | formatter.locale = Locale.init(identifier: "zh_CN") 26 | formatter.dateFormat = dateFormat 27 | let date = formatter.string(from: date) 28 | return date 29 | } 30 | 31 | // String -> Date 32 | // 如果参数指定了格式则根据指定格式进行转换 33 | // 如果没有指定格式, 分别尝试使用 yyyy-MM-dd HH:mm:ss 和 yyyy-MM-dd 进行转换 34 | func string2Date(_ string:String, dateFormat:String? = nil) -> Date { 35 | let formatter = DateFormatter() 36 | formatter.locale = Locale.init(identifier: "zh_CN") 37 | 38 | // 外面传入了参数 39 | if dateFormat != nil { 40 | formatter.dateFormat = dateFormat 41 | if let date = formatter.date(from: string) { 42 | return date 43 | } 44 | } 45 | 46 | // 外部没有传参, 按以下顺序格式化 47 | formatter.dateFormat = "yyyy-MM-dd HH:mm:ss" 48 | if let date = formatter.date(from: string) { 49 | return date 50 | } 51 | 52 | formatter.dateFormat = "yyyy-MM-dd" 53 | if let date = formatter.date(from: string) { 54 | return date 55 | } 56 | 57 | return Date() 58 | } 59 | 60 | // 增强字符串 61 | extension String { 62 | var isBlank: Bool { 63 | // 去除空格和换行 64 | let trimmedStr = self.trimmingCharacters(in: .whitespacesAndNewlines) 65 | return trimmedStr.isEmpty 66 | } 67 | /* 68 | *去掉首尾空格 69 | */ 70 | var removeHeadAndTailSpace:String { 71 | let whitespace = NSCharacterSet.whitespaces 72 | return self.trimmingCharacters(in: whitespace) 73 | } 74 | /* 75 | *去掉首尾空格 包括后面的换行 \n 76 | */ 77 | var removeHeadAndTailSpacePro:String { 78 | let whitespace = NSCharacterSet.whitespacesAndNewlines 79 | return self.trimmingCharacters(in: whitespace) 80 | } 81 | /* 82 | *去掉所有空格 83 | */ 84 | var removeAllSapce: String { 85 | return self.replacingOccurrences(of: " ", with: "", options: .literal, range: nil) 86 | } 87 | /* 88 | *去掉首尾空格 后 指定开头空格数 89 | */ 90 | func beginSpaceNum(num: Int) -> String { 91 | var beginSpace = "" 92 | for _ in 0.. String { 101 | return prefix(1).lowercased() + self.dropFirst() 102 | } 103 | } 104 | 105 | // 增强View:隐藏键盘 106 | extension View { 107 | func hideKeyboard() { 108 | UIApplication.shared.sendAction( 109 | #selector(UIResponder.resignFirstResponder), 110 | to: nil, 111 | from: nil, 112 | for: nil 113 | ) 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/Api/BaseApi.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseAPI.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import Foundation 9 | import Alamofire 10 | 11 | class BaseAPI { 12 | // 获取数据列表 13 | static func getList(path: String, parameters: Parameters, completion: @escaping (Result) -> Void) { 14 | NetworkManager.shared.requestPost(path: path, parameters: parameters) { result in 15 | switch result { 16 | case let.success(data): 17 | let parseResult: Result = parseData(data) 18 | completion(parseResult) 19 | case let .failure(error): 20 | completion(.failure(error)) 21 | } 22 | } 23 | } 24 | 25 | // 获取数据详情(根据id) 26 | static func getDetail(path: String, id: Int, completion: @escaping (Result) -> Void) { 27 | NetworkManager.shared.requestGet(path: path, parameters: nil) { result in 28 | switch result { 29 | case let .success(data): 30 | let parseResult: Result = parseData(data) 31 | completion(parseResult) 32 | case let .failure(error): 33 | completion(.failure(error)) 34 | } 35 | } 36 | } 37 | 38 | // 新增/修改 数据 39 | static func saveOrUpdate(path: String, obj: T, 40 | completion: @escaping (Result, Error>) -> Void) { 41 | guard let parameters = model2Dic(obj) else { 42 | let error = NSError(domain: "APIError", code: 0, userInfo: [NSLocalizedDescriptionKey: "model2Dic Error"]) 43 | completion(.failure(error)) 44 | return 45 | } 46 | NetworkManager.shared.requestPost(path: path, parameters: parameters) { result in 47 | switch result { 48 | case let .success(data): 49 | let parseResult: Result, Error> = parseData(data) 50 | completion(parseResult) 51 | case let .failure(error): 52 | completion(.failure(error)) 53 | } 54 | } 55 | } 56 | 57 | // 删除数据 58 | static func delete(path: String, id: Int, completion: @escaping (Result) -> Void) { 59 | NetworkManager.shared.requestGet(path: path, parameters: nil) { result in 60 | switch result { 61 | case let .success(data): 62 | let parseResult: Result = self.parseData(data) 63 | completion(parseResult) 64 | case let .failure(error): 65 | completion(.failure(error)) 66 | } 67 | } 68 | } 69 | 70 | // json -> model 71 | static func parseData(_ data: Data) -> Result { 72 | let decoder = JSONDecoder() 73 | 74 | let dataStr = String(data: data, encoding: .utf8)! 75 | print(dataStr) 76 | 77 | guard let decodedData = try? decoder.decode(T.self, from: data) else { 78 | let error = NSError(domain: "NetworkAPIError", code: 0, 79 | userInfo: [NSLocalizedDescriptionKey: "Can not parse data"]) 80 | return .failure(error) 81 | } 82 | return .success(decodedData) 83 | } 84 | 85 | // model -> dic 86 | static func model2Dic(_ model: T) -> [String: Any]? { 87 | guard let data = try? JSONEncoder().encode(model) else { 88 | return nil 89 | } 90 | guard let dict = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves) as? [String: Any] else { 91 | return nil 92 | } 93 | return dict 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/Meeting/MeetingListView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MeetingListView.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct MeetingListView: View { 11 | @StateObject var viewModel: MeetingVM = MeetingVM() 12 | var body: some View { 13 | ZYListView( 14 | title: "会议列表", // 上方显示的标题 15 | viewModel: viewModel, // 模型视图层 16 | // 通过导航栏进行跳转的页面 17 | navContent: { MeetingDetailView(viewModel: viewModel, id: nil) }, // id 为 nil 表示新增 18 | listItem: { item in ListItem(viewModel: viewModel, item: item)}, // 具体的列表条目 19 | withHelp: true, 20 | withFilter: true, 21 | helpItem: { Text("长按 “查看详情” 按钮可以进行删除操作") }, 22 | filterItem: { ListHead(viewModel: viewModel) } // 搜索框 23 | ) 24 | } 25 | 26 | struct ListItem: View { 27 | @StateObject var viewModel: MeetingVM 28 | var item: Meeting 29 | 30 | var body: some View { 31 | VStack { 32 | HStack { 33 | if item.mtName.isBlank { 34 | Text("未命名") 35 | .foregroundColor(.gray) 36 | .fontWeight(.bold) 37 | } else { 38 | Text(item.mtName) 39 | .fontWeight(.bold) 40 | } 41 | Spacer() 42 | // 指定了 id 则为更新 43 | detailButton { MeetingDetailView(viewModel: viewModel, id: item.id)} 44 | } 45 | Spacer() 46 | HStack { 47 | Text("会议主题:\(item.mtTheme)") 48 | .font(.caption) 49 | .opacity(0.5) 50 | .lineLimit(1) 51 | Spacer() 52 | } 53 | HStack { 54 | Text("会议概要:\(item.mtSummary)") 55 | .font(.caption) 56 | .opacity(0.5) 57 | .lineLimit(1) 58 | Spacer() 59 | Text("会议时间:\(String(item.mtTime.prefix(10)))") 60 | .font(.caption) 61 | .opacity(0.5) 62 | .lineLimit(1) 63 | } 64 | .padding(.vertical, 1) 65 | Divider() 66 | } 67 | .padding(defaultListItemPadding) 68 | .contextMenu { 69 | Button { viewModel.deleteData(item: item) {} } label: { 70 | Label("删除此会议纪要", systemImage: "xmark.circle") 71 | } 72 | } 73 | } 74 | } 75 | 76 | struct ListHead: View { 77 | @StateObject var viewModel: MeetingVM 78 | 79 | var body: some View { 80 | HStack { 81 | Text("会议名称:") 82 | TextField("请输入内容", text: $viewModel.mtName) 83 | .padding(5) 84 | .border(.selection) 85 | .onChange(of: viewModel.mtName) { _ in 86 | viewModel.filterData() 87 | } 88 | // Button(action: { 89 | // viewModel.filterData() 90 | // }, label: { 91 | // Text("搜索") 92 | // }) 93 | } 94 | .padding() 95 | .font(.system(size: 13)).opacity(0.7) 96 | } 97 | } 98 | } 99 | 100 | struct MeetingListView_Previews: PreviewProvider { 101 | static var previews: some View { 102 | MeetingListView() 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Gitee 地址:[https://gitee.com/szluyu99/ZYSwiftUIFrame](https://gitee.com/szluyu99/ZYSwiftUIFrame) 2 | 3 | Github 地址:[https://github.com/szluyu99/ZYSwiftUIFrame](https://github.com/szluyu99/ZYSwiftUIFrame) 4 | 5 | 本项目主要维护 Github 地址,同时会同步将其推送到 Gitee 地址(相当于镜像) 6 | 7 | ## 前言 8 | 9 | 我并不是专业的 IOS 开发人员,之前也没有接触过 IOS,但是因为某些原因,团队需要开发一个 IOS App,然后我便接触到了 Swift 和 SwiftUI,当然,我并没有学 OC 和 UIKit。该项目中几乎没有用到 UIKit 相关的东西(有也是谷歌搜索到了代码直接复制一下),基本上完全使用 SwiftUI 进行开发。 10 | 11 | 总觉得以后应该不会再和 IOS 有太多交集,但是好歹也是钻研了这么一段时间的技术,总希望能留下点什么东西,因此就诞生了这个项目。我试图将我开发 IOS 时学习和积累到的知识点和技术尽可能的集成到这个项目中,该框架也许会不停的迭代(如果我还有机会接触 IOS 的话)。 12 | 13 | 再次申明,**我并不是专业的 IOS 开发人员**,很多代码风格和思维,也许都是其他项目的开发经验,欢迎探讨。 14 | 15 | 希望我的项目能为 SwiftUI 带来一丝丝微弱的光芒。 16 | 17 | ## 主要特色 18 | 19 | 从我这么一个对 IOS 完全零基础的人的角度来看,我之前查询过很多项目,但是很多项目的功能性都是比较偏向某面,大多都是着力于视图层或其他功能性,很少能遇到比较完整的项目(可能我的看法并不专业)。而且 SwiftUI 开发中必然会遇到一些拦路虎如:下拉刷新、上拉加载、显示网络图片等,主要原因是因为 SwiftUI 目前还不是特别成熟,但是它作为未来的趋势是必然的。 20 | 21 | 该 SwiftUI 项目包含完整的:**网络请求、下拉刷新、上拉加载更多、数据增删改查、图片上传、图片预览**等功能(后续还会继续更新),代码中抽取成了框架体系:例如通用 ViewModel 等,很适合进行快速开发。 22 | 23 | 项目特色: 24 | 25 | * **拥有服务端项目**,为了模拟实际的项目场景,我使用 Go 开发的 26 | * 包含**网络请求部分**,结合上面服务端,实现了对数据库数据的增删改查 27 | * 即使不运行服务端,项目也有**单机 Demo**,供你快速了解其主要功能 28 | * 封装了**丝滑的上拉刷新、下拉加载更多**(基于 BBSwiftUIKit),也可以模仿我的代码自行封装 29 | * **代码优雅**、风格整洁,注释比较详细 30 | * 待更新... 31 | 32 | ## 项目技术 33 | 34 | IOS 技术栈:基于 Swift 语言 35 | 36 | * SwiftUI 37 | 38 | 服务端技术栈:基于 Go 语言 39 | 40 | * Web 框架:Gin 41 | * ORM 框架:GORM 42 | 43 | ## 项目预览 44 | 45 | ![](https://img-blog.csdnimg.cn/img_convert/e252d7cc96b135c753e246991cfa8691.png) 46 | 47 | ### 1. 不需要开启服务端 48 | 49 | 不需要开启服务端,功能是下面 “需要开启服务端” 功能的简化版,仅用于本地演示,并且不涉及到数据请求。 50 | 51 | #### 1.1 用户列表 52 | 53 | 下拉刷新、上拉加载更多: 54 | 55 | ![](https://img-blog.csdnimg.cn/img_convert/03e3ffbbd9fdce04a05309bd8830dae3.gif) 56 | 57 | 新增、删除、修改: 58 | 59 | ![](https://img-blog.csdnimg.cn/img_convert/5d05aac8252709be10257c9173dc8e97.gif) 60 | 61 | 62 | 帮助、搜索: 63 | 64 | ![](https://img-blog.csdnimg.cn/img_convert/63b7e4d967321cb254bda5ac418408df.gif) 65 | 66 | ### 2. 需要开启服务端 67 | 68 | 开启服务端的数据,模拟真实的请求后台,实现对数据库的操作。 69 | 70 | #### 2.1 消息列表 71 | 72 | 上拉、下拉、删除: 73 | 74 | ![](https://img-blog.csdnimg.cn/img_convert/e9bebd97d19257d014da9ccae62fb2c7.gif) 75 | 76 | 77 | 78 | #### 2.2 会议列表 79 | 80 | 显示帮助、删除、下拉刷新、搜索: 81 | 82 | ![](https://img-blog.csdnimg.cn/img_convert/96080cbef5b6483f98917b8108b6a99d.gif) 83 | 84 | 更新、新增: 85 | 86 | ![](https://img-blog.csdnimg.cn/img_convert/3e50cf14f2941307a5c3130be70b403d.gif) 87 | 88 | 图片上传、预览、删除、保存: 89 | 90 | ![](https://img-blog.csdnimg.cn/img_convert/e0bdc66530fcabea91e058101b0f246a.gif) 91 | 92 | 93 | 94 | 95 | 96 | ## 运行教程 97 | 98 | ### 运行 IOS 项目 99 | 100 | 这个应该不用多说了,项目拉下来,用 Xcode 打开 `ZYSwiftUIFrame.xcodeproj` 文件。 101 | 102 | 运行前需要修改签名等操作。 103 | 104 | --- 105 | 106 | 项目跑起来后,**不需要服务端的界面是可以直接查看的**,需要服务端的界面,还需要运行起服务端。 107 | 108 | 当服务端跑起来后,将 `Api/NetworkManager.swift` 中的 `NetworkAPIBaseURL` 修改为你当前的局域网 IP。 109 | 110 | (端口默认是 8080,不需要修改) 111 | 112 | > 保证你的真机和运行起服务端的电脑在同一个局域网下,或者直接使用模拟器运行项目。 113 | 114 | 查看电脑当前 IP 的方法:在网络偏好设置查看。 115 | 116 | ![](https://img-blog.csdnimg.cn/img_convert/057ea9fa3f18e93d54d8474936713096.png) 117 | 118 | ### 运行服务端项目 119 | 120 | > 需要有 Go 语言的环境。 121 | 122 | 项目我已经打包好了,就是 go_api_server 目录下的 `main` 文件,终端中 `./main` 即可运行。 123 | 124 | 运行前记得修改 `config` 目录中的配置文件,修改成自己的数据库名、用户名、密码。 125 | 126 | #### 数据库相关 127 | 128 | 我本地数据库用的 MySQL 8。 129 | 130 | **Golang 的数据库框架有自动迁移功能**,在连接上数据库的基础上,直接运行起项目会自动建表。 131 | 132 | 我也在代码中初始化生成了一些测试数据,因此只要数据库连接正常,项目运行起来,就有数据了。 133 | 134 | > 当然,我也提供了 SQL 语句(结构 + 数据),在项目的 `sql` 文件中。 135 | 136 | #### 文件上传目录 137 | 138 | 文件上传到本地,目前写死是 `uploads/file` 目录。 139 | 140 | #### 后台接口文档 141 | 142 | 该接口文档由 ApiPost 生成: 143 | 144 | [https://console-docs.apipost.cn/cover.html?url=36557b241534caed&salt=6015c9b386e133e0](https://console-docs.apipost.cn/cover.html?url=36557b241534caed&salt=6015c9b386e133e0) 145 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UIFrame/ZYNavBarView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ZYNavBarView.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import SwiftUI 9 | 10 | /** 11 | * 上方导航的界面 12 | * 可以传入具体的帮助页面内容,不传有默认值 13 | */ 14 | private let defaultHelpView: Text = Text("长按 “查看详情” 按钮可以进行删除操作") 15 | 16 | struct ZYNavBarView: View { 17 | @ViewBuilder var helpContent: HelpContent 18 | 19 | // 新增按钮 20 | @Binding var showAddView: Bool 21 | 22 | // 是否展示过滤按钮 23 | @State var filterFlag: Bool = false 24 | var showFilter: Binding? // 可选的 @Binding 25 | 26 | // 帮助按钮 27 | @State var helpFlag: Bool = false 28 | var showHelpView: Binding? 29 | 30 | init (showAddView: Binding) { 31 | self.helpContent = defaultHelpView as! HelpContent 32 | _showAddView = showAddView // 注意 @Binding 的初始化是这么做的 33 | self.filterFlag = false 34 | } 35 | 36 | init (@ViewBuilder helpContent: () -> HelpContent, 37 | showAddView: Binding) { 38 | self.helpContent = helpContent() 39 | _showAddView = showAddView // 注意 @Binding 的初始化是这么做的 40 | self.filterFlag = false 41 | } 42 | 43 | init (showAddView: Binding, 44 | showFilter: Binding?) { 45 | self.helpContent = defaultHelpView as! HelpContent 46 | _showAddView = showAddView 47 | self.showFilter = showFilter 48 | if (self.showFilter != nil) { 49 | _filterFlag = .init(initialValue: true) 50 | } else { 51 | _filterFlag = .init(initialValue: false) 52 | } 53 | } 54 | 55 | init (@ViewBuilder helpContent: () -> HelpContent, 56 | showAddView: Binding, 57 | showHelpView: Binding?, 58 | showFilter: Binding?) { 59 | self.helpContent = helpContent() 60 | _showAddView = showAddView 61 | self.showHelpView = showHelpView 62 | if (self.showHelpView != nil) { 63 | _helpFlag = .init(initialValue: true) 64 | } else { 65 | _helpFlag = .init(initialValue: false) 66 | } 67 | self.showFilter = showFilter 68 | if (self.showFilter != nil) { 69 | _filterFlag = .init(initialValue: true) 70 | } else { 71 | _filterFlag = .init(initialValue: false) 72 | } 73 | 74 | } 75 | 76 | var body: some View { 77 | HStack { 78 | // 帮助按钮 79 | if self.helpFlag { 80 | Button(action: { self.showHelpView?.wrappedValue = true }) { 81 | Image(systemName: "questionmark.circle") 82 | .resizable() 83 | .aspectRatio(contentMode: .fit) 84 | .frame(width: 22) 85 | .foregroundColor(.black) 86 | } 87 | .sheet(isPresented: showHelpView!) { 88 | helpContent // 外部传入页面 89 | } 90 | } 91 | // 过滤按钮 92 | if self.filterFlag { 93 | Button(action: { 94 | withAnimation { 95 | self.showFilter?.wrappedValue.toggle() 96 | } 97 | }){ 98 | Image(systemName: "magnifyingglass.circle") 99 | .resizable() 100 | .aspectRatio(contentMode: .fit) 101 | .frame(width: 22) 102 | .foregroundColor(.black) 103 | } 104 | } 105 | // 新增按钮 106 | Button(action: { self.showAddView = true }) { 107 | Image(systemName: "plus.circle") 108 | .resizable() 109 | .aspectRatio(contentMode: .fit) 110 | .frame(width: 22) 111 | .foregroundColor(.black) 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UIFrame/ImagePick/ImagePickerView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImagePickerView.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/4/2. 6 | // 7 | 8 | import SwiftUI 9 | import UIKit 10 | import PhotosUI 11 | 12 | public struct ImagePickerView: UIViewControllerRepresentable { 13 | 14 | public typealias UIViewControllerType = PHPickerViewController 15 | 16 | public init(filter: PHPickerFilter = .images, selectionLimit: Int = 1, delegate: PHPickerViewControllerDelegate) { 17 | self.filter = filter 18 | self.selectionLimit = selectionLimit 19 | self.delegate = delegate 20 | } 21 | 22 | private let filter: PHPickerFilter 23 | private let selectionLimit: Int 24 | private let delegate: PHPickerViewControllerDelegate 25 | 26 | public func makeUIViewController(context: Context) -> PHPickerViewController { 27 | var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared()) 28 | configuration.filter = filter 29 | configuration.selectionLimit = selectionLimit 30 | 31 | let controller = PHPickerViewController(configuration: configuration) 32 | controller.delegate = delegate 33 | return controller 34 | } 35 | 36 | public func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) { } 37 | } 38 | 39 | extension ImagePickerView { 40 | public class Delegate: NSObject, PHPickerViewControllerDelegate { 41 | 42 | public init(isPresented: Binding, didCancel: @escaping (PHPickerViewController) -> (), didSelect: @escaping (ImagePickerResult) -> (), didFail: @escaping (ImagePickerError) -> ()) { 43 | self._isPresented = isPresented 44 | self.didCancel = didCancel 45 | self.didSelect = didSelect 46 | self.didFail = didFail 47 | } 48 | 49 | @Binding var isPresented: Bool 50 | private let didCancel: (PHPickerViewController) -> () 51 | private let didSelect: (ImagePickerResult) -> () 52 | private let didFail: (ImagePickerError) -> () 53 | 54 | public func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { 55 | if results.count == 0 { 56 | self.isPresented = false 57 | self.didCancel(picker) 58 | return 59 | } 60 | var images = [UIImage]() 61 | for i in 0.. 0 { 39 | self.rowBody(row: rows, isLast: true) 40 | } 41 | } 42 | .fullScreenCover(isPresented: $showImageViewer) { 43 | EmptyView() 44 | .frame(maxWidth: .infinity, maxHeight: .infinity) 45 | // 图片预览 46 | .overlay(ImageViewerRemote(imageURL: self.$imgURL, viewerShown: self.$showImageViewer)) 47 | .onTapGesture { 48 | self.showSheet = true 49 | } 50 | .actionSheet(isPresented: $showSheet, content: {imgOptSheet}) 51 | .alert(isPresented: $showAlert, content: { 52 | Alert(title: Text("消息提示"), 53 | message: Text(self.alertMsg), 54 | dismissButton: .default(Text("确定"))) 55 | }) 56 | } 57 | } 58 | } 59 | 60 | func rowBody(row: Int, isLast: Bool) -> some View { 61 | HStack(spacing: 6) { 62 | ForEach(0 ..< (isLast ? self.lastRowCols : self.cols), id: \.self) { col in 63 | // 这里加上服务器前缀(根据需求决定要不要) 64 | WebImage(url: URL(string: NetworkAPIBaseURL + self.imgList[row * self.cols + col].url)) 65 | .resizable() 66 | .aspectRatio(contentMode: .fill) 67 | .frame(minWidth: 60, maxWidth: 80, minHeight: 60, maxHeight: 80) 68 | .aspectRatio(1, contentMode: .fill) 69 | .clipped() 70 | .onTapGesture { 71 | // 这里加上服务器前缀(根据需求决定要不要) 72 | self.imgURL = NetworkAPIBaseURL + self.imgList[row * self.cols + col].url 73 | self.showImageViewer = true 74 | } 75 | } 76 | } 77 | } 78 | 79 | // 点击图片进行的操作 80 | private var imgOptSheet: ActionSheet { 81 | let action = ActionSheet(title: Text("图片操作"), message: Text("请选择您的操作"), 82 | buttons: [.default(Text("保存图片到相册"), action: { 83 | self.showSheet = false 84 | ImageUtil.saveImageToAlbumFromURL(urlStr: self.imgURL, successHandler: { 85 | self.alertMsg = "保存成功!" 86 | self.showAlert = true 87 | }, errorHandler: { 88 | self.alertMsg = "保存失败!\($0.localizedDescription)" 89 | self.showAlert = true 90 | }) 91 | }),.destructive(Text("删除图片"), action: { 92 | removeImg() 93 | self.showSheet = false 94 | }),.cancel(Text("取消"), action: { 95 | self.showSheet = false 96 | })]) 97 | return action 98 | } 99 | 100 | // 删除列表中的图片 101 | private func removeImg() { 102 | // 这里加上服务器前缀(根据需求决定要不要) 103 | if let idx = imgList.firstIndex(where: { NetworkAPIBaseURL + $0.url == self.imgURL } ) { 104 | imgList.remove(at: idx) 105 | self.showImageViewer = false 106 | } else { 107 | print("图片删除失败") 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/User/UserListView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserListView.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/4/2. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct UserListView: View { 11 | @StateObject var viewModel: UserVM = UserVM() 12 | 13 | var body: some View { 14 | ZYListView( 15 | title: "用户列表", // 上方显示的标题 16 | viewModel: viewModel, // 模型视图层 17 | // 通过导航栏进行跳转的页面 18 | navContent: { UserDetailView(viewModel: viewModel, id: nil) }, // id 为 nil 表示新增 19 | listItem: { item in ListItem(viewModel: viewModel, item: item)}, // 具体的列表条目 20 | withHelp: true, // 显示帮助按钮, 若不想显示这里设置为 false 21 | withFilter: true, // 显示搜索按钮, 若不想显示这里设置为 false 22 | helpItem: { HelpContent() }, // 一些帮助信息 23 | filterItem: { ListHead(viewModel: viewModel) } // 搜索框 24 | ) 25 | } 26 | 27 | struct ListItem: View { 28 | @StateObject var viewModel: UserVM 29 | var item: User 30 | 31 | var body: some View { 32 | // 查看详情页面 33 | NavigationLink(destination: UserDetailView(viewModel: viewModel, id: item.id)) { 34 | HStack { 35 | Image(systemName: "person.crop.circle") 36 | .resizable() 37 | .frame(width: 50, height: 50) 38 | VStack(alignment: .leading, spacing: 15) { 39 | HStack { 40 | Text(item.nickname) 41 | .font(.headline) 42 | Spacer() 43 | Text(item.username) 44 | .font(.subheadline) 45 | .opacity(0.5) 46 | } 47 | VStack { 48 | Text(item.phone) 49 | .font(.subheadline) 50 | .opacity(0.5) 51 | .lineLimit(1) 52 | Spacer() 53 | } 54 | } 55 | } 56 | .padding(defaultListItemPadding) 57 | } 58 | .contextMenu { 59 | Button { 60 | viewModel.deleteData(item: item) {} 61 | } label: { 62 | Label("删除此用户", systemImage: "xmark.circle") 63 | } 64 | } 65 | .buttonStyle(.borderless) 66 | .foregroundColor(.black) // 消去 NavigationLink 的覆盖颜色样式 67 | } 68 | } 69 | 70 | struct ListHead: View { 71 | @StateObject var viewModel: UserVM 72 | 73 | var body: some View { 74 | HStack { 75 | Text("用户昵称:") 76 | TextField("请输入内容", text: $viewModel.nickname) 77 | .padding(5) 78 | .border(.selection) 79 | Button(action: { 80 | viewModel.filterData() 81 | }, label: { 82 | Text("搜索") 83 | }) 84 | } 85 | .padding() 86 | .font(.system(size: 13)).opacity(0.7) 87 | } 88 | } 89 | 90 | struct HelpContent: View { 91 | var body: some View { 92 | VStack { 93 | Text("该页面主要用于演示一些基础功能:\n") 94 | .font(.title3) 95 | Text(""" 96 | - 页面的 [下拉刷新]、[上拉加载更多] 97 | - 点击页面条目进入 [修改界面] 98 | - 点击顶部的 "加号" 进入 [新增界面] 99 | - 长按页面条目可执行 [删除操作] 100 | - 点击顶部的 “搜索” 执行 [过滤操作] 101 | - 点击顶部的 "问号" 显示 [帮助信息]\n 102 | """) 103 | .font(.headline) 104 | Text(""" 105 | 以上只是单机版的功能演示,较为简单 106 | 开启服务端版本的封装好了网络请求相关 107 | """) 108 | .font(.headline) 109 | .foregroundColor(.gray) 110 | 111 | } 112 | } 113 | } 114 | 115 | } 116 | 117 | struct UserListView_Previews: PreviewProvider { 118 | static var previews: some View { 119 | UserListView() 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UIFrame/Refresh/ZYListView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ZYListView.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import SwiftUI 9 | import BBSwiftUIKit 10 | 11 | // 本项目中通用的带有 过滤框, 帮助按钮, 新增按钮 的可刷新页面 12 | struct ZYListView: View 13 | where Model: Equatable, Model: Identifiable { 14 | 15 | // 页面名称 16 | let title: String 17 | // 是否有过滤框 18 | var withFilter: Bool 19 | // 是否有帮助提示 20 | var withHelp: Bool 21 | 22 | // 通用 ViewModel 23 | @StateObject var viewModel: CommonVM 24 | 25 | @ViewBuilder var navContent: NavContent // 要跳转 新增 / 更新 页面 26 | @ViewBuilder var listItem: (Model) -> ListItem // 列表条目 27 | @ViewBuilder var helpItem: HelpItem // 帮助信息 28 | @ViewBuilder var filterItem: FilterItem // 搜索条目 29 | 30 | // 默认没有 帮助提示 和 搜索框 31 | init (title: String, viewModel: CommonVM, 32 | @ViewBuilder navContent: () -> NavContent, 33 | @ViewBuilder listItem: @escaping (Model) -> ListItem) 34 | { 35 | self.title = title 36 | // 初始化 @StateObject 37 | _viewModel = StateObject(wrappedValue: viewModel) 38 | self.withFilter = true // 默认没搜索框 39 | self.withHelp = false // 默认没帮助框 40 | self.navContent = navContent() 41 | self.listItem = listItem 42 | self.helpItem = Text("") as! HelpItem // 没有帮助框不会展示出来 43 | self.filterItem = Text("") as! FilterItem // 没有搜索框不会展示出来 44 | } 45 | 46 | // 自定义有没有 帮助提示 和 搜索框 47 | init (title: String, viewModel: CommonVM, 48 | @ViewBuilder navContent: () -> NavContent, 49 | @ViewBuilder listItem: @escaping (Model) -> ListItem, 50 | withHelp: Bool, 51 | withFilter: Bool, 52 | @ViewBuilder helpItem: () -> HelpItem, 53 | @ViewBuilder filterItem: () -> FilterItem) { 54 | self.title = title 55 | // 初始化 @StateObject 56 | _viewModel = StateObject(wrappedValue: viewModel) 57 | self.navContent = navContent() 58 | self.listItem = listItem 59 | self.withHelp = withHelp 60 | self.helpItem = helpItem() 61 | self.withFilter = withFilter // 手动控制有没有搜索 62 | self.filterItem = filterItem() 63 | } 64 | 65 | // 每个列表页面基本都有的属性 66 | @State private var showFilter = false // 过滤框 67 | @State private var showAddView = false // 新增页面 68 | @State private var showHelpView = false // 帮助页面 69 | 70 | var body: some View { 71 | NavigationLink(destination: navContent, isActive: $showAddView) { EmptyView() } 72 | 73 | if showFilter { 74 | filterItem 75 | } 76 | 77 | Group { 78 | if viewModel.total != 0 { 79 | BBTableView(viewModel.items) { item in 80 | listItem(item) 81 | } 82 | .bb_reloadData($viewModel.isReloadData) 83 | .bb_pullDownToRefresh(isRefreshing: $viewModel.isRefreshing) { 84 | DispatchQueue.main.asyncAfter(deadline: .now() + refreshTime) { 85 | viewModel.fetchData { 86 | viewModel.isRefreshing = false 87 | } 88 | } 89 | } 90 | .bb_pullUpToLoadMore(bottomSpace: 40) { 91 | if viewModel.isLoadingMore{ return } 92 | viewModel.isLoadingMore = true 93 | DispatchQueue.main.asyncAfter(deadline: .now() + loadMoreTime) { 94 | viewModel.fetchMoreData { 95 | viewModel.isLoadingMore = false 96 | } 97 | } 98 | } 99 | } else { 100 | Text("当前没有数据!") 101 | } 102 | } 103 | .navigationBarTitle(self.title, displayMode: .inline) 104 | .navigationBarItems( 105 | trailing: ZYNavBarView(helpContent: { helpItem } , 106 | showAddView: $showAddView, 107 | showHelpView: withHelp ? $showHelpView: nil, 108 | showFilter: withFilter ? $showFilter : nil) 109 | ) 110 | 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/Meeting/MeetingDetailView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MeetingDetailView.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct MeetingDetailView: View { 11 | @StateObject var viewModel: MeetingVM 12 | 13 | @Environment(\.presentationMode) var presentationMode: Binding 14 | 15 | // 根据传入 id 是否为 nil 判断新增还是更新 16 | var id: Int? 17 | 18 | // 处理表单中的特殊类型, 如 日期类型 19 | @State private var mtTime = Date() 20 | 21 | @State var errorFlag = false // 错误弹窗 22 | @State var errorMsg = "" // 错误消息 23 | 24 | var disableForm: Bool { 25 | viewModel.item.mtName.isBlank || viewModel.item.mtTheme.isBlank || viewModel.item.mtSummary.isBlank || viewModel.item.mtContent.isBlank || viewModel.item.mtMember.isBlank 26 | } 27 | 28 | var body: some View { 29 | List { 30 | CommonTextEditor(text: "*会议名", value: $viewModel.item.mtName) 31 | CommonTextEditor(text: "*主题名", value: $viewModel.item.mtTheme) 32 | CommonTextEditor(text: "*概要名", value: $viewModel.item.mtSummary) 33 | CommonTextEditor(text: "*内容", value: $viewModel.item.mtContent) 34 | CommonTextEditor(text: "*参会人员", value: $viewModel.item.mtMember) 35 | CommonDatePicker(text: " 开会时间", value: $mtTime) 36 | RemarkField(remark: $viewModel.item.remark) { Text(" 备注:") } 37 | // 图片选择(多选) 38 | MultipleImagePickView(text: " 会议图片", imgList: $viewModel.item.anList) 39 | // 图片预览 40 | ImageShowView(imgList: $viewModel.item.anList) 41 | 42 | submitButton(disableForm: disableForm) { saveOrUpdate() } 43 | .alert(isPresented: $errorFlag) { 44 | Alert(title: Text("消息提示"), message: Text(errorMsg), dismissButton: .default(Text("知道了!"))) 45 | } 46 | } 47 | .listStyle(PlainListStyle()) 48 | .navigationBarTitle(id != nil ? "会议信息详情" : "新增会议信息", displayMode: .inline) 49 | .gesture( 50 | DragGesture() 51 | .onChanged { _ in 52 | hideKeyboard() 53 | } 54 | ) 55 | .onAppear { 56 | echoData() 57 | } 58 | } 59 | 60 | // 更新界面需要回显数据 61 | private func echoData() { 62 | if let id = id { // 更新 - 回显数据 63 | viewModel.fetchDetail(id: id) { 64 | // 对一些比较特殊的数据进行处理, 如时间等 65 | processEchoData() 66 | } 67 | } else { // 新增 - 初始化数据 68 | viewModel.item = Meeting() 69 | } 70 | } 71 | 72 | private func processEchoData() { 73 | // 宣传时间 74 | if viewModel.item.mtTime.isBlank { 75 | self.mtTime = Date() 76 | } else { 77 | self.mtTime = string2Date(viewModel.item.mtTime) 78 | } 79 | } 80 | 81 | private func saveOrUpdate() { 82 | let item = buildSubmitData() 83 | 84 | if self.id == nil { 85 | // 新增 86 | viewModel.addData(item: item) { result in 87 | switch result { 88 | case .success: 89 | self.presentationMode.wrappedValue.dismiss() 90 | case let .failure(error): 91 | self.errorMsg = error.localizedDescription 92 | self.errorFlag = true 93 | } 94 | } 95 | } else { 96 | // 更新 97 | viewModel.updateData(item: item) { result in 98 | // 有 BUG 待修复 99 | switch result { 100 | case .success: 101 | self.presentationMode.wrappedValue.dismiss() 102 | case let .failure(error): 103 | self.errorMsg = error.localizedDescription 104 | self.errorFlag = true 105 | } 106 | } 107 | } 108 | } 109 | 110 | private func buildSubmitData() -> Meeting { 111 | var obj: Meeting = viewModel.item 112 | obj.mtTime = date2String(self.mtTime) // 会议时间 113 | obj.annexIds = obj.anList.map { $0.id } 114 | return obj 115 | } 116 | 117 | 118 | } 119 | 120 | //struct MeetingDetailView_Previews: PreviewProvider { 121 | // static var previews: some View { 122 | // MeetingDetailView() 123 | // } 124 | //} 125 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/UI/Map/MapDemo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MapDemo.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/4/4. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct MapDemo: View { 11 | @StateObject var locationViewModel = LocationViewModel() // 地理 12 | 13 | @State var address = "" // 地址名称 14 | @State var longitude = "" // 经度 15 | @State var latitude = "" // 纬度 16 | 17 | @State var showHelp: Bool = false // 显示帮助页面 18 | @State var errorFlag: Bool = false // 错误弹框 19 | @State var errorMsg: String = "" // 错误消息 20 | 21 | var body: some View { 22 | Group { 23 | List { 24 | HStack { 25 | Text("当前地址:") 26 | TextField("点击图标跳转高德地图", text: $address) 27 | Spacer() 28 | Image(systemName: "location.circle.fill") 29 | .onTapGesture { 30 | if (longitude.isBlank || latitude.isBlank) { 31 | self.errorMsg = "经纬度为空,无法跳转!" 32 | self.errorFlag = true 33 | } else if address.isBlank { 34 | self.errorMsg = "当前地址名称为空,请输入一个名称!" 35 | self.errorFlag = true 36 | } else { 37 | // 跳转高德地图,没有高德地图则打开 Appp Sotre 38 | MapNavigation.showLocation(address, lat: latitude, lng: longitude) 39 | } 40 | } 41 | .alert(isPresented: $errorFlag) { 42 | Alert(title: Text("消息提示"), message: Text(errorMsg), dismissButton: .default(Text("知道了!"))) 43 | } 44 | 45 | } 46 | HStack { 47 | Text("单位经度:") 48 | TextField("点击图标获取", text: $longitude) 49 | Spacer() 50 | Image(systemName: "location.magnifyingglass") 51 | .onTapGesture { 52 | // 判断授权状态 53 | switch locationViewModel.authorizationStatus { 54 | case .notDetermined: 55 | locationViewModel.requestPermission() 56 | case .restricted: 57 | self.errorMsg = "获取权限被拒绝,请在设置中开启" 58 | self.errorFlag = true 59 | case .denied: 60 | self.errorMsg = "未获取到地理位置权限,请在设置中开启" 61 | self.errorFlag = true 62 | case .authorizedAlways, .authorizedWhenInUse: 63 | // 已授权,点击获取当前位置 64 | let co = locationViewModel.lastSeenLocation?.coordinate 65 | let lng = co?.longitude ?? 0 66 | let lat = co?.latitude ?? 0 67 | longitude = (lng == 0) ? "" : String(lng) 68 | latitude = (lat == 0) ? "" : String(lat) 69 | default: 70 | self.errorMsg = "未知错误!" 71 | self.errorFlag = true 72 | } 73 | } 74 | } 75 | HStack { 76 | Text("单位纬度:") 77 | TextField("点击图标获取经纬度", text: $latitude) 78 | } 79 | HStack { 80 | Text("地图更多用法参考:") 81 | Spacer() 82 | Link(destination: URL(string: "https://lbs.amap.com/api/amap-mobile/guide/ios/ios-uri-information")!) { 83 | Text("高德 IOS 开发文档") 84 | } 85 | } 86 | } 87 | } 88 | .navigationTitle("地图示例") 89 | .navigationBarTitleDisplayMode(.inline) 90 | .toolbar(content: { 91 | Button(action: { self.showHelp = true }) { 92 | Image(systemName: "questionmark.circle") 93 | .resizable() 94 | .aspectRatio(contentMode: .fit) 95 | .frame(width: 22) 96 | .foregroundColor(.black) 97 | } 98 | .sheet(isPresented: $showHelp) { 99 | Text(""" 100 | 该页面主要是对高德地图 API 的使用: 101 | 102 | 点击 [单位经度] 右边的图标 103 | 会尝试获取地理权限 104 | 授权以后再次点击 105 | 可以获取当前位置的经纬度 106 | 107 | 点击 [当前地址] 右边的图标 108 | 尝试用高德地图打开下面的经纬度 109 | 如果没有高德地图 110 | 则跳转到 AppStore 中的高德安装页面 111 | """) 112 | .padding() 113 | } 114 | }) 115 | } 116 | } 117 | 118 | struct MapDemo_Previews: PreviewProvider { 119 | static var previews: some View { 120 | MapDemo() 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/Api/NetworkManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkManager.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import Foundation 9 | import Alamofire 10 | import UIKit 11 | 12 | // 给类型取别名,增加代码的可读性 13 | typealias NetworkRequestResult = Result 14 | typealias NetworkRequestCompletion = (NetworkRequestResult) -> Void 15 | 16 | public let NetworkAPIBaseURL = "http://192.168.3.6:8080/" 17 | 18 | // 网络模块,设计为单例模式 19 | class NetworkManager { 20 | // 共享对象 21 | static let shared = NetworkManager() 22 | 23 | // 获取有token的请求头 24 | // 你应当在合适的时机, 将 token 存入 UserDefaults 中 25 | var commonHeaders: HTTPHeaders { ["token": UserDefaults.standard.string(forKey: "token") ?? ""] } 26 | 27 | private init() {} // 外部无法使用该类创建该对象 28 | 29 | // 封装http-get请求 30 | @discardableResult // 外部调用该函数可以没有返回值 31 | func requestGet(path: String, 32 | parameters: Parameters?, 33 | // @escaping,逃逸闭包: 一个闭包被作为一个参数传递给一个函数,并且在函数return之后才被唤起执行 34 | completion: @escaping NetworkRequestCompletion) -> DataRequest { 35 | AF.request(NetworkAPIBaseURL + path, 36 | parameters: parameters, 37 | headers: commonHeaders, 38 | requestModifier: { $0.timeoutInterval = 30 }) 39 | .responseData { response in 40 | switch response.result { 41 | case let .success(data): completion(.success(data)) 42 | case let .failure(error): completion(self.handleError(error)) 43 | } 44 | } 45 | } 46 | 47 | // 封装http-post请求 48 | @discardableResult 49 | func requestPost(path: String, 50 | parameters: Parameters?, 51 | completion: @escaping NetworkRequestCompletion) -> DataRequest { 52 | AF.request(NetworkAPIBaseURL + path, 53 | method: .post, 54 | parameters: parameters, 55 | encoding: JSONEncoding.prettyPrinted, // parameters的编码方式,默认为JSON 56 | headers: commonHeaders, 57 | requestModifier: { $0.timeoutInterval = 30 }) 58 | .responseData { response in 59 | // 请求发送成功与失败 60 | switch response.result { 61 | case let .success(data): completion(.success(data)) 62 | case let .failure(error): completion(self.handleError(error)) 63 | } 64 | } 65 | } 66 | 67 | // 图片上传 68 | @discardableResult 69 | func uploadImg(image: UIImage, 70 | to url: String, 71 | params: [String: Any], 72 | completion: @escaping NetworkRequestCompletion) -> DataRequest 73 | { 74 | AF.upload(multipartFormData: { multiPart in 75 | print(NetworkAPIBaseURL + url) 76 | for (key, value) in params { 77 | if let temp = value as? String { 78 | multiPart.append(temp.data(using: .utf8)!, withName: key) 79 | } 80 | if let temp = value as? Int { 81 | multiPart.append("\(temp)".data(using: .utf8)!, withName: key) 82 | } 83 | if let temp = value as? NSArray { 84 | temp.forEach({ element in 85 | let keyObj = key + "[]" 86 | if let string = element as? String { 87 | multiPart.append(string.data(using: .utf8)!, withName: keyObj) 88 | } else 89 | if let num = element as? Int { 90 | let value = "\(num)" 91 | multiPart.append(value.data(using: .utf8)!, withName: keyObj) 92 | } 93 | }) 94 | } 95 | } 96 | multiPart.append(image.jpegData(compressionQuality: 0.9)!, withName: "file", fileName: "file.png", mimeType: "image/png") 97 | }, to: NetworkAPIBaseURL + url) 98 | .uploadProgress(queue: .main, closure: { progress in 99 | print("Upload Progress: \(progress.fractionCompleted)") 100 | }) 101 | .responseData { response in 102 | switch response.result { 103 | case let .success(data): completion(.success(data)) 104 | case let .failure(error): completion(.failure(error)) 105 | } 106 | } 107 | } 108 | 109 | // 处理网络请求中的错误 110 | private func handleError(_ error: AFError) -> NetworkRequestResult { 111 | if let underlyingError = error.underlyingError { 112 | let nserror = underlyingError as NSError 113 | let code = nserror.code 114 | if code == NSURLErrorNotConnectedToInternet || 115 | code == NSURLErrorTimedOut || 116 | code == NSURLErrorInternationalRoamingOff || 117 | code == NSURLErrorDataNotAllowed || 118 | code == NSURLErrorCannotFindHost || 119 | code == NSURLErrorCannotConnectToHost || 120 | code == NSURLErrorNetworkConnectionLost { 121 | var userInfo = nserror.userInfo 122 | userInfo[NSLocalizedDescriptionKey] = "网络连接有问题喔~" 123 | let currentError = NSError(domain: nserror.domain, code: code, userInfo: userInfo) 124 | return .failure(currentError) 125 | } 126 | } 127 | return .failure(error) 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame/Api/CommonVM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CommonVM.swift 3 | // ZYSwiftUIFrame 4 | // 5 | // Created by lzy on 2022/3/31. 6 | // 7 | 8 | import Foundation 9 | import Alamofire 10 | 11 | class CommonVM: ObservableObject where T: Codable { 12 | // API 13 | let thisAPI: CommonApiObj 14 | 15 | // 数据列表 16 | @Published var items: [T] = [] 17 | @Published var page: Int = 1 18 | @Published var total: Int = 0 19 | 20 | // 下拉刷新, 上拉加载 21 | @Published var isRefreshing: Bool = false 22 | @Published var isLoadingMore: Bool = false 23 | @Published var isReloadData: Bool = false 24 | 25 | // 详情 26 | @Published var item: T 27 | 28 | // 过滤条件 29 | @Published var filterParams: Parameters = ["pageSize": 15] 30 | 31 | init (item: T, module: String) { 32 | self.item = item 33 | self.module = module 34 | self.thisAPI = CommonApiObj(moduleUrl: module) 35 | } 36 | 37 | init (item: T, apiObj: CommonApiObj) { 38 | self.item = item 39 | self.module = apiObj.moduleUrl 40 | self.thisAPI = apiObj 41 | 42 | self.fetchData {} 43 | } 44 | 45 | // 没有更多 46 | var noMore: Bool { 47 | items.count >= total 48 | } 49 | 50 | var module: String = String(describing: T.self).lowercasedFisterLetter() 51 | 52 | // 获取数据 53 | func fetchData(completion: @escaping () -> Void) { 54 | filterParams["page"] = 1 55 | thisAPI.list(parameters: filterParams) { res in 56 | switch res { 57 | case let .success(data): 58 | guard let res = data.data else { 59 | print("CommonViewModel: 未从\(self.module)接口中获取到数据 \(data.message)") 60 | return 61 | } 62 | self.items = res.records 63 | self.page = 2 64 | self.total = res.total 65 | 66 | completion() 67 | case let .failure(error): 68 | print("获取\(self.module)列表失败 \(error.localizedDescription)") 69 | } 70 | } 71 | } 72 | 73 | // 获取更多数据 74 | func fetchMoreData(completion: @escaping () -> Void) { 75 | filterParams["page"] = page 76 | thisAPI.list(parameters: filterParams) { res in 77 | switch res { 78 | case let .success(data): 79 | guard let res = data.data else { 80 | print("未从\(self.module)接口获取到数据 \(data.message)") 81 | return 82 | } 83 | if (self.items.count < res.total) { 84 | self.items.append(contentsOf: res.records) 85 | self.page = res.page + 1 86 | self.total = res.total 87 | } 88 | completion() 89 | case let .failure(error): 90 | print("获取\(self.module)列表失败 \(error.localizedDescription)") 91 | } 92 | } 93 | } 94 | 95 | // 获取详情 96 | func fetchDetail(id: Int, completion: @escaping () -> Void) { 97 | thisAPI.detail(id: id) { result in 98 | switch result { 99 | case let .success(data): 100 | guard let resp = data.data else { 101 | print("未从\(self.module)详情接口获取数据 \(data.message)") 102 | return 103 | } 104 | self.item = resp 105 | // 处理特殊数据 106 | completion() 107 | case let .failure(error): 108 | print("加载\(self.module)详情失败 \(error.localizedDescription)") 109 | } 110 | } 111 | } 112 | 113 | // 更新数据 114 | func updateData(item: T, completion: @escaping (Result) -> Void) { 115 | thisAPI.update(obj: item) { result in 116 | switch result { 117 | case let .success(resp): 118 | if resp.code == 0 { 119 | // 处理当前数据数组 120 | if let idx = self.items.firstIndex(where: { $0.id == item.id }) { 121 | self.items[idx] = item 122 | completion(.success("")) 123 | } 124 | completion(.success("")) 125 | } else { 126 | print("更新\(self.module)接口调用错误 \(resp.message)") 127 | let error = NSError(domain: "ApiError", code: 0, userInfo: [NSLocalizedDescriptionKey: resp.message]) 128 | completion(.failure(error)) 129 | } 130 | case let .failure(error): 131 | print("更新\(self.module)失败:\(error.localizedDescription)") 132 | completion(.failure(error)) 133 | } 134 | } 135 | } 136 | 137 | // 新增数据 138 | func addData(item: T, completion: @escaping (Result) -> Void) { 139 | thisAPI.save(obj: item) { result in 140 | switch result { 141 | case let .success(resp): 142 | if resp.code == 0 { 143 | // 新增完后刷新页面 144 | self.fetchData {} 145 | completion(.success("")) 146 | } else { 147 | print("新增\(self.module)接口调用错误 \(resp.message)") 148 | let error = NSError(domain: "ApiError", code: 0, userInfo: [NSLocalizedDescriptionKey: resp.message]) 149 | completion(.failure(error)) 150 | } 151 | case let .failure(error): 152 | print("新增\(self.module)失败:\(error.localizedDescription)") 153 | completion(.failure(error)) 154 | } 155 | } 156 | } 157 | 158 | // 删除数据 159 | func deleteData(item: T, completion: @escaping() -> Void) { 160 | thisAPI.delete(id: item.id as! Int) { result in 161 | switch result { 162 | case let .success(data): 163 | if data.code == 0 { 164 | // 处理当前数据 165 | let idx = self.items.firstIndex { $0.id == item.id } 166 | self.items.remove(at: idx!) 167 | completion() 168 | } else { 169 | print("调用\(self.module)删除接口失败 \(data.message)") 170 | } 171 | case let .failure(error): 172 | print("删除\(self.module)失败 \(error.localizedDescription)") 173 | } 174 | } 175 | } 176 | 177 | } 178 | -------------------------------------------------------------------------------- /go_api_server/go.sum: -------------------------------------------------------------------------------- 1 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= 5 | github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= 6 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 7 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 8 | github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= 9 | github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= 10 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 11 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 12 | github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= 13 | github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= 14 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 15 | github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= 16 | github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= 17 | github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= 18 | github.com/go-playground/validator/v10 v10.10.1 h1:uA0+amWMiglNZKZ9FJRKUAe9U3RX91eVn1JYXMWt7ig= 19 | github.com/go-playground/validator/v10 v10.10.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= 20 | github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= 21 | github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 22 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 23 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 24 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 25 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 26 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 27 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 28 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 29 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 30 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 31 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 32 | github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas= 33 | github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 34 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 35 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 36 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 37 | github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 38 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 39 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 40 | github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 41 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 42 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 43 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 44 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 45 | github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= 46 | github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= 47 | github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= 48 | github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= 49 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 50 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= 51 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 52 | github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= 53 | github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 54 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 55 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 56 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 57 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 58 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 59 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 60 | github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= 61 | github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= 62 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 63 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 64 | github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= 65 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 66 | github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 67 | github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= 68 | github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= 69 | github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= 70 | github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= 71 | github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 72 | github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= 73 | github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 74 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 75 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 76 | github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= 77 | github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= 78 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 79 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 80 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 81 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 82 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 83 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 84 | github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= 85 | github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= 86 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 87 | github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= 88 | github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= 89 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 90 | github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= 91 | github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= 92 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 93 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 94 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 95 | golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 96 | golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 h1:S25/rfnfsMVgORT4/J61MJ7rdyseOZOyvLIrZEZ7s6s= 97 | golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 98 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 99 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 100 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 101 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 102 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 103 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 104 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 105 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 106 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 107 | golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 108 | golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886 h1:eJv7u3ksNXoLbGSKuv2s/SIO4tJVxc/A+MTpzxDgz/Q= 109 | golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 110 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 111 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 112 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 113 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 114 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 115 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 116 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 117 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 118 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 119 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 120 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 121 | google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= 122 | google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 123 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 124 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 125 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 126 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 127 | gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= 128 | gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 129 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 130 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 131 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 132 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 133 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 134 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 135 | gorm.io/driver/mysql v1.3.2 h1:QJryWiqQ91EvZ0jZL48NOpdlPdMjdip1hQ8bTgo4H7I= 136 | gorm.io/driver/mysql v1.3.2/go.mod h1:ChK6AHbHgDCFZyJp0F+BmVGb06PSIoh9uVYKAlRbb2U= 137 | gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= 138 | gorm.io/gorm v1.23.3 h1:jYh3nm7uLZkrMVfA8WVNjDZryKfr7W+HTlInVgKFJAg= 139 | gorm.io/gorm v1.23.3/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= 140 | -------------------------------------------------------------------------------- /go_api_server/sql/testpro.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : 127.0.0.1 5 | Source Server Type : MySQL 6 | Source Server Version : 50737 7 | Source Host : localhost:3306 8 | Source Schema : testpro 9 | 10 | Target Server Type : MySQL 11 | Target Server Version : 50737 12 | File Encoding : 65001 13 | 14 | Date: 03/04/2022 21:27:52 15 | */ 16 | 17 | SET NAMES utf8mb4; 18 | SET FOREIGN_KEY_CHECKS = 0; 19 | 20 | -- ---------------------------- 21 | -- Table structure for meeting 22 | -- ---------------------------- 23 | DROP TABLE IF EXISTS `meeting`; 24 | CREATE TABLE `meeting` ( 25 | `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 26 | `created_at` datetime(3) DEFAULT NULL, 27 | `updated_at` datetime(3) DEFAULT NULL, 28 | `remark` longtext COMMENT '备注', 29 | `mt_name` longtext COMMENT '会议名称', 30 | `mt_theme` longtext COMMENT '会议主题', 31 | `mt_summary` longtext COMMENT '会议概要', 32 | `mt_content` longtext COMMENT '会议内容', 33 | `mt_member` longtext COMMENT '参会人员', 34 | `mt_time` longtext COMMENT '开会时间', 35 | `create_user` bigint(20) DEFAULT NULL COMMENT '创建人', 36 | PRIMARY KEY (`id`) 37 | ) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8; 38 | 39 | -- ---------------------------- 40 | -- Records of meeting 41 | -- ---------------------------- 42 | BEGIN; 43 | INSERT INTO `meeting` VALUES (7, '2022-04-01 21:31:37.028', '2022-04-03 01:14:16.368', '123123', '会议名称123', '会议主题123', '会议概要677', '会议内容6', '成员6', '2022-04-01 00:00:00', 0); 44 | INSERT INTO `meeting` VALUES (12, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称11', '会议主题11', '会议概要11', '会议内容11', '成员11', '2022-04-01', 0); 45 | INSERT INTO `meeting` VALUES (14, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称13', '会议主题13', '会议概要13', '会议内容13', '成员13', '2022-04-01', 0); 46 | INSERT INTO `meeting` VALUES (15, '2022-04-01 21:31:37.028', '2022-04-02 17:39:41.740', '', '新增会议A', '新增会议主题B', '新增会议概要C', '新增会议内容C', '新增会议成员D', '2022-02-20 14:00:00', 0); 47 | INSERT INTO `meeting` VALUES (16, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称15', '会议主题15', '会议概要15', '会议内容15', '成员15', '2022-04-01', 0); 48 | INSERT INTO `meeting` VALUES (17, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称16', '会议主题16', '会议概要16', '会议内容16', '成员16', '2022-04-01', 0); 49 | INSERT INTO `meeting` VALUES (18, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称17', '会议主题17', '会议概要17', '会议内容17', '成员17', '2022-04-01', 0); 50 | INSERT INTO `meeting` VALUES (19, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称18', '会议主题18', '会议概要18', '会议内容18', '成员18', '2022-04-01', 0); 51 | INSERT INTO `meeting` VALUES (20, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称19', '会议主题19', '会议概要19', '会议内容19', '成员19', '2022-04-01', 0); 52 | INSERT INTO `meeting` VALUES (21, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称20', '会议主题20', '会议概要20', '会议内容20', '成员20', '2022-04-01', 0); 53 | INSERT INTO `meeting` VALUES (22, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称21', '会议主题21', '会议概要21', '会议内容21', '成员21', '2022-04-01', 0); 54 | INSERT INTO `meeting` VALUES (23, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称22', '会议主题22', '会议概要22', '会议内容22', '成员22', '2022-04-01', 0); 55 | INSERT INTO `meeting` VALUES (24, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称23', '会议主题23', '会议概要23', '会议内容23', '成员23', '2022-04-01', 0); 56 | INSERT INTO `meeting` VALUES (25, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称24', '会议主题24', '会议概要24', '会议内容24', '成员24', '2022-04-01', 0); 57 | INSERT INTO `meeting` VALUES (26, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称25', '会议主题25', '会议概要25', '会议内容25', '成员25', '2022-04-01', 0); 58 | INSERT INTO `meeting` VALUES (27, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称26', '会议主题26', '会议概要26', '会议内容26', '成员26', '2022-04-01', 0); 59 | INSERT INTO `meeting` VALUES (28, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称27', '会议主题27', '会议概要27', '会议内容27', '成员27', '2022-04-01', 0); 60 | INSERT INTO `meeting` VALUES (29, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称28', '会议主题28', '会议概要28', '会议内容28', '成员28', '2022-04-01', 0); 61 | INSERT INTO `meeting` VALUES (30, '2022-04-01 21:31:37.028', '2022-04-01 21:31:37.028', '', '会议名称29', '会议主题29', '会议概要29', '会议内容29', '成员29', '2022-04-01', 0); 62 | INSERT INTO `meeting` VALUES (32, '2022-04-03 01:14:29.513', '2022-04-03 21:26:40.894', '66666', '111111', '22222', '3333344', '44444', '55555', '2022-04-03 01:14:18', -1); 63 | COMMIT; 64 | 65 | -- ---------------------------- 66 | -- Table structure for message 67 | -- ---------------------------- 68 | DROP TABLE IF EXISTS `message`; 69 | CREATE TABLE `message` ( 70 | `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 71 | `created_at` datetime(3) DEFAULT NULL, 72 | `updated_at` datetime(3) DEFAULT NULL, 73 | `remark` longtext COMMENT '备注', 74 | `theme` longtext COMMENT '消息标题', 75 | `content` longtext COMMENT '消息内容', 76 | `is_read` bigint(20) DEFAULT NULL COMMENT '是否已读', 77 | `receive_user` bigint(20) DEFAULT NULL COMMENT '接收人id', 78 | `send_user` bigint(20) DEFAULT NULL COMMENT '发送人id', 79 | PRIMARY KEY (`id`) 80 | ) ENGINE=InnoDB AUTO_INCREMENT=51 DEFAULT CHARSET=utf8; 81 | 82 | -- ---------------------------- 83 | -- Records of message 84 | -- ---------------------------- 85 | BEGIN; 86 | INSERT INTO `message` VALUES (5, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题4', '这是消息的具体内容4这是消息的具体内容4这是消息的具体内容4这是消息的具体内容4这是消息的具体内容4', 0, 0, 0); 87 | INSERT INTO `message` VALUES (7, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题6', '这是消息的具体内容6这是消息的具体内容6这是消息的具体内容6这是消息的具体内容6这是消息的具体内容6', 0, 0, 0); 88 | INSERT INTO `message` VALUES (8, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题7', '这是消息的具体内容7这是消息的具体内容7这是消息的具体内容7这是消息的具体内容7这是消息的具体内容7', 0, 0, 0); 89 | INSERT INTO `message` VALUES (9, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题8', '这是消息的具体内容8这是消息的具体内容8这是消息的具体内容8这是消息的具体内容8这是消息的具体内容8', 0, 0, 0); 90 | INSERT INTO `message` VALUES (10, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题9', '这是消息的具体内容9这是消息的具体内容9这是消息的具体内容9这是消息的具体内容9这是消息的具体内容9', 0, 0, 0); 91 | INSERT INTO `message` VALUES (11, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题10', '这是消息的具体内容10这是消息的具体内容10这是消息的具体内容10这是消息的具体内容10这是消息的具体内容10', 0, 0, 0); 92 | INSERT INTO `message` VALUES (12, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题11', '这是消息的具体内容11这是消息的具体内容11这是消息的具体内容11这是消息的具体内容11这是消息的具体内容11', 0, 0, 0); 93 | INSERT INTO `message` VALUES (13, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题12', '这是消息的具体内容12这是消息的具体内容12这是消息的具体内容12这是消息的具体内容12这是消息的具体内容12', 0, 0, 0); 94 | INSERT INTO `message` VALUES (14, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题13', '这是消息的具体内容13这是消息的具体内容13这是消息的具体内容13这是消息的具体内容13这是消息的具体内容13', 0, 0, 0); 95 | INSERT INTO `message` VALUES (15, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题14', '这是消息的具体内容14这是消息的具体内容14这是消息的具体内容14这是消息的具体内容14这是消息的具体内容14', 0, 0, 0); 96 | INSERT INTO `message` VALUES (16, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题15', '这是消息的具体内容15这是消息的具体内容15这是消息的具体内容15这是消息的具体内容15这是消息的具体内容15', 0, 0, 0); 97 | INSERT INTO `message` VALUES (17, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题16', '这是消息的具体内容16这是消息的具体内容16这是消息的具体内容16这是消息的具体内容16这是消息的具体内容16', 0, 0, 0); 98 | INSERT INTO `message` VALUES (18, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题17', '这是消息的具体内容17这是消息的具体内容17这是消息的具体内容17这是消息的具体内容17这是消息的具体内容17', 0, 0, 0); 99 | INSERT INTO `message` VALUES (19, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题18', '这是消息的具体内容18这是消息的具体内容18这是消息的具体内容18这是消息的具体内容18这是消息的具体内容18', 0, 0, 0); 100 | INSERT INTO `message` VALUES (20, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题19', '这是消息的具体内容19这是消息的具体内容19这是消息的具体内容19这是消息的具体内容19这是消息的具体内容19', 0, 0, 0); 101 | INSERT INTO `message` VALUES (21, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题20', '这是消息的具体内容20这是消息的具体内容20这是消息的具体内容20这是消息的具体内容20这是消息的具体内容20', 0, 0, 0); 102 | INSERT INTO `message` VALUES (22, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题21', '这是消息的具体内容21这是消息的具体内容21这是消息的具体内容21这是消息的具体内容21这是消息的具体内容21', 0, 0, 0); 103 | INSERT INTO `message` VALUES (23, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题22', '这是消息的具体内容22这是消息的具体内容22这是消息的具体内容22这是消息的具体内容22这是消息的具体内容22', 0, 0, 0); 104 | INSERT INTO `message` VALUES (24, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题23', '这是消息的具体内容23这是消息的具体内容23这是消息的具体内容23这是消息的具体内容23这是消息的具体内容23', 0, 0, 0); 105 | INSERT INTO `message` VALUES (25, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题24', '这是消息的具体内容24这是消息的具体内容24这是消息的具体内容24这是消息的具体内容24这是消息的具体内容24', 0, 0, 0); 106 | INSERT INTO `message` VALUES (26, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题25', '这是消息的具体内容25这是消息的具体内容25这是消息的具体内容25这是消息的具体内容25这是消息的具体内容25', 0, 0, 0); 107 | INSERT INTO `message` VALUES (27, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题26', '这是消息的具体内容26这是消息的具体内容26这是消息的具体内容26这是消息的具体内容26这是消息的具体内容26', 0, 0, 0); 108 | INSERT INTO `message` VALUES (28, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题27', '这是消息的具体内容27这是消息的具体内容27这是消息的具体内容27这是消息的具体内容27这是消息的具体内容27', 0, 0, 0); 109 | INSERT INTO `message` VALUES (29, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题28', '这是消息的具体内容28这是消息的具体内容28这是消息的具体内容28这是消息的具体内容28这是消息的具体内容28', 0, 0, 0); 110 | INSERT INTO `message` VALUES (30, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题29', '这是消息的具体内容29这是消息的具体内容29这是消息的具体内容29这是消息的具体内容29这是消息的具体内容29', 0, 0, 0); 111 | INSERT INTO `message` VALUES (31, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题30', '这是消息的具体内容30这是消息的具体内容30这是消息的具体内容30这是消息的具体内容30这是消息的具体内容30', 0, 0, 0); 112 | INSERT INTO `message` VALUES (32, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题31', '这是消息的具体内容31这是消息的具体内容31这是消息的具体内容31这是消息的具体内容31这是消息的具体内容31', 0, 0, 0); 113 | INSERT INTO `message` VALUES (33, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题32', '这是消息的具体内容32这是消息的具体内容32这是消息的具体内容32这是消息的具体内容32这是消息的具体内容32', 0, 0, 0); 114 | INSERT INTO `message` VALUES (35, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题34', '这是消息的具体内容34这是消息的具体内容34这是消息的具体内容34这是消息的具体内容34这是消息的具体内容34', 0, 0, 0); 115 | INSERT INTO `message` VALUES (37, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题36', '这是消息的具体内容36这是消息的具体内容36这是消息的具体内容36这是消息的具体内容36这是消息的具体内容36', 0, 0, 0); 116 | INSERT INTO `message` VALUES (38, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题37', '这是消息的具体内容37这是消息的具体内容37这是消息的具体内容37这是消息的具体内容37这是消息的具体内容37', 0, 0, 0); 117 | INSERT INTO `message` VALUES (39, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题38', '这是消息的具体内容38这是消息的具体内容38这是消息的具体内容38这是消息的具体内容38这是消息的具体内容38', 0, 0, 0); 118 | INSERT INTO `message` VALUES (40, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题39', '这是消息的具体内容39这是消息的具体内容39这是消息的具体内容39这是消息的具体内容39这是消息的具体内容39', 0, 0, 0); 119 | INSERT INTO `message` VALUES (41, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题40', '这是消息的具体内容40这是消息的具体内容40这是消息的具体内容40这是消息的具体内容40这是消息的具体内容40', 0, 0, 0); 120 | INSERT INTO `message` VALUES (42, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题41', '这是消息的具体内容41这是消息的具体内容41这是消息的具体内容41这是消息的具体内容41这是消息的具体内容41', 0, 0, 0); 121 | INSERT INTO `message` VALUES (43, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题42', '这是消息的具体内容42这是消息的具体内容42这是消息的具体内容42这是消息的具体内容42这是消息的具体内容42', 0, 0, 0); 122 | INSERT INTO `message` VALUES (44, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题43', '这是消息的具体内容43这是消息的具体内容43这是消息的具体内容43这是消息的具体内容43这是消息的具体内容43', 0, 0, 0); 123 | INSERT INTO `message` VALUES (45, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题44', '这是消息的具体内容44这是消息的具体内容44这是消息的具体内容44这是消息的具体内容44这是消息的具体内容44', 0, 0, 0); 124 | INSERT INTO `message` VALUES (46, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题45', '这是消息的具体内容45这是消息的具体内容45这是消息的具体内容45这是消息的具体内容45这是消息的具体内容45', 0, 0, 0); 125 | INSERT INTO `message` VALUES (47, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题46', '这是消息的具体内容46这是消息的具体内容46这是消息的具体内容46这是消息的具体内容46这是消息的具体内容46', 0, 0, 0); 126 | INSERT INTO `message` VALUES (48, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题47', '这是消息的具体内容47这是消息的具体内容47这是消息的具体内容47这是消息的具体内容47这是消息的具体内容47', 0, 0, 0); 127 | INSERT INTO `message` VALUES (49, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题48', '这是消息的具体内容48这是消息的具体内容48这是消息的具体内容48这是消息的具体内容48这是消息的具体内容48', 0, 0, 0); 128 | INSERT INTO `message` VALUES (50, '2022-04-01 21:31:37.024', '2022-04-01 21:31:37.024', '', '消息主题49', '这是消息的具体内容49这是消息的具体内容49这是消息的具体内容49这是消息的具体内容49这是消息的具体内容49', 0, 0, 0); 129 | COMMIT; 130 | 131 | -- ---------------------------- 132 | -- Table structure for sys_user 133 | -- ---------------------------- 134 | DROP TABLE IF EXISTS `sys_user`; 135 | CREATE TABLE `sys_user` ( 136 | `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 137 | `created_at` datetime(3) DEFAULT NULL, 138 | `updated_at` datetime(3) DEFAULT NULL, 139 | `remark` longtext COMMENT '备注', 140 | `username` longtext COMMENT '用户登录名', 141 | `password` longtext COMMENT '用户登录密码', 142 | `nickname` longtext COMMENT '用户昵称', 143 | `phone` longtext COMMENT '用户手机号码', 144 | `header_img` varchar(191) DEFAULT 'https://qmplusimg.henrongyi.top/gva_header.jpg' COMMENT '用户头像', 145 | PRIMARY KEY (`id`) 146 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 147 | 148 | -- ---------------------------- 149 | -- Records of sys_user 150 | -- ---------------------------- 151 | BEGIN; 152 | COMMIT; 153 | 154 | -- ---------------------------- 155 | -- Table structure for upload_and_download 156 | -- ---------------------------- 157 | DROP TABLE IF EXISTS `upload_and_download`; 158 | CREATE TABLE `upload_and_download` ( 159 | `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 160 | `created_at` datetime(3) DEFAULT NULL, 161 | `updated_at` datetime(3) DEFAULT NULL, 162 | `remark` longtext COMMENT '备注', 163 | `name` longtext COMMENT '文件名', 164 | `url` longtext COMMENT '文件地址', 165 | `tag` longtext COMMENT '文件标签', 166 | `key` longtext COMMENT '编号', 167 | `meeting_id` bigint(20) unsigned DEFAULT NULL, 168 | PRIMARY KEY (`id`) 169 | ) ENGINE=InnoDB AUTO_INCREMENT=48 DEFAULT CHARSET=utf8; 170 | 171 | -- ---------------------------- 172 | -- Records of upload_and_download 173 | -- ---------------------------- 174 | BEGIN; 175 | INSERT INTO `upload_and_download` VALUES (45, '2022-04-03 21:26:39.163', '2022-04-03 21:26:40.885', '', '2022_04_03_21_26_39_821file.png', 'uploads/file/2022_04_03_21_26_39_821file.png', '普通文件', '普通文件', 32); 176 | INSERT INTO `upload_and_download` VALUES (46, '2022-04-03 21:26:39.165', '2022-04-03 21:26:40.885', '', '2022_04_03_21_26_39_51file.png', 'uploads/file/2022_04_03_21_26_39_51file.png', '普通文件', '普通文件', 32); 177 | INSERT INTO `upload_and_download` VALUES (47, '2022-04-03 21:26:39.180', '2022-04-03 21:26:40.885', '', '2022_04_03_21_26_39_937file.png', 'uploads/file/2022_04_03_21_26_39_937file.png', '普通文件', '普通文件', 32); 178 | COMMIT; 179 | 180 | SET FOREIGN_KEY_CHECKS = 1; 181 | -------------------------------------------------------------------------------- /ZYSwiftUIFrame/ZYSwiftUIFrame.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 55; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 844B4BB027F594A900D329F2 /* ZYSwiftUIFrameApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B4BAF27F594A900D329F2 /* ZYSwiftUIFrameApp.swift */; }; 11 | 844B4BB227F594A900D329F2 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B4BB127F594A900D329F2 /* ContentView.swift */; }; 12 | 844B4BB427F594AB00D329F2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 844B4BB327F594AB00D329F2 /* Assets.xcassets */; }; 13 | 844B4BB727F594AB00D329F2 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 844B4BB627F594AB00D329F2 /* Preview Assets.xcassets */; }; 14 | 844B4BC027F5986600D329F2 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B4BBF27F5986600D329F2 /* NetworkManager.swift */; }; 15 | 844B4BC327F598DA00D329F2 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 844B4BC227F598DA00D329F2 /* Alamofire */; }; 16 | 844B4BC527F599C600D329F2 /* BaseApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B4BC427F599C600D329F2 /* BaseApi.swift */; }; 17 | 847443C427F8937500E92F16 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847443C327F8937500E92F16 /* AboutView.swift */; }; 18 | 847E0CB427F8793D00CA64E0 /* UserDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847E0CB327F8793D00CA64E0 /* UserDetailView.swift */; }; 19 | 848A976027F82BF500B6DC03 /* UploadApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848A975F27F82BF500B6DC03 /* UploadApi.swift */; }; 20 | 848A976327F82C5100B6DC03 /* Upload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848A976227F82C5100B6DC03 /* Upload.swift */; }; 21 | 848A976927F82E5C00B6DC03 /* MultipleImagePickView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848A976827F82E5C00B6DC03 /* MultipleImagePickView.swift */; }; 22 | 848A976B27F82E6F00B6DC03 /* ImagePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848A976A27F82E6F00B6DC03 /* ImagePickerView.swift */; }; 23 | 848A976D27F8302B00B6DC03 /* ImageShowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848A976C27F8302B00B6DC03 /* ImageShowView.swift */; }; 24 | 848A976F27F830B900B6DC03 /* ImageUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848A976E27F830B900B6DC03 /* ImageUtil.swift */; }; 25 | 848A977327F8490A00B6DC03 /* ImageViewerRemote in Frameworks */ = {isa = PBXBuildFile; productRef = 848A977227F8490A00B6DC03 /* ImageViewerRemote */; }; 26 | 848A977927F858E700B6DC03 /* SDWebImageSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = 848A977827F858E700B6DC03 /* SDWebImageSwiftUI */; }; 27 | 84ACD9CC27F59A5300C9C5C8 /* CommonApiObj.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84ACD9CB27F59A5300C9C5C8 /* CommonApiObj.swift */; }; 28 | 84ACD9CE27F59ACB00C9C5C8 /* CommonVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84ACD9CD27F59ACB00C9C5C8 /* CommonVM.swift */; }; 29 | 84ACD9D127F59B2100C9C5C8 /* ZYRefreshView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84ACD9D027F59B2100C9C5C8 /* ZYRefreshView.swift */; }; 30 | 84ACD9D427F59B3B00C9C5C8 /* BBSwiftUIKit in Frameworks */ = {isa = PBXBuildFile; productRef = 84ACD9D327F59B3B00C9C5C8 /* BBSwiftUIKit */; }; 31 | 84ACD9D627F59B7F00C9C5C8 /* ZYListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84ACD9D527F59B7F00C9C5C8 /* ZYListView.swift */; }; 32 | 84ACD9D827F59D6800C9C5C8 /* ZYNavBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84ACD9D727F59D6800C9C5C8 /* ZYNavBarView.swift */; }; 33 | 84ACD9DA27F59DBB00C9C5C8 /* ServerResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84ACD9D927F59DBB00C9C5C8 /* ServerResponse.swift */; }; 34 | 84ACD9DD27F59E1E00C9C5C8 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84ACD9DC27F59E1E00C9C5C8 /* Constants.swift */; }; 35 | 84ACD9DF27F59E8500C9C5C8 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84ACD9DE27F59E8500C9C5C8 /* Extensions.swift */; }; 36 | 84ACD9E227F5A31000C9C5C8 /* Meeting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84ACD9E127F5A31000C9C5C8 /* Meeting.swift */; }; 37 | 84ACD9E527F5A35000C9C5C8 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84ACD9E427F5A35000C9C5C8 /* Message.swift */; }; 38 | 84ACD9E727F5A39D00C9C5C8 /* CodableDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84ACD9E627F5A39D00C9C5C8 /* CodableDefault.swift */; }; 39 | 84ACD9E927F5A3F500C9C5C8 /* MessageAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84ACD9E827F5A3F500C9C5C8 /* MessageAPI.swift */; }; 40 | 84ACD9EB27F5A44400C9C5C8 /* MessageVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84ACD9EA27F5A44400C9C5C8 /* MessageVM.swift */; }; 41 | 84ACD9ED27F5A4C800C9C5C8 /* MessageListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84ACD9EC27F5A4C800C9C5C8 /* MessageListView.swift */; }; 42 | 84ACD9EF27F5B78500C9C5C8 /* MessageDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84ACD9EE27F5B78500C9C5C8 /* MessageDetailView.swift */; }; 43 | 84B82ABA27FB32380053C29B /* MapDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B82AB927FB32380053C29B /* MapDemo.swift */; }; 44 | 84B82ABC27FB33510053C29B /* MapNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B82ABB27FB33510053C29B /* MapNavigation.swift */; }; 45 | 84B82ABE27FB34080053C29B /* LocationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B82ABD27FB34080053C29B /* LocationViewModel.swift */; }; 46 | 84B82AC227FB402D0053C29B /* NotificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B82AC127FB402D0053C29B /* NotificationView.swift */; }; 47 | 84C089D927F5D52F0059AA1A /* MeetingAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C089D827F5D52F0059AA1A /* MeetingAPI.swift */; }; 48 | 84C089DB27F5D55A0059AA1A /* MeetingVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C089DA27F5D55A0059AA1A /* MeetingVM.swift */; }; 49 | 84C089DD27F5D5BB0059AA1A /* MeetingListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C089DC27F5D5BB0059AA1A /* MeetingListView.swift */; }; 50 | 84C089DF27F5D6D60059AA1A /* ButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C089DE27F5D6D60059AA1A /* ButtonView.swift */; }; 51 | 84C089E127F5DA5C0059AA1A /* MeetingDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C089E027F5DA5C0059AA1A /* MeetingDetailView.swift */; }; 52 | 84C089E327F5DB120059AA1A /* CommonText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C089E227F5DB120059AA1A /* CommonText.swift */; }; 53 | 84E87CA027F86F1B006E46AF /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E87C9F27F86F1B006E46AF /* User.swift */; }; 54 | 84E87CA227F86FD3006E46AF /* UserAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E87CA127F86FD3006E46AF /* UserAPI.swift */; }; 55 | 84E87CA427F86FFE006E46AF /* UserVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E87CA327F86FFE006E46AF /* UserVM.swift */; }; 56 | 84E87CA627F870A0006E46AF /* UserListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E87CA527F870A0006E46AF /* UserListView.swift */; }; 57 | /* End PBXBuildFile section */ 58 | 59 | /* Begin PBXFileReference section */ 60 | 844B4BAC27F594A900D329F2 /* ZYSwiftUIFrame.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ZYSwiftUIFrame.app; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | 844B4BAF27F594A900D329F2 /* ZYSwiftUIFrameApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZYSwiftUIFrameApp.swift; sourceTree = ""; }; 62 | 844B4BB127F594A900D329F2 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 63 | 844B4BB327F594AB00D329F2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 64 | 844B4BB627F594AB00D329F2 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 65 | 844B4BBF27F5986600D329F2 /* NetworkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = ""; }; 66 | 844B4BC427F599C600D329F2 /* BaseApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseApi.swift; sourceTree = ""; }; 67 | 847443C327F8937500E92F16 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = ""; }; 68 | 847E0CB327F8793D00CA64E0 /* UserDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDetailView.swift; sourceTree = ""; }; 69 | 848A975F27F82BF500B6DC03 /* UploadApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadApi.swift; sourceTree = ""; }; 70 | 848A976227F82C5100B6DC03 /* Upload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Upload.swift; sourceTree = ""; }; 71 | 848A976827F82E5C00B6DC03 /* MultipleImagePickView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultipleImagePickView.swift; sourceTree = ""; }; 72 | 848A976A27F82E6F00B6DC03 /* ImagePickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePickerView.swift; sourceTree = ""; }; 73 | 848A976C27F8302B00B6DC03 /* ImageShowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageShowView.swift; sourceTree = ""; }; 74 | 848A976E27F830B900B6DC03 /* ImageUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageUtil.swift; sourceTree = ""; }; 75 | 84ACD9CB27F59A5300C9C5C8 /* CommonApiObj.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonApiObj.swift; sourceTree = ""; }; 76 | 84ACD9CD27F59ACB00C9C5C8 /* CommonVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonVM.swift; sourceTree = ""; }; 77 | 84ACD9D027F59B2100C9C5C8 /* ZYRefreshView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZYRefreshView.swift; sourceTree = ""; }; 78 | 84ACD9D527F59B7F00C9C5C8 /* ZYListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZYListView.swift; sourceTree = ""; }; 79 | 84ACD9D727F59D6800C9C5C8 /* ZYNavBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZYNavBarView.swift; sourceTree = ""; }; 80 | 84ACD9D927F59DBB00C9C5C8 /* ServerResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerResponse.swift; sourceTree = ""; }; 81 | 84ACD9DC27F59E1E00C9C5C8 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 82 | 84ACD9DE27F59E8500C9C5C8 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 83 | 84ACD9E127F5A31000C9C5C8 /* Meeting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Meeting.swift; sourceTree = ""; }; 84 | 84ACD9E427F5A35000C9C5C8 /* Message.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = ""; }; 85 | 84ACD9E627F5A39D00C9C5C8 /* CodableDefault.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableDefault.swift; sourceTree = ""; }; 86 | 84ACD9E827F5A3F500C9C5C8 /* MessageAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageAPI.swift; sourceTree = ""; }; 87 | 84ACD9EA27F5A44400C9C5C8 /* MessageVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageVM.swift; sourceTree = ""; }; 88 | 84ACD9EC27F5A4C800C9C5C8 /* MessageListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageListView.swift; sourceTree = ""; }; 89 | 84ACD9EE27F5B78500C9C5C8 /* MessageDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageDetailView.swift; sourceTree = ""; }; 90 | 84B82AB927FB32380053C29B /* MapDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapDemo.swift; sourceTree = ""; }; 91 | 84B82ABB27FB33510053C29B /* MapNavigation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapNavigation.swift; sourceTree = ""; }; 92 | 84B82ABD27FB34080053C29B /* LocationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationViewModel.swift; sourceTree = ""; }; 93 | 84B82AC127FB402D0053C29B /* NotificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationView.swift; sourceTree = ""; }; 94 | 84C089D827F5D52F0059AA1A /* MeetingAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingAPI.swift; sourceTree = ""; }; 95 | 84C089DA27F5D55A0059AA1A /* MeetingVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingVM.swift; sourceTree = ""; }; 96 | 84C089DC27F5D5BB0059AA1A /* MeetingListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingListView.swift; sourceTree = ""; }; 97 | 84C089DE27F5D6D60059AA1A /* ButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonView.swift; sourceTree = ""; }; 98 | 84C089E027F5DA5C0059AA1A /* MeetingDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingDetailView.swift; sourceTree = ""; }; 99 | 84C089E227F5DB120059AA1A /* CommonText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonText.swift; sourceTree = ""; }; 100 | 84E87C9F27F86F1B006E46AF /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; 101 | 84E87CA127F86FD3006E46AF /* UserAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAPI.swift; sourceTree = ""; }; 102 | 84E87CA327F86FFE006E46AF /* UserVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserVM.swift; sourceTree = ""; }; 103 | 84E87CA527F870A0006E46AF /* UserListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserListView.swift; sourceTree = ""; }; 104 | /* End PBXFileReference section */ 105 | 106 | /* Begin PBXFrameworksBuildPhase section */ 107 | 844B4BA927F594A900D329F2 /* Frameworks */ = { 108 | isa = PBXFrameworksBuildPhase; 109 | buildActionMask = 2147483647; 110 | files = ( 111 | 848A977927F858E700B6DC03 /* SDWebImageSwiftUI in Frameworks */, 112 | 844B4BC327F598DA00D329F2 /* Alamofire in Frameworks */, 113 | 84ACD9D427F59B3B00C9C5C8 /* BBSwiftUIKit in Frameworks */, 114 | 848A977327F8490A00B6DC03 /* ImageViewerRemote in Frameworks */, 115 | ); 116 | runOnlyForDeploymentPostprocessing = 0; 117 | }; 118 | /* End PBXFrameworksBuildPhase section */ 119 | 120 | /* Begin PBXGroup section */ 121 | 844B4BA327F594A900D329F2 = { 122 | isa = PBXGroup; 123 | children = ( 124 | 844B4BAE27F594A900D329F2 /* ZYSwiftUIFrame */, 125 | 844B4BAD27F594A900D329F2 /* Products */, 126 | ); 127 | sourceTree = ""; 128 | }; 129 | 844B4BAD27F594A900D329F2 /* Products */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 844B4BAC27F594A900D329F2 /* ZYSwiftUIFrame.app */, 133 | ); 134 | name = Products; 135 | sourceTree = ""; 136 | }; 137 | 844B4BAE27F594A900D329F2 /* ZYSwiftUIFrame */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | 84ACD9DB27F59DF300C9C5C8 /* Global */, 141 | 84ACD9CF27F59AF100C9C5C8 /* UIFrame */, 142 | 844B4BBE27F597D000D329F2 /* UI */, 143 | 844B4BBD27F5953F00D329F2 /* Api */, 144 | 844B4BB327F594AB00D329F2 /* Assets.xcassets */, 145 | 844B4BB527F594AB00D329F2 /* Preview Content */, 146 | ); 147 | path = ZYSwiftUIFrame; 148 | sourceTree = ""; 149 | }; 150 | 844B4BB527F594AB00D329F2 /* Preview Content */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 844B4BB627F594AB00D329F2 /* Preview Assets.xcassets */, 154 | ); 155 | path = "Preview Content"; 156 | sourceTree = ""; 157 | }; 158 | 844B4BBD27F5953F00D329F2 /* Api */ = { 159 | isa = PBXGroup; 160 | children = ( 161 | 844B4BBF27F5986600D329F2 /* NetworkManager.swift */, 162 | 844B4BC427F599C600D329F2 /* BaseApi.swift */, 163 | 84ACD9CB27F59A5300C9C5C8 /* CommonApiObj.swift */, 164 | 84ACD9CD27F59ACB00C9C5C8 /* CommonVM.swift */, 165 | 84ACD9D927F59DBB00C9C5C8 /* ServerResponse.swift */, 166 | 848A975F27F82BF500B6DC03 /* UploadApi.swift */, 167 | ); 168 | path = Api; 169 | sourceTree = ""; 170 | }; 171 | 844B4BBE27F597D000D329F2 /* UI */ = { 172 | isa = PBXGroup; 173 | children = ( 174 | 84E87C9E27F86BE5006E46AF /* User */, 175 | 848A976127F82C3700B6DC03 /* Upload */, 176 | 84ACD9E327F5A34700C9C5C8 /* Message */, 177 | 84ACD9E027F59EE600C9C5C8 /* Meeting */, 178 | 84B82AB827FB31FB0053C29B /* Map */, 179 | 84B82AC027FB401D0053C29B /* Notification */, 180 | 84B82ABF27FB40100053C29B /* About */, 181 | 844B4BAF27F594A900D329F2 /* ZYSwiftUIFrameApp.swift */, 182 | 844B4BB127F594A900D329F2 /* ContentView.swift */, 183 | ); 184 | path = UI; 185 | sourceTree = ""; 186 | }; 187 | 848A976127F82C3700B6DC03 /* Upload */ = { 188 | isa = PBXGroup; 189 | children = ( 190 | 848A976227F82C5100B6DC03 /* Upload.swift */, 191 | ); 192 | path = Upload; 193 | sourceTree = ""; 194 | }; 195 | 848A976427F82DD100B6DC03 /* ImagePick */ = { 196 | isa = PBXGroup; 197 | children = ( 198 | 848A976827F82E5C00B6DC03 /* MultipleImagePickView.swift */, 199 | 848A976A27F82E6F00B6DC03 /* ImagePickerView.swift */, 200 | ); 201 | path = ImagePick; 202 | sourceTree = ""; 203 | }; 204 | 848A976527F82DD800B6DC03 /* Refresh */ = { 205 | isa = PBXGroup; 206 | children = ( 207 | 84ACD9D027F59B2100C9C5C8 /* ZYRefreshView.swift */, 208 | 84ACD9D527F59B7F00C9C5C8 /* ZYListView.swift */, 209 | ); 210 | path = Refresh; 211 | sourceTree = ""; 212 | }; 213 | 848A976627F82DF800B6DC03 /* Common */ = { 214 | isa = PBXGroup; 215 | children = ( 216 | 84C089DE27F5D6D60059AA1A /* ButtonView.swift */, 217 | 84C089E227F5DB120059AA1A /* CommonText.swift */, 218 | 848A976C27F8302B00B6DC03 /* ImageShowView.swift */, 219 | ); 220 | path = Common; 221 | sourceTree = ""; 222 | }; 223 | 848A976727F82E0900B6DC03 /* Enhance */ = { 224 | isa = PBXGroup; 225 | children = ( 226 | 84ACD9DE27F59E8500C9C5C8 /* Extensions.swift */, 227 | 84ACD9E627F5A39D00C9C5C8 /* CodableDefault.swift */, 228 | ); 229 | path = Enhance; 230 | sourceTree = ""; 231 | }; 232 | 84ACD9CF27F59AF100C9C5C8 /* UIFrame */ = { 233 | isa = PBXGroup; 234 | children = ( 235 | 848A976727F82E0900B6DC03 /* Enhance */, 236 | 848A976527F82DD800B6DC03 /* Refresh */, 237 | 848A976427F82DD100B6DC03 /* ImagePick */, 238 | 848A976627F82DF800B6DC03 /* Common */, 239 | 84ACD9D727F59D6800C9C5C8 /* ZYNavBarView.swift */, 240 | ); 241 | path = UIFrame; 242 | sourceTree = ""; 243 | }; 244 | 84ACD9DB27F59DF300C9C5C8 /* Global */ = { 245 | isa = PBXGroup; 246 | children = ( 247 | 84ACD9DC27F59E1E00C9C5C8 /* Constants.swift */, 248 | 848A976E27F830B900B6DC03 /* ImageUtil.swift */, 249 | ); 250 | path = Global; 251 | sourceTree = ""; 252 | }; 253 | 84ACD9E027F59EE600C9C5C8 /* Meeting */ = { 254 | isa = PBXGroup; 255 | children = ( 256 | 84ACD9E127F5A31000C9C5C8 /* Meeting.swift */, 257 | 84C089D827F5D52F0059AA1A /* MeetingAPI.swift */, 258 | 84C089DA27F5D55A0059AA1A /* MeetingVM.swift */, 259 | 84C089DC27F5D5BB0059AA1A /* MeetingListView.swift */, 260 | 84C089E027F5DA5C0059AA1A /* MeetingDetailView.swift */, 261 | ); 262 | path = Meeting; 263 | sourceTree = ""; 264 | }; 265 | 84ACD9E327F5A34700C9C5C8 /* Message */ = { 266 | isa = PBXGroup; 267 | children = ( 268 | 84ACD9E427F5A35000C9C5C8 /* Message.swift */, 269 | 84ACD9E827F5A3F500C9C5C8 /* MessageAPI.swift */, 270 | 84ACD9EA27F5A44400C9C5C8 /* MessageVM.swift */, 271 | 84ACD9EC27F5A4C800C9C5C8 /* MessageListView.swift */, 272 | 84ACD9EE27F5B78500C9C5C8 /* MessageDetailView.swift */, 273 | ); 274 | path = Message; 275 | sourceTree = ""; 276 | }; 277 | 84B82AB827FB31FB0053C29B /* Map */ = { 278 | isa = PBXGroup; 279 | children = ( 280 | 84B82AB927FB32380053C29B /* MapDemo.swift */, 281 | 84B82ABB27FB33510053C29B /* MapNavigation.swift */, 282 | 84B82ABD27FB34080053C29B /* LocationViewModel.swift */, 283 | ); 284 | path = Map; 285 | sourceTree = ""; 286 | }; 287 | 84B82ABF27FB40100053C29B /* About */ = { 288 | isa = PBXGroup; 289 | children = ( 290 | 847443C327F8937500E92F16 /* AboutView.swift */, 291 | ); 292 | path = About; 293 | sourceTree = ""; 294 | }; 295 | 84B82AC027FB401D0053C29B /* Notification */ = { 296 | isa = PBXGroup; 297 | children = ( 298 | 84B82AC127FB402D0053C29B /* NotificationView.swift */, 299 | ); 300 | path = Notification; 301 | sourceTree = ""; 302 | }; 303 | 84E87C9E27F86BE5006E46AF /* User */ = { 304 | isa = PBXGroup; 305 | children = ( 306 | 84E87C9F27F86F1B006E46AF /* User.swift */, 307 | 84E87CA127F86FD3006E46AF /* UserAPI.swift */, 308 | 84E87CA327F86FFE006E46AF /* UserVM.swift */, 309 | 84E87CA527F870A0006E46AF /* UserListView.swift */, 310 | 847E0CB327F8793D00CA64E0 /* UserDetailView.swift */, 311 | ); 312 | path = User; 313 | sourceTree = ""; 314 | }; 315 | /* End PBXGroup section */ 316 | 317 | /* Begin PBXNativeTarget section */ 318 | 844B4BAB27F594A900D329F2 /* ZYSwiftUIFrame */ = { 319 | isa = PBXNativeTarget; 320 | buildConfigurationList = 844B4BBA27F594AB00D329F2 /* Build configuration list for PBXNativeTarget "ZYSwiftUIFrame" */; 321 | buildPhases = ( 322 | 844B4BA827F594A900D329F2 /* Sources */, 323 | 844B4BA927F594A900D329F2 /* Frameworks */, 324 | 844B4BAA27F594A900D329F2 /* Resources */, 325 | ); 326 | buildRules = ( 327 | ); 328 | dependencies = ( 329 | ); 330 | name = ZYSwiftUIFrame; 331 | packageProductDependencies = ( 332 | 844B4BC227F598DA00D329F2 /* Alamofire */, 333 | 84ACD9D327F59B3B00C9C5C8 /* BBSwiftUIKit */, 334 | 848A977227F8490A00B6DC03 /* ImageViewerRemote */, 335 | 848A977827F858E700B6DC03 /* SDWebImageSwiftUI */, 336 | ); 337 | productName = ZYSwiftUIFrame; 338 | productReference = 844B4BAC27F594A900D329F2 /* ZYSwiftUIFrame.app */; 339 | productType = "com.apple.product-type.application"; 340 | }; 341 | /* End PBXNativeTarget section */ 342 | 343 | /* Begin PBXProject section */ 344 | 844B4BA427F594A900D329F2 /* Project object */ = { 345 | isa = PBXProject; 346 | attributes = { 347 | BuildIndependentTargetsInParallel = 1; 348 | LastSwiftUpdateCheck = 1310; 349 | LastUpgradeCheck = 1310; 350 | TargetAttributes = { 351 | 844B4BAB27F594A900D329F2 = { 352 | CreatedOnToolsVersion = 13.1; 353 | }; 354 | }; 355 | }; 356 | buildConfigurationList = 844B4BA727F594A900D329F2 /* Build configuration list for PBXProject "ZYSwiftUIFrame" */; 357 | compatibilityVersion = "Xcode 13.0"; 358 | developmentRegion = en; 359 | hasScannedForEncodings = 0; 360 | knownRegions = ( 361 | en, 362 | Base, 363 | ); 364 | mainGroup = 844B4BA327F594A900D329F2; 365 | packageReferences = ( 366 | 844B4BC127F598DA00D329F2 /* XCRemoteSwiftPackageReference "Alamofire" */, 367 | 84ACD9D227F59B3B00C9C5C8 /* XCRemoteSwiftPackageReference "BBSwiftUIKit" */, 368 | 848A977127F8490A00B6DC03 /* XCRemoteSwiftPackageReference "swiftui-image-viewer" */, 369 | 848A977727F858E700B6DC03 /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */, 370 | ); 371 | productRefGroup = 844B4BAD27F594A900D329F2 /* Products */; 372 | projectDirPath = ""; 373 | projectRoot = ""; 374 | targets = ( 375 | 844B4BAB27F594A900D329F2 /* ZYSwiftUIFrame */, 376 | ); 377 | }; 378 | /* End PBXProject section */ 379 | 380 | /* Begin PBXResourcesBuildPhase section */ 381 | 844B4BAA27F594A900D329F2 /* Resources */ = { 382 | isa = PBXResourcesBuildPhase; 383 | buildActionMask = 2147483647; 384 | files = ( 385 | 844B4BB727F594AB00D329F2 /* Preview Assets.xcassets in Resources */, 386 | 844B4BB427F594AB00D329F2 /* Assets.xcassets in Resources */, 387 | ); 388 | runOnlyForDeploymentPostprocessing = 0; 389 | }; 390 | /* End PBXResourcesBuildPhase section */ 391 | 392 | /* Begin PBXSourcesBuildPhase section */ 393 | 844B4BA827F594A900D329F2 /* Sources */ = { 394 | isa = PBXSourcesBuildPhase; 395 | buildActionMask = 2147483647; 396 | files = ( 397 | 84ACD9E727F5A39D00C9C5C8 /* CodableDefault.swift in Sources */, 398 | 844B4BC027F5986600D329F2 /* NetworkManager.swift in Sources */, 399 | 84E87CA227F86FD3006E46AF /* UserAPI.swift in Sources */, 400 | 84ACD9EF27F5B78500C9C5C8 /* MessageDetailView.swift in Sources */, 401 | 847E0CB427F8793D00CA64E0 /* UserDetailView.swift in Sources */, 402 | 84ACD9DD27F59E1E00C9C5C8 /* Constants.swift in Sources */, 403 | 84E87CA027F86F1B006E46AF /* User.swift in Sources */, 404 | 84ACD9EB27F5A44400C9C5C8 /* MessageVM.swift in Sources */, 405 | 84B82AC227FB402D0053C29B /* NotificationView.swift in Sources */, 406 | 84B82ABC27FB33510053C29B /* MapNavigation.swift in Sources */, 407 | 84ACD9ED27F5A4C800C9C5C8 /* MessageListView.swift in Sources */, 408 | 84C089DF27F5D6D60059AA1A /* ButtonView.swift in Sources */, 409 | 84C089D927F5D52F0059AA1A /* MeetingAPI.swift in Sources */, 410 | 84ACD9E227F5A31000C9C5C8 /* Meeting.swift in Sources */, 411 | 848A976327F82C5100B6DC03 /* Upload.swift in Sources */, 412 | 84B82ABA27FB32380053C29B /* MapDemo.swift in Sources */, 413 | 84ACD9D127F59B2100C9C5C8 /* ZYRefreshView.swift in Sources */, 414 | 84ACD9CE27F59ACB00C9C5C8 /* CommonVM.swift in Sources */, 415 | 847443C427F8937500E92F16 /* AboutView.swift in Sources */, 416 | 844B4BC527F599C600D329F2 /* BaseApi.swift in Sources */, 417 | 84E87CA427F86FFE006E46AF /* UserVM.swift in Sources */, 418 | 84ACD9CC27F59A5300C9C5C8 /* CommonApiObj.swift in Sources */, 419 | 84ACD9D627F59B7F00C9C5C8 /* ZYListView.swift in Sources */, 420 | 84ACD9DF27F59E8500C9C5C8 /* Extensions.swift in Sources */, 421 | 84B82ABE27FB34080053C29B /* LocationViewModel.swift in Sources */, 422 | 84C089DD27F5D5BB0059AA1A /* MeetingListView.swift in Sources */, 423 | 84ACD9E927F5A3F500C9C5C8 /* MessageAPI.swift in Sources */, 424 | 84E87CA627F870A0006E46AF /* UserListView.swift in Sources */, 425 | 84C089E127F5DA5C0059AA1A /* MeetingDetailView.swift in Sources */, 426 | 844B4BB227F594A900D329F2 /* ContentView.swift in Sources */, 427 | 84C089DB27F5D55A0059AA1A /* MeetingVM.swift in Sources */, 428 | 84C089E327F5DB120059AA1A /* CommonText.swift in Sources */, 429 | 844B4BB027F594A900D329F2 /* ZYSwiftUIFrameApp.swift in Sources */, 430 | 848A976D27F8302B00B6DC03 /* ImageShowView.swift in Sources */, 431 | 848A976B27F82E6F00B6DC03 /* ImagePickerView.swift in Sources */, 432 | 848A976F27F830B900B6DC03 /* ImageUtil.swift in Sources */, 433 | 84ACD9D827F59D6800C9C5C8 /* ZYNavBarView.swift in Sources */, 434 | 84ACD9DA27F59DBB00C9C5C8 /* ServerResponse.swift in Sources */, 435 | 84ACD9E527F5A35000C9C5C8 /* Message.swift in Sources */, 436 | 848A976027F82BF500B6DC03 /* UploadApi.swift in Sources */, 437 | 848A976927F82E5C00B6DC03 /* MultipleImagePickView.swift in Sources */, 438 | ); 439 | runOnlyForDeploymentPostprocessing = 0; 440 | }; 441 | /* End PBXSourcesBuildPhase section */ 442 | 443 | /* Begin XCBuildConfiguration section */ 444 | 844B4BB827F594AB00D329F2 /* Debug */ = { 445 | isa = XCBuildConfiguration; 446 | buildSettings = { 447 | ALWAYS_SEARCH_USER_PATHS = NO; 448 | CLANG_ANALYZER_NONNULL = YES; 449 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 450 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 451 | CLANG_CXX_LIBRARY = "libc++"; 452 | CLANG_ENABLE_MODULES = YES; 453 | CLANG_ENABLE_OBJC_ARC = YES; 454 | CLANG_ENABLE_OBJC_WEAK = YES; 455 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 456 | CLANG_WARN_BOOL_CONVERSION = YES; 457 | CLANG_WARN_COMMA = YES; 458 | CLANG_WARN_CONSTANT_CONVERSION = YES; 459 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 460 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 461 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 462 | CLANG_WARN_EMPTY_BODY = YES; 463 | CLANG_WARN_ENUM_CONVERSION = YES; 464 | CLANG_WARN_INFINITE_RECURSION = YES; 465 | CLANG_WARN_INT_CONVERSION = YES; 466 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 467 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 468 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 469 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 470 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 471 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 472 | CLANG_WARN_STRICT_PROTOTYPES = YES; 473 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 474 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 475 | CLANG_WARN_UNREACHABLE_CODE = YES; 476 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 477 | COPY_PHASE_STRIP = NO; 478 | DEBUG_INFORMATION_FORMAT = dwarf; 479 | ENABLE_STRICT_OBJC_MSGSEND = YES; 480 | ENABLE_TESTABILITY = YES; 481 | GCC_C_LANGUAGE_STANDARD = gnu11; 482 | GCC_DYNAMIC_NO_PIC = NO; 483 | GCC_NO_COMMON_BLOCKS = YES; 484 | GCC_OPTIMIZATION_LEVEL = 0; 485 | GCC_PREPROCESSOR_DEFINITIONS = ( 486 | "DEBUG=1", 487 | "$(inherited)", 488 | ); 489 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 490 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 491 | GCC_WARN_UNDECLARED_SELECTOR = YES; 492 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 493 | GCC_WARN_UNUSED_FUNCTION = YES; 494 | GCC_WARN_UNUSED_VARIABLE = YES; 495 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 496 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 497 | MTL_FAST_MATH = YES; 498 | ONLY_ACTIVE_ARCH = YES; 499 | SDKROOT = iphoneos; 500 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 501 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 502 | }; 503 | name = Debug; 504 | }; 505 | 844B4BB927F594AB00D329F2 /* Release */ = { 506 | isa = XCBuildConfiguration; 507 | buildSettings = { 508 | ALWAYS_SEARCH_USER_PATHS = NO; 509 | CLANG_ANALYZER_NONNULL = YES; 510 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 511 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 512 | CLANG_CXX_LIBRARY = "libc++"; 513 | CLANG_ENABLE_MODULES = YES; 514 | CLANG_ENABLE_OBJC_ARC = YES; 515 | CLANG_ENABLE_OBJC_WEAK = YES; 516 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 517 | CLANG_WARN_BOOL_CONVERSION = YES; 518 | CLANG_WARN_COMMA = YES; 519 | CLANG_WARN_CONSTANT_CONVERSION = YES; 520 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 521 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 522 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 523 | CLANG_WARN_EMPTY_BODY = YES; 524 | CLANG_WARN_ENUM_CONVERSION = YES; 525 | CLANG_WARN_INFINITE_RECURSION = YES; 526 | CLANG_WARN_INT_CONVERSION = YES; 527 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 528 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 529 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 530 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 531 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 532 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 533 | CLANG_WARN_STRICT_PROTOTYPES = YES; 534 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 535 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 536 | CLANG_WARN_UNREACHABLE_CODE = YES; 537 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 538 | COPY_PHASE_STRIP = NO; 539 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 540 | ENABLE_NS_ASSERTIONS = NO; 541 | ENABLE_STRICT_OBJC_MSGSEND = YES; 542 | GCC_C_LANGUAGE_STANDARD = gnu11; 543 | GCC_NO_COMMON_BLOCKS = YES; 544 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 545 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 546 | GCC_WARN_UNDECLARED_SELECTOR = YES; 547 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 548 | GCC_WARN_UNUSED_FUNCTION = YES; 549 | GCC_WARN_UNUSED_VARIABLE = YES; 550 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 551 | MTL_ENABLE_DEBUG_INFO = NO; 552 | MTL_FAST_MATH = YES; 553 | SDKROOT = iphoneos; 554 | SWIFT_COMPILATION_MODE = wholemodule; 555 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 556 | VALIDATE_PRODUCT = YES; 557 | }; 558 | name = Release; 559 | }; 560 | 844B4BBB27F594AB00D329F2 /* Debug */ = { 561 | isa = XCBuildConfiguration; 562 | buildSettings = { 563 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 564 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 565 | CODE_SIGN_STYLE = Automatic; 566 | CURRENT_PROJECT_VERSION = 1; 567 | DEVELOPMENT_ASSET_PATHS = "\"ZYSwiftUIFrame/Preview Content\""; 568 | DEVELOPMENT_TEAM = BT34MG3U8S; 569 | ENABLE_PREVIEWS = YES; 570 | GENERATE_INFOPLIST_FILE = YES; 571 | INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "请允许获取地理位置的权限"; 572 | INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "请允许获取地理位置的权限"; 573 | INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "请允许使用相册的权限"; 574 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 575 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 576 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 577 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 578 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 579 | LD_RUNPATH_SEARCH_PATHS = ( 580 | "$(inherited)", 581 | "@executable_path/Frameworks", 582 | ); 583 | MARKETING_VERSION = 1.0; 584 | PRODUCT_BUNDLE_IDENTIFIER = cn.yusael.ZYSwiftUIFrame; 585 | PRODUCT_NAME = "$(TARGET_NAME)"; 586 | SWIFT_EMIT_LOC_STRINGS = YES; 587 | SWIFT_VERSION = 5.0; 588 | TARGETED_DEVICE_FAMILY = 1; 589 | }; 590 | name = Debug; 591 | }; 592 | 844B4BBC27F594AB00D329F2 /* Release */ = { 593 | isa = XCBuildConfiguration; 594 | buildSettings = { 595 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 596 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 597 | CODE_SIGN_STYLE = Automatic; 598 | CURRENT_PROJECT_VERSION = 1; 599 | DEVELOPMENT_ASSET_PATHS = "\"ZYSwiftUIFrame/Preview Content\""; 600 | DEVELOPMENT_TEAM = BT34MG3U8S; 601 | ENABLE_PREVIEWS = YES; 602 | GENERATE_INFOPLIST_FILE = YES; 603 | INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "请允许获取地理位置的权限"; 604 | INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "请允许获取地理位置的权限"; 605 | INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "请允许使用相册的权限"; 606 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 607 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 608 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 609 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 610 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 611 | LD_RUNPATH_SEARCH_PATHS = ( 612 | "$(inherited)", 613 | "@executable_path/Frameworks", 614 | ); 615 | MARKETING_VERSION = 1.0; 616 | PRODUCT_BUNDLE_IDENTIFIER = cn.yusael.ZYSwiftUIFrame; 617 | PRODUCT_NAME = "$(TARGET_NAME)"; 618 | SWIFT_EMIT_LOC_STRINGS = YES; 619 | SWIFT_VERSION = 5.0; 620 | TARGETED_DEVICE_FAMILY = 1; 621 | }; 622 | name = Release; 623 | }; 624 | /* End XCBuildConfiguration section */ 625 | 626 | /* Begin XCConfigurationList section */ 627 | 844B4BA727F594A900D329F2 /* Build configuration list for PBXProject "ZYSwiftUIFrame" */ = { 628 | isa = XCConfigurationList; 629 | buildConfigurations = ( 630 | 844B4BB827F594AB00D329F2 /* Debug */, 631 | 844B4BB927F594AB00D329F2 /* Release */, 632 | ); 633 | defaultConfigurationIsVisible = 0; 634 | defaultConfigurationName = Release; 635 | }; 636 | 844B4BBA27F594AB00D329F2 /* Build configuration list for PBXNativeTarget "ZYSwiftUIFrame" */ = { 637 | isa = XCConfigurationList; 638 | buildConfigurations = ( 639 | 844B4BBB27F594AB00D329F2 /* Debug */, 640 | 844B4BBC27F594AB00D329F2 /* Release */, 641 | ); 642 | defaultConfigurationIsVisible = 0; 643 | defaultConfigurationName = Release; 644 | }; 645 | /* End XCConfigurationList section */ 646 | 647 | /* Begin XCRemoteSwiftPackageReference section */ 648 | 844B4BC127F598DA00D329F2 /* XCRemoteSwiftPackageReference "Alamofire" */ = { 649 | isa = XCRemoteSwiftPackageReference; 650 | repositoryURL = "https://gitee.com/idoing/Alamofire.git"; 651 | requirement = { 652 | kind = upToNextMajorVersion; 653 | minimumVersion = 5.0.0; 654 | }; 655 | }; 656 | 848A977127F8490A00B6DC03 /* XCRemoteSwiftPackageReference "swiftui-image-viewer" */ = { 657 | isa = XCRemoteSwiftPackageReference; 658 | repositoryURL = "https://gitee.com/wei_wen_yue/swiftui-image-viewer"; 659 | requirement = { 660 | branch = master; 661 | kind = branch; 662 | }; 663 | }; 664 | 848A977727F858E700B6DC03 /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */ = { 665 | isa = XCRemoteSwiftPackageReference; 666 | repositoryURL = "https://gitee.com/szluyu99/SDWebImageSwiftUI.git"; 667 | requirement = { 668 | branch = master; 669 | kind = branch; 670 | }; 671 | }; 672 | 84ACD9D227F59B3B00C9C5C8 /* XCRemoteSwiftPackageReference "BBSwiftUIKit" */ = { 673 | isa = XCRemoteSwiftPackageReference; 674 | repositoryURL = "https://gitee.com/RDCenter/BBSwiftUIKit.git"; 675 | requirement = { 676 | branch = master; 677 | kind = branch; 678 | }; 679 | }; 680 | /* End XCRemoteSwiftPackageReference section */ 681 | 682 | /* Begin XCSwiftPackageProductDependency section */ 683 | 844B4BC227F598DA00D329F2 /* Alamofire */ = { 684 | isa = XCSwiftPackageProductDependency; 685 | package = 844B4BC127F598DA00D329F2 /* XCRemoteSwiftPackageReference "Alamofire" */; 686 | productName = Alamofire; 687 | }; 688 | 848A977227F8490A00B6DC03 /* ImageViewerRemote */ = { 689 | isa = XCSwiftPackageProductDependency; 690 | package = 848A977127F8490A00B6DC03 /* XCRemoteSwiftPackageReference "swiftui-image-viewer" */; 691 | productName = ImageViewerRemote; 692 | }; 693 | 848A977827F858E700B6DC03 /* SDWebImageSwiftUI */ = { 694 | isa = XCSwiftPackageProductDependency; 695 | package = 848A977727F858E700B6DC03 /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */; 696 | productName = SDWebImageSwiftUI; 697 | }; 698 | 84ACD9D327F59B3B00C9C5C8 /* BBSwiftUIKit */ = { 699 | isa = XCSwiftPackageProductDependency; 700 | package = 84ACD9D227F59B3B00C9C5C8 /* XCRemoteSwiftPackageReference "BBSwiftUIKit" */; 701 | productName = BBSwiftUIKit; 702 | }; 703 | /* End XCSwiftPackageProductDependency section */ 704 | }; 705 | rootObject = 844B4BA427F594A900D329F2 /* Project object */; 706 | } 707 | --------------------------------------------------------------------------------