├── .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 | 
46 |
47 | ### 1. 不需要开启服务端
48 |
49 | 不需要开启服务端,功能是下面 “需要开启服务端” 功能的简化版,仅用于本地演示,并且不涉及到数据请求。
50 |
51 | #### 1.1 用户列表
52 |
53 | 下拉刷新、上拉加载更多:
54 |
55 | 
56 |
57 | 新增、删除、修改:
58 |
59 | 
60 |
61 |
62 | 帮助、搜索:
63 |
64 | 
65 |
66 | ### 2. 需要开启服务端
67 |
68 | 开启服务端的数据,模拟真实的请求后台,实现对数据库的操作。
69 |
70 | #### 2.1 消息列表
71 |
72 | 上拉、下拉、删除:
73 |
74 | 
75 |
76 |
77 |
78 | #### 2.2 会议列表
79 |
80 | 显示帮助、删除、下拉刷新、搜索:
81 |
82 | 
83 |
84 | 更新、新增:
85 |
86 | 
87 |
88 | 图片上传、预览、删除、保存:
89 |
90 | 
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 | 
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 |
--------------------------------------------------------------------------------