实现权限驱动的首页 Tab 并对齐 Android

This commit is contained in:
2026-07-06 17:27:54 +08:00
parent e04ad8f8f0
commit d79d3003e3
27 changed files with 2573 additions and 10 deletions
@@ -0,0 +1,28 @@
//
// HomeMenuItem.swift
// suixinkan
//
import Foundation
/// 首页菜单展示项,由服务端权限 URI 与本地 catalog 合并而成。
struct HomeMenuItem: Equatable, Hashable, Sendable {
let uri: String
let title: String
let iconName: String
let serverName: String
init(uri: String, title: String, iconName: String, serverName: String = "") {
self.uri = uri
self.title = title
self.iconName = iconName
self.serverName = serverName
}
/// 固定的「更多功能」入口。
static let moreFunctions = HomeMenuItem(
uri: "more_functions",
title: "更多功能",
iconName: "square.grid.2x2"
)
}
@@ -0,0 +1,38 @@
//
// LocationModels.swift
// suixinkan
//
import Foundation
/// 位置上报详情,对齐 Android `LocationDetailResponse`。
struct LocationDetailResponse: Decodable, Sendable {
let status: Int
let needReport: Bool
let expireTime: Int64
enum CodingKeys: String, CodingKey {
case status
case needReport = "need_report"
case expireTime = "expire_time"
}
init(status: Int = 0, needReport: Bool = true, expireTime: Int64 = 0) {
self.status = status
self.needReport = needReport
self.expireTime = expireTime
}
}
/// 位置上报结果,对齐 Android `LocationReportResponse`。
struct LocationReportResponse: Decodable, Sendable {
let staffId: String
let expired: Int64
let status: Int
enum CodingKeys: String, CodingKey {
case staffId = "staff_id"
case expired
case status
}
}
@@ -0,0 +1,143 @@
//
// RolePermissionModels.swift
// suixinkan
//
import Foundation
/// 角色权限接口根节点,对齐 Android `RolePermissionResponse`。
struct RolePermissionResponse: Codable, Equatable, Sendable {
let role: RoleInfo
let scenic: [ScenicInfo]
init(role: RoleInfo, scenic: [ScenicInfo] = []) {
self.role = role
self.scenic = scenic
}
}
/// 角色信息与顶层权限列表。
struct RoleInfo: Codable, Equatable, Sendable {
let id: Int
let name: String
let roleCode: String
let notes: String?
let permission: [PermissionItem]
enum CodingKeys: String, CodingKey {
case id
case name
case roleCode = "role_code"
case notes
case permission
}
init(
id: Int = 0,
name: String = "",
roleCode: String = "",
notes: String? = nil,
permission: [PermissionItem] = []
) {
self.id = id
self.name = name
self.roleCode = roleCode
self.notes = notes
self.permission = permission
}
}
/// 权限树节点。
struct PermissionItem: Codable, Equatable, Sendable {
let id: Int
let pid: Int
let name: String
let uri: String
let iconSrc: String?
let children: [PermissionItem]?
enum CodingKeys: String, CodingKey {
case id
case pid
case name
case uri
case iconSrc = "icon_src"
case children
}
init(
id: Int = 0,
pid: Int = 0,
name: String = "",
uri: String = "",
iconSrc: String? = nil,
children: [PermissionItem]? = nil
) {
self.id = id
self.pid = pid
self.name = name
self.uri = uri
self.iconSrc = iconSrc
self.children = children
}
}
/// 角色绑定的景区信息。
struct ScenicInfo: Codable, Equatable, Sendable, Hashable {
let id: Int
let name: String
let status: Int
let location: ScenicLocationInfo?
let coverImg: String?
enum CodingKeys: String, CodingKey {
case id
case name
case status
case location
case coverImg = "cover_img"
}
init(
id: Int = 0,
name: String = "",
status: Int = 0,
location: ScenicLocationInfo? = nil,
coverImg: String? = nil
) {
self.id = id
self.name = name
self.status = status
self.location = location
self.coverImg = coverImg
}
}
/// 景区位置信息。
struct ScenicLocationInfo: Codable, Equatable, Sendable, Hashable {
let lng: Double
let lat: Double
let address: String
}
/// 扁平化后的权限项,供首页菜单与本地缓存使用。
struct HomePermissionItem: Codable, Equatable, Sendable, Hashable {
let id: String
let name: String
let uri: String
let pid: Int
init(id: String, name: String, uri: String, pid: Int = 0) {
self.id = id
self.name = name
self.uri = uri
self.pid = pid
}
init(from item: PermissionItem) {
self.id = String(item.id)
self.name = item.name
self.uri = item.uri
self.pid = item.pid
}
}
@@ -0,0 +1,52 @@
//
// StoreModels.swift
// suixinkan
//
import Foundation
/// 门店列表项,对齐 Android `StoreItem`。
struct StoreItem: Codable, Equatable, Sendable {
let id: Int
let scenicId: Int
let name: String
let address: String
let status: Int
let statusText: String
enum CodingKeys: String, CodingKey {
case id
case scenicId = "scenic_id"
case name
case address
case status
case statusText = "status_text"
}
init(
id: Int = 0,
scenicId: Int = 0,
name: String = "",
address: String = "",
status: Int = 0,
statusText: String = ""
) {
self.id = id
self.scenicId = scenicId
self.name = name
self.address = address
self.status = status
self.statusText = statusText
}
}
/// 门店列表响应,对齐 Android `ListResponse<StoreItem>`。
struct StoreListResponse: Codable, Sendable {
let total: Int
let list: [StoreItem]
init(total: Int = 0, list: [StoreItem] = []) {
self.total = total
self.list = list
}
}