Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6a0f0a4ce | ||
|
|
8a8a914a8c | ||
|
|
ee498064cc | ||
|
|
6337454956 | ||
|
|
2c2f307247 | ||
|
|
6f9f903ca1 | ||
|
|
1bfe617cab | ||
|
|
a47d1a56fa | ||
|
|
d0ff8c2c19 | ||
|
|
b69578aa4a | ||
|
|
c7925e3189 | ||
|
|
82a432f77a | ||
|
|
c5b5149bb1 | ||
|
|
823063653b | ||
|
|
aa34d4623e |
@@ -0,0 +1,196 @@
|
|||||||
|
# Agent 行为准则 & XinjiangProject iOS 开发规范
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、Agent 行为准则
|
||||||
|
|
||||||
|
### 0. 语言强制
|
||||||
|
- 强制使用简体中文进行所有交互(代码除外)。
|
||||||
|
|
||||||
|
### 1. 抽象设计确认
|
||||||
|
- 涉及抽象设计、架构调整或新功能模块时,必须先用文字或 Mermaid 图对齐设计思路。
|
||||||
|
- 必须等待用户确认方案后,才能开始编写代码。
|
||||||
|
|
||||||
|
### 2. 任务清单确认
|
||||||
|
- 执行任何实质性任务前,必须先列出详细的任务清单。
|
||||||
|
- 必须等待用户明确回复(如"好的"、"开始")后,才能进入执行阶段。
|
||||||
|
|
||||||
|
### 3. 分步执行与确认
|
||||||
|
- 代码量较大或逻辑复杂的任务,禁止一次性完成。
|
||||||
|
- 拆分为多个步骤,每步完成后汇报进度并询问"是否可以进行下一步?"。
|
||||||
|
|
||||||
|
### 4. 所有修改必须确认
|
||||||
|
- 对代码库的任何修改(新建文件、修改文件、删除文件、执行 pod install 等)前,必须先描述变更内容。
|
||||||
|
- 必须等待用户明确回复"确认"或"同意"后,才能执行。
|
||||||
|
|
||||||
|
### 9. 代码注释语言规范
|
||||||
|
- 所有注释使用简体中文。
|
||||||
|
- 标识符(变量名、函数名、类名)仍使用英文。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、项目技术规范
|
||||||
|
|
||||||
|
### 技术栈
|
||||||
|
- **主语言**: Objective-C
|
||||||
|
- **混编**: 允许 OC/Swift 混编,OC 为主。引入 Swift 文件前**必须征得用户确认**。
|
||||||
|
- **UI 框架**: UIKit
|
||||||
|
- **架构模式**: MVC + Manager 层
|
||||||
|
- **包管理**: CocoaPods,使用 `.xcworkspace` 打开项目
|
||||||
|
- **最低系统版本**: iOS 12.0
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 项目目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
XinjiangProject/
|
||||||
|
├── Project/ # 业务模块(按功能划分)
|
||||||
|
│ ├── Base/ # 基类 ViewController
|
||||||
|
│ ├── AppDelegate/
|
||||||
|
│ ├── Login_Register/
|
||||||
|
│ ├── HomeV2/
|
||||||
|
│ ├── Homepage/
|
||||||
|
│ ├── Monitoring/
|
||||||
|
│ ├── MainCenter/
|
||||||
|
│ ├── BANK/
|
||||||
|
│ ├── SOS/
|
||||||
|
│ ├── Qusetion/
|
||||||
|
│ ├── TUIChat/
|
||||||
|
│ ├── CustomTUIChat/
|
||||||
|
│ └── simulationUser(模拟用户)/
|
||||||
|
├── Manager/ # 业务逻辑管理层
|
||||||
|
│ ├── NetworkHelpManager/ # 网络层(XJPNetAPI、JKCQNetworkingWithCache)
|
||||||
|
│ ├── UserManager/
|
||||||
|
│ ├── AudioManager/
|
||||||
|
│ ├── TUIManager/
|
||||||
|
│ └── RuntimeManager/
|
||||||
|
├── Categorys/ # UIKit 分类扩展
|
||||||
|
├── Utils/ # 工具类
|
||||||
|
├── Define/ # 宏定义(颜色、字体、接口地址、Key)
|
||||||
|
└── ThirdParty/ # 本地化第三方库
|
||||||
|
```
|
||||||
|
|
||||||
|
新增模块按以下结构组织:
|
||||||
|
```
|
||||||
|
Project/ModuleName/
|
||||||
|
├── Controller/
|
||||||
|
├── View/
|
||||||
|
└── Model/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 命名规范
|
||||||
|
|
||||||
|
**类名(PascalCase):**
|
||||||
|
- 新建类统一使用前缀 `XJ`,如 `XJOrderViewController`、`XJUserModel`
|
||||||
|
- 历史遗留 `HQ` 前缀类(如 `HQUserInfo`)维护时保持原前缀,不得重命名
|
||||||
|
- 分类命名:`ClassName+ExtensionName`,如 `UIView+Extension`
|
||||||
|
|
||||||
|
**方法名(camelCase):**
|
||||||
|
```objc
|
||||||
|
- (void)setupNavigationBar;
|
||||||
|
- (void)loadUserDataWithType:(NSInteger)type;
|
||||||
|
```
|
||||||
|
|
||||||
|
**属性修饰符规范:**
|
||||||
|
```objc
|
||||||
|
@property (nonatomic, strong) UIView *containerView; // 对象用 strong
|
||||||
|
@property (nonatomic, copy) NSString *userName; // 字符串/Block 用 copy
|
||||||
|
@property (nonatomic, assign) NSInteger pageIndex; // 基本类型用 assign
|
||||||
|
@property (nonatomic, weak) id<Protocol> delegate; // 代理用 weak
|
||||||
|
```
|
||||||
|
|
||||||
|
**宏常量:**
|
||||||
|
```objc
|
||||||
|
#define kNavBgColor [UIColor colorWithHexString:@"#00AE68"] // 颜色用 k 前缀
|
||||||
|
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width // 系统级用大写
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 代码组织(#pragma mark)
|
||||||
|
|
||||||
|
```objc
|
||||||
|
#pragma mark - ————— Life Cycle —————
|
||||||
|
|
||||||
|
#pragma mark - ————— Setter / Getter —————
|
||||||
|
|
||||||
|
#pragma mark - ————— Private Methods —————
|
||||||
|
|
||||||
|
#pragma mark - ————— Network —————
|
||||||
|
|
||||||
|
#pragma mark - ————— UITableViewDataSource —————
|
||||||
|
|
||||||
|
#pragma mark - ————— UITableViewDelegate —————
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 内存管理
|
||||||
|
|
||||||
|
Block 内防循环引用,使用项目全局 `kWeakSelf` 宏:
|
||||||
|
|
||||||
|
```objc
|
||||||
|
kWeakSelf(self);
|
||||||
|
[self.manager doSomethingWithCompletion:^{
|
||||||
|
[weakself updateUI];
|
||||||
|
}];
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### UI 布局
|
||||||
|
|
||||||
|
frame 与 Masonry 均可使用,根据实际场景判断,不强制统一。
|
||||||
|
|
||||||
|
屏幕适配使用项目已定义宏(基于 375pt 基准):
|
||||||
|
```objc
|
||||||
|
kRealValue(x) // 尺寸等比缩放
|
||||||
|
kFontSize(x) // 字体等比缩放
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 网络层规范
|
||||||
|
|
||||||
|
项目网络层使用 `XJPNetAPI` + `JKCQNetworkingWithCache`,
|
||||||
|
回调通过 `performSelector` 动态分发,**遵循以下固定签名**:
|
||||||
|
|
||||||
|
**发起请求:**
|
||||||
|
```objc
|
||||||
|
// init:tag:NeedToken: 初始化,self 作为代理,tag 区分同一 VC 内的不同请求
|
||||||
|
XJPNetAPI *api = [[XJPNetAPI alloc] init:self tag:@"USERINFO" NeedToken:token];
|
||||||
|
[api getUserInfo:paramDic];
|
||||||
|
```
|
||||||
|
|
||||||
|
**实现回调(固定方法签名,不得修改):**
|
||||||
|
```objc
|
||||||
|
// 请求成功
|
||||||
|
- (void)Sucess:(id)response tag:(NSString *)tag {
|
||||||
|
if ([tag isEqualToString:@"USERINFO"]) {
|
||||||
|
// 处理用户信息数据
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 请求失败
|
||||||
|
- (void)Failed:(NSString *)message tag:(NSString *)tag {
|
||||||
|
[self showMBProgressHUDOnlyWithString:message];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**注意事项:**
|
||||||
|
- `Sucess` 为项目约定拼写(非笔误),禁止修改方法名
|
||||||
|
- 同一 VC 内多个请求通过 `tag` 字符串区分,在回调中用 `if/else` 分支处理
|
||||||
|
- API 地址统一定义在 `StatusMacros.h`,禁止在业务代码中硬编码 URL
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 禁止事项
|
||||||
|
|
||||||
|
- 禁止将 API Key、SDKAPPID 等敏感信息硬编码在业务文件中(统一放 `ThirdMacros.h`)
|
||||||
|
- 禁止在主线程执行网络请求、数据库读写、文件 IO 等耗时操作
|
||||||
|
- 禁止在 Category 中声明存储属性(需用 `objc_setAssociatedObject`)
|
||||||
|
- 禁止修改 `Sucess:tag:` / `Failed:tag:` 的方法签名
|
||||||
|
- 禁止未经确认自行封装或绕过 `XJPNetAPI` 发起网络请求
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
platform :ios, '12.0'
|
platform :ios, '15.0'
|
||||||
# 忽略引入库的所有警告
|
# 忽略引入库的所有警告
|
||||||
inhibit_all_warnings!
|
inhibit_all_warnings!
|
||||||
|
|
||||||
|
|||||||
@@ -511,6 +511,6 @@ SPEC CHECKSUMS:
|
|||||||
YYKit: 7cda43304a8dc3696c449041e2cb3107b4e236e7
|
YYKit: 7cda43304a8dc3696c449041e2cb3107b4e236e7
|
||||||
YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
|
YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
|
||||||
|
|
||||||
PODFILE CHECKSUM: c63ef0a5edf68dd395621c435af5c0063b38442a
|
PODFILE CHECKSUM: 9ebe0e8991fab6e5cf3d18a72b82760099c4bc48
|
||||||
|
|
||||||
COCOAPODS: 1.16.2
|
COCOAPODS: 1.16.2
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
188C3FFF3005E07600461C07 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 188C3FFE3005E07600461C07 /* Security.framework */; };
|
||||||
|
188C40013005E08000461C07 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 188C40003005E08000461C07 /* CoreTelephony.framework */; };
|
||||||
2A9D6F4901C83B23A09A207B /* libPods-XinjiangProject.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5380821CF956D8001EF91CA7 /* libPods-XinjiangProject.a */; };
|
2A9D6F4901C83B23A09A207B /* libPods-XinjiangProject.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5380821CF956D8001EF91CA7 /* libPods-XinjiangProject.a */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
@@ -31,6 +33,10 @@
|
|||||||
1809E4622E092C710034C8FC /* XinjiangProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XinjiangProject.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
1809E4622E092C710034C8FC /* XinjiangProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XinjiangProject.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
1809E47D2E092C740034C8FC /* XinjiangProjectTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = XinjiangProjectTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
1809E47D2E092C740034C8FC /* XinjiangProjectTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = XinjiangProjectTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
1809E4872E092C740034C8FC /* XinjiangProjectUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = XinjiangProjectUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
1809E4872E092C740034C8FC /* XinjiangProjectUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = XinjiangProjectUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
188C3FFE3005E07600461C07 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
|
||||||
|
188C40003005E08000461C07 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; };
|
||||||
|
188C40023005E08B00461C07 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||||
|
188C40033005E09100461C07 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
||||||
5380821CF956D8001EF91CA7 /* libPods-XinjiangProject.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-XinjiangProject.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
5380821CF956D8001EF91CA7 /* libPods-XinjiangProject.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-XinjiangProject.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D5F062871D7E5499A760A0A9 /* Pods-XinjiangProject.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-XinjiangProject.release.xcconfig"; path = "Target Support Files/Pods-XinjiangProject/Pods-XinjiangProject.release.xcconfig"; sourceTree = "<group>"; };
|
D5F062871D7E5499A760A0A9 /* Pods-XinjiangProject.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-XinjiangProject.release.xcconfig"; path = "Target Support Files/Pods-XinjiangProject/Pods-XinjiangProject.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
F4F935FBD1765B37B37D212D /* Pods-XinjiangProject.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-XinjiangProject.debug.xcconfig"; path = "Target Support Files/Pods-XinjiangProject/Pods-XinjiangProject.debug.xcconfig"; sourceTree = "<group>"; };
|
F4F935FBD1765B37B37D212D /* Pods-XinjiangProject.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-XinjiangProject.debug.xcconfig"; path = "Target Support Files/Pods-XinjiangProject/Pods-XinjiangProject.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
@@ -72,6 +78,8 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
188C40013005E08000461C07 /* CoreTelephony.framework in Frameworks */,
|
||||||
|
188C3FFF3005E07600461C07 /* Security.framework in Frameworks */,
|
||||||
2A9D6F4901C83B23A09A207B /* libPods-XinjiangProject.a in Frameworks */,
|
2A9D6F4901C83B23A09A207B /* libPods-XinjiangProject.a in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -118,6 +126,10 @@
|
|||||||
5E0194FB12246C95B3FA5215 /* Frameworks */ = {
|
5E0194FB12246C95B3FA5215 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
188C40033005E09100461C07 /* libc++.tbd */,
|
||||||
|
188C40023005E08B00461C07 /* libz.tbd */,
|
||||||
|
188C40003005E08000461C07 /* CoreTelephony.framework */,
|
||||||
|
188C3FFE3005E07600461C07 /* Security.framework */,
|
||||||
5380821CF956D8001EF91CA7 /* libPods-XinjiangProject.a */,
|
5380821CF956D8001EF91CA7 /* libPods-XinjiangProject.a */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
@@ -207,7 +219,7 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = 1;
|
BuildIndependentTargetsInParallel = 1;
|
||||||
LastUpgradeCheck = 1630;
|
LastUpgradeCheck = 2630;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
1809E4612E092C710034C8FC = {
|
1809E4612E092C710034C8FC = {
|
||||||
CreatedOnToolsVersion = 16.3;
|
CreatedOnToolsVersion = 16.3;
|
||||||
@@ -374,9 +386,10 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = XinjiangProject/XinjiangProject.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
|
||||||
DEVELOPMENT_TEAM = A7CC5LW224;
|
DEVELOPMENT_TEAM = A7CC5LW224;
|
||||||
|
ENABLE_MODULE_VERIFIER = YES;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
GCC_PREFIX_HEADER = "$(SRCROOT)/XinjiangProject/Supporting Files/PrefixHeader.pch";
|
GCC_PREFIX_HEADER = "$(SRCROOT)/XinjiangProject/Supporting Files/PrefixHeader.pch";
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@@ -400,7 +413,8 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.8;
|
MARKETING_VERSION = 1.0.14;
|
||||||
|
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.questionTools.XinjiangProject;
|
PRODUCT_BUNDLE_IDENTIFIER = com.questionTools.XinjiangProject;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
@@ -418,9 +432,10 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = XinjiangProject/XinjiangProject.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
|
||||||
DEVELOPMENT_TEAM = A7CC5LW224;
|
DEVELOPMENT_TEAM = A7CC5LW224;
|
||||||
|
ENABLE_MODULE_VERIFIER = YES;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
GCC_PREFIX_HEADER = "$(SRCROOT)/XinjiangProject/Supporting Files/PrefixHeader.pch";
|
GCC_PREFIX_HEADER = "$(SRCROOT)/XinjiangProject/Supporting Files/PrefixHeader.pch";
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@@ -444,7 +459,8 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.8;
|
MARKETING_VERSION = 1.0.14;
|
||||||
|
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.questionTools.XinjiangProject;
|
PRODUCT_BUNDLE_IDENTIFIER = com.questionTools.XinjiangProject;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
@@ -515,6 +531,7 @@
|
|||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@@ -570,6 +587,7 @@
|
|||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
|
|||||||
+102
@@ -0,0 +1,102 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "2630"
|
||||||
|
version = "1.7">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "1809E4612E092C710034C8FC"
|
||||||
|
BuildableName = "XinjiangProject.app"
|
||||||
|
BlueprintName = "XinjiangProject"
|
||||||
|
ReferencedContainer = "container:XinjiangProject.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
<Testables>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO"
|
||||||
|
parallelizable = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "1809E47C2E092C740034C8FC"
|
||||||
|
BuildableName = "XinjiangProjectTests.xctest"
|
||||||
|
BlueprintName = "XinjiangProjectTests"
|
||||||
|
ReferencedContainer = "container:XinjiangProject.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO"
|
||||||
|
parallelizable = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "1809E4862E092C740034C8FC"
|
||||||
|
BuildableName = "XinjiangProjectUITests.xctest"
|
||||||
|
BlueprintName = "XinjiangProjectUITests"
|
||||||
|
ReferencedContainer = "container:XinjiangProject.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "1809E4612E092C710034C8FC"
|
||||||
|
BuildableName = "XinjiangProject.app"
|
||||||
|
BlueprintName = "XinjiangProject"
|
||||||
|
ReferencedContainer = "container:XinjiangProject.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "1809E4612E092C710034C8FC"
|
||||||
|
BuildableName = "XinjiangProject.app"
|
||||||
|
BlueprintName = "XinjiangProject"
|
||||||
|
ReferencedContainer = "container:XinjiangProject.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
@@ -91,7 +91,7 @@ static char edgeKey;
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DIYStyleImgBottom:
|
case DIYStyleImgBottom:
|
||||||
NSLog(@"%f",titleX);
|
DLog(@"%f",titleX);
|
||||||
self.titleEdgeInsets = UIEdgeInsetsMake(((selfH - totalH)/2.0 - titleY),
|
self.titleEdgeInsets = UIEdgeInsetsMake(((selfH - totalH)/2.0 - titleY),
|
||||||
-(titleX + titleW/2.0 - selfW/2.0),
|
-(titleX + titleW/2.0 - selfW/2.0),
|
||||||
-((selfH - totalH)/2.0 - titleY),
|
-((selfH - totalH)/2.0 - titleY),
|
||||||
@@ -156,7 +156,7 @@ static char edgeKey;
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DIYStyleImgBottom:
|
case DIYStyleImgBottom:
|
||||||
NSLog(@"%f",titleX);
|
DLog(@"%f",titleX);
|
||||||
self.titleEdgeInsets = UIEdgeInsetsMake(((selfH - totalH)/2.0 - titleY),
|
self.titleEdgeInsets = UIEdgeInsetsMake(((selfH - totalH)/2.0 - titleY),
|
||||||
-(titleX + titleW/2.0 - selfW/2.0),
|
-(titleX + titleW/2.0 - selfW/2.0),
|
||||||
-((selfH - totalH)/2.0 - titleY),
|
-((selfH - totalH)/2.0 - titleY),
|
||||||
@@ -220,7 +220,7 @@ static char edgeKey;
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DIYStyleImgBottom:
|
case DIYStyleImgBottom:
|
||||||
NSLog(@"%f",titleX);
|
DLog(@"%f",titleX);
|
||||||
self.titleEdgeInsets = UIEdgeInsetsMake(((selfH - totalH)/2.0 - titleY),
|
self.titleEdgeInsets = UIEdgeInsetsMake(((selfH - totalH)/2.0 - titleY),
|
||||||
-(titleX + titleW/2.0 - selfW/2.0),
|
-(titleX + titleW/2.0 - selfW/2.0),
|
||||||
-((selfH - totalH)/2.0 - titleY),
|
-((selfH - totalH)/2.0 - titleY),
|
||||||
@@ -288,7 +288,7 @@ static char edgeKey;
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DIYStyleImgBottom:
|
case DIYStyleImgBottom:
|
||||||
NSLog(@"%f",titleX);
|
DLog(@"%f",titleX);
|
||||||
self.titleEdgeInsets = UIEdgeInsetsMake(((selfH - totalH)/2.0 - titleY),
|
self.titleEdgeInsets = UIEdgeInsetsMake(((selfH - totalH)/2.0 - titleY),
|
||||||
-(titleX + titleW/2.0 - selfW/2.0),
|
-(titleX + titleW/2.0 - selfW/2.0),
|
||||||
-((selfH - totalH)/2.0 - titleY),
|
-((selfH - totalH)/2.0 - titleY),
|
||||||
|
|||||||
@@ -15,13 +15,11 @@
|
|||||||
#define KNotificationLoginIMResult @"loginIMResult"
|
#define KNotificationLoginIMResult @"loginIMResult"
|
||||||
|
|
||||||
//切换tabar
|
//切换tabar
|
||||||
#define KNotificSelectHomePageTabbar @"SlectHomePageTabBar"
|
|
||||||
|
|
||||||
#define KNotificSelectSoSTabbar @"SlectSoSTabBar"
|
#define KNotificSelectQuestionTabbar @"SlectQuestionTabBar"
|
||||||
|
#define KNotificSelectSOSCenterTabbar @"SlectSoSTabBar"
|
||||||
|
#define KNotificSelectWatchTabbar @"SlectMonitoringTabBar"
|
||||||
|
|
||||||
#define KNotificSelectPhysicalTabbar @"SlectPhysicalTabBar"
|
|
||||||
|
|
||||||
#define KNotificSelectFileTabbar @"SlectFileTabBar"
|
|
||||||
|
|
||||||
//同意协议
|
//同意协议
|
||||||
|
|
||||||
@@ -63,39 +61,52 @@
|
|||||||
#pragma mark: 网络前缀
|
#pragma mark: 网络前缀
|
||||||
#define ResourceAddress [NSString stringWithFormat:@"%@/file/show/",Http]
|
#define ResourceAddress [NSString stringWithFormat:@"%@/file/show/",Http]
|
||||||
|
|
||||||
//开发环境地址 彭杰 http://192.168.1.37
|
|
||||||
|
|
||||||
//#define Http @"http://192.168.1.37"//
|
|
||||||
//#define H5DevHost @"xjgateway.mcrm.vip:8888"//
|
|
||||||
//#define IntervenH5 @"https://xjconsole.mcrm.vip:8888"
|
|
||||||
//#define BASEURL @"https://yyjk.cqygjk.com" //北边接口前缀
|
|
||||||
//#define SCHEME @"https" //
|
|
||||||
//#define Http @"http://192.168.1.23"//昊
|
|
||||||
|
|
||||||
//正式地址
|
//正式地址
|
||||||
//#define Http @"https://api-jkglpt.iosp.ydpt.tech"//
|
//#define Http @"https://api-jkglpt.iosp.ydpt.tech"//
|
||||||
//#define H5DevHost @"api-jkglpt.iosp.ydpt.tech"//
|
//#define H5DevHost @"api-jkglpt.iosp.ydpt.tech"//
|
||||||
//#define IntervenH5 @"https://console-jkglpt.iosp.ydpt.tech"
|
//#define IntervenH5 @"https://console-jkglpt.iosp.ydpt.tech"
|
||||||
//#define SCHEME @"https" //
|
//#define SCHEME @"https" //
|
||||||
|
//#define OtherHttp @"https://api-jkglpt.iosp.ydpt.tech/hb" //
|
||||||
|
|
||||||
//卫鑫本地
|
|
||||||
//#define Http @"https://api-jkglpt.iosp.ydpt.tech"//
|
|
||||||
//#define H5DevHost @"api-jkglpt.iosp.ydpt.tech"//
|
|
||||||
//#define IntervenH5 @"http://192.168.1.26:9876"
|
|
||||||
//#define SCHEME @"https" //
|
|
||||||
|
|
||||||
//测试
|
|
||||||
#define Http @"https://api-xj.tri.icdat.cn"//
|
//最新新疆测试地址
|
||||||
#define H5DevHost @"api-xj.tri.icdat.cn"//
|
//#define Http @"http://192.168.1.223"//彭杰
|
||||||
#define IntervenH5 @"https://console-xj.tri.icdat.cn"
|
// 最新地址
|
||||||
|
//#define Http @"http://192.168.1.47"//王昊
|
||||||
|
#define Http @"https://xj-api.yixiong-tech.com:8081"//
|
||||||
|
#define H5DevHost @"xjxc-api.mcrm.vip:8888"//
|
||||||
|
#define IntervenH5 @"http://10.10.10.228:23006/"
|
||||||
#define SCHEME @"https" //
|
#define SCHEME @"https" //
|
||||||
|
#define OtherHttp @"https://gstest.superwx.cn/xj_health" //
|
||||||
|
|
||||||
|
|
||||||
//新疆项目后期的调试环境由阿里云迁移至公司内部主机服务器,功能联调和测试可用以下的环境地址
|
#pragma mark - ——————— 健康知识/资讯 ————————
|
||||||
//https://api-xj.tri.icdat.cn
|
|
||||||
//https://console-xj.tri.icdat.cn/
|
// H5 页面地址
|
||||||
//接口: http://api-xj.tri.dt.io/
|
#define kHealthKnowMoreH5 @"/healthnewsweb/healthKnow.html"
|
||||||
//后台: http://console-xj.tri.dt.io/
|
#define kHealthNewsMoreH5 @"/healthnewsweb/healthNews.html"
|
||||||
//大屏: http://screen-xj.tri.dt.io/home
|
#define kHealthDetailH5 @"/healthnewsweb/healthNewsDetail.html"
|
||||||
|
#define kHealthSearchH5 @"/healthnewsweb/healthSecrch.html"
|
||||||
|
|
||||||
|
// HMAC-SHA256 签名密钥
|
||||||
|
#define kHealthKnowledgeSecretKey @"XJp3EHpcnwReXc1A"
|
||||||
|
|
||||||
|
//测试 健康知识+资讯
|
||||||
|
//#define kHealthKnowledgeBaseURL @"https://gstest.superwx.cn/healthcheck"
|
||||||
|
//#define kHealthKnowledgeH5Host @"https://gstest.superwx.cn"
|
||||||
|
//正式 健康知识+资讯
|
||||||
|
#define kHealthKnowledgeBaseURL @"https://api-jkglpt.iosp.ydpt.tech/hb"
|
||||||
|
#define kHealthKnowledgeH5Host @"https://console-jkglpt.iosp.ydpt.tech/hb"
|
||||||
|
|
||||||
|
// API 路径
|
||||||
|
#define kHealthKnowledgeTokenPath @"/pe/frontend/init"
|
||||||
|
#define kHealthKnowledgeCategoryPath @"/cms/frontend/category/list"
|
||||||
|
#define kHealthKnowledgeArticleListPath @"/cms/frontend/articleList"
|
||||||
|
|
||||||
|
// 急救宣教资源
|
||||||
|
#define kFirstAidResourceDetailPath @"/health-emergency/api/emergency/firstAid/resource/resource/queryById"
|
||||||
|
|
||||||
|
|
||||||
#endif /* StatusMacros_h */
|
#endif /* StatusMacros_h */
|
||||||
|
|||||||
@@ -10,9 +10,11 @@
|
|||||||
#define ThirdMacros_h
|
#define ThirdMacros_h
|
||||||
|
|
||||||
//微信
|
//微信
|
||||||
#define kAppKey_Wechat @""
|
#define kAppKey_Wechat @"wxb33cd60beda0a212"
|
||||||
|
|
||||||
#define kSecret_Wechat @""
|
#define kSecret_Wechat @"9de1222d6c32af184538d2ae25d1f5a2"
|
||||||
|
|
||||||
|
#define kUniversalLink_Wechat @"https://www.rk-health.com"
|
||||||
|
|
||||||
#define UMShareAppKey @""
|
#define UMShareAppKey @""
|
||||||
|
|
||||||
@@ -22,6 +24,7 @@
|
|||||||
|
|
||||||
#define buglyAppid @""
|
#define buglyAppid @""
|
||||||
|
|
||||||
|
#define SecretKey @"XJp3EHpcnwReXc1A"
|
||||||
|
|
||||||
|
|
||||||
//高德key
|
//高德key
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
|
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
|
||||||
//下载进度
|
//下载进度
|
||||||
progress ? progress(downloadProgress) : nil;
|
progress ? progress(downloadProgress) : nil;
|
||||||
NSLog(@"下载进度:%.2f%%",100.0*downloadProgress.completedUnitCount/downloadProgress.totalUnitCount);
|
DLog(@"下载进度:%.2f%%",100.0*downloadProgress.completedUnitCount/downloadProgress.totalUnitCount);
|
||||||
} destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
|
} destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
|
||||||
|
|
||||||
//拼接缓存目录
|
//拼接缓存目录
|
||||||
@@ -35,11 +35,11 @@
|
|||||||
//拼接文件路径
|
//拼接文件路径
|
||||||
NSString *filePath = [downloadStr stringByAppendingPathComponent:fileDir];
|
NSString *filePath = [downloadStr stringByAppendingPathComponent:fileDir];
|
||||||
|
|
||||||
NSLog(@"downloadStr = %@",downloadStr);
|
DLog(@"downloadStr = %@",downloadStr);
|
||||||
return [NSURL fileURLWithPath:filePath];
|
return [NSURL fileURLWithPath:filePath];
|
||||||
|
|
||||||
} completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
|
} completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
|
||||||
NSLog(@"%@---%@", filePath, filePath.absoluteString);
|
DLog(@"%@---%@", filePath, filePath.absoluteString);
|
||||||
success ? success(filePath.absoluteString /** NSURL->NSString*/) : nil;
|
success ? success(filePath.absoluteString /** NSURL->NSString*/) : nil;
|
||||||
failure && error ? failure(error) : nil;
|
failure && error ? failure(error) : nil;
|
||||||
}];
|
}];
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
//获取路径
|
//获取路径
|
||||||
NSString *documentsPath = [ReaderDocument documentsPath];
|
NSString *documentsPath = [ReaderDocument documentsPath];
|
||||||
//可根据路径command + shift + G查看该路径下的所有的pdf文件
|
//可根据路径command + shift + G查看该路径下的所有的pdf文件
|
||||||
NSLog(@"%@", documentsPath);
|
DLog(@"%@", documentsPath);
|
||||||
NSString *filePath = [documentsPath stringByAppendingPathComponent:fileName];
|
NSString *filePath = [documentsPath stringByAppendingPathComponent:fileName];
|
||||||
ReaderDocument *document = [ReaderDocument withDocumentFilePath:filePath password:nil];
|
ReaderDocument *document = [ReaderDocument withDocumentFilePath:filePath password:nil];
|
||||||
if (document != nil)
|
if (document != nil)
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
[self downloadWithURL:url fileDir:fileName progress:^(NSProgress *progress) {
|
[self downloadWithURL:url fileDir:fileName progress:^(NSProgress *progress) {
|
||||||
|
|
||||||
} success:^(NSString *filePath) {
|
} success:^(NSString *filePath) {
|
||||||
NSLog(@"%@", filePath);
|
DLog(@"%@", filePath);
|
||||||
//下载完成直接打开
|
//下载完成直接打开
|
||||||
[self downLoadPdfFileByUrl:url fileName:fileName];
|
[self downLoadPdfFileByUrl:url fileName:fileName];
|
||||||
} failure:^(NSError *error) {
|
} failure:^(NSError *error) {
|
||||||
@@ -93,7 +93,7 @@
|
|||||||
NSString *filePath = [path stringByAppendingPathComponent:fileName];
|
NSString *filePath = [path stringByAppendingPathComponent:fileName];
|
||||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||||
BOOL result = [fileManager fileExistsAtPath:filePath];
|
BOOL result = [fileManager fileExistsAtPath:filePath];
|
||||||
NSLog(@"这个文件已经存在:%@",result?@"是的":@"不存在");
|
DLog(@"这个文件已经存在:%@",result?@"是的":@"不存在");
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,4 +55,7 @@ typedef void (^FileDownloadFail)(int code, NSString * desc);
|
|||||||
|
|
||||||
#pragma mark - 表单带参数
|
#pragma mark - 表单带参数
|
||||||
- (void)httpPostFormDataRequest:(NSString *)api params:(NSMutableDictionary *)params;
|
- (void)httpPostFormDataRequest:(NSString *)api params:(NSMutableDictionary *)params;
|
||||||
|
|
||||||
|
//外部接口
|
||||||
|
- (void)httpOtherPostRequest:(NSString *)api params:(NSMutableDictionary *)params;
|
||||||
@end
|
@end
|
||||||
|
|||||||
+107
-4
@@ -8,7 +8,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "JKCQNetworkingWithCache.h"
|
#import "JKCQNetworkingWithCache.h"
|
||||||
|
#import <CommonCrypto/CommonHMAC.h>
|
||||||
#define DYLog(...) NSLog(__VA_ARGS__) //如果不需要打印数据, 注释掉NSLog
|
#define DYLog(...) NSLog(__VA_ARGS__) //如果不需要打印数据, 注释掉NSLog
|
||||||
|
|
||||||
|
|
||||||
@@ -20,8 +20,8 @@ typedef NS_ENUM(NSInteger, RequestType) {
|
|||||||
RequestTypeMultiUpload,//多个上传
|
RequestTypeMultiUpload,//多个上传
|
||||||
RequestTypeDownload,
|
RequestTypeDownload,
|
||||||
RequestTypeUpLoadVideo,//上传视频
|
RequestTypeUpLoadVideo,//上传视频
|
||||||
RequestTypeParmFormData//参数表单
|
RequestTypeParmFormData,//参数表单
|
||||||
|
RequestTypeOterTypePost//外部接口
|
||||||
};
|
};
|
||||||
|
|
||||||
@implementation JKCQNetworkingWithCache
|
@implementation JKCQNetworkingWithCache
|
||||||
@@ -65,6 +65,11 @@ typedef NS_ENUM(NSInteger, RequestType) {
|
|||||||
[self httpRequestWithUrlStr:api params:params requestType:RequestTypePost isCache:YES cacheKey:api imageKey:nil withData:nil withDataArray:nil];
|
[self httpRequestWithUrlStr:api params:params requestType:RequestTypePost isCache:YES cacheKey:api imageKey:nil withData:nil withDataArray:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)httpOtherPostRequest:(NSString *)api params:(NSMutableDictionary *)params
|
||||||
|
{
|
||||||
|
[self httpRequestWithUrlStr:api params:params requestType:RequestTypeOterTypePost isCache:NO cacheKey:nil imageKey:nil withData:nil withDataArray:nil];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - 上传文件方法
|
#pragma mark - 上传文件方法
|
||||||
//上传单张图片
|
//上传单张图片
|
||||||
- (void)upLoadDataWithUrlStr:(NSString *)api params:(NSMutableDictionary *)params imageKey:(NSString *)name withData:(NSData *)data
|
- (void)upLoadDataWithUrlStr:(NSString *)api params:(NSMutableDictionary *)params imageKey:(NSString *)name withData:(NSData *)data
|
||||||
@@ -248,6 +253,7 @@ typedef NS_ENUM(NSInteger, RequestType) {
|
|||||||
{
|
{
|
||||||
|
|
||||||
NSLog(@"%@",url);
|
NSLog(@"%@",url);
|
||||||
|
[MBProgressHUD hideHUDForView:[HQCommonUtils getCurrentVC].view animated:YES];
|
||||||
UIWindow *keyWindow = UIApplication.sharedApplication.windows.firstObject;
|
UIWindow *keyWindow = UIApplication.sharedApplication.windows.firstObject;
|
||||||
for (UIWindow *window in UIApplication.sharedApplication.windows) {
|
for (UIWindow *window in UIApplication.sharedApplication.windows) {
|
||||||
if (window.isKeyWindow) {
|
if (window.isKeyWindow) {
|
||||||
@@ -257,7 +263,7 @@ typedef NS_ENUM(NSInteger, RequestType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MBProgressHUD hideHUDForView:keyWindow animated:YES];
|
[MBProgressHUD hideHUDForView:keyWindow animated:YES];
|
||||||
[self showError:@"网络服务出错"];
|
[EasyTextView showErrorText:@"请求超时"];
|
||||||
}
|
}
|
||||||
|
|
||||||
}];
|
}];
|
||||||
@@ -360,10 +366,74 @@ typedef NS_ENUM(NSInteger, RequestType) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
[MBProgressHUD hideHUDForView:[HQCommonUtils getCurrentVC].view animated:YES];
|
[MBProgressHUD hideHUDForView:[HQCommonUtils getCurrentVC].view animated:YES];
|
||||||
|
UIWindow *keyWindow = UIApplication.sharedApplication.windows.firstObject;
|
||||||
|
for (UIWindow *window in UIApplication.sharedApplication.windows) {
|
||||||
|
if (window.isKeyWindow) {
|
||||||
|
keyWindow = window;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MBProgressHUD hideHUDForView:keyWindow animated:YES];
|
||||||
[EasyTextView showErrorText:@"请求超时"];
|
[EasyTextView showErrorText:@"请求超时"];
|
||||||
}
|
}
|
||||||
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
}else if(requestType == RequestTypeOterTypePost) {//参数表单上传
|
||||||
|
//获取当前时间戳
|
||||||
|
|
||||||
|
NSDate *date = [NSDate date];
|
||||||
|
|
||||||
|
NSTimeInterval time = [date timeIntervalSince1970];
|
||||||
|
|
||||||
|
NSString *timeString = [NSString stringWithFormat:@"%.0f", time];
|
||||||
|
|
||||||
|
[session.requestSerializer setValue:@"application/json;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
|
||||||
|
//加密
|
||||||
|
NSString * needSign = [NSString stringWithFormat:@"%@%@",timeString,params];
|
||||||
|
|
||||||
|
NSString * sign = [self signWithTimestamp:timeString body:params secretKey:SecretKey];
|
||||||
|
|
||||||
|
DLog(@"%@",sign);
|
||||||
|
|
||||||
|
[session POST:url parameters:params headers:@{@"X-Timestamp":timeString,@"X-Sign":sign} progress:^(NSProgress * _Nonnull downloadProgress) {
|
||||||
|
|
||||||
|
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||||
|
|
||||||
|
[weakSelf dealWithResponseObject:responseObject cacheUrl:allUrl];
|
||||||
|
|
||||||
|
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
||||||
|
NSString * statusCode = [error.userInfo objectForKey:@"NSLocalizedDescription"];
|
||||||
|
if ([statusCode containsString:@"401"]) {
|
||||||
|
DLog(@"%@",error.userInfo);
|
||||||
|
[HQCommonUtils keyedArchiverWithData:nil key:LoginUserInfo];
|
||||||
|
KPostNotification(KNotificationLoginStateChange, @NO);
|
||||||
|
if (![HQCommonUtils isLogin]) {
|
||||||
|
[EasyTextView showErrorText:@"请您登录"];
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
[EasyTextView showErrorText:@"身份信息已过期"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
NSLog(@"%@",url);
|
||||||
|
[MBProgressHUD hideHUDForView:[HQCommonUtils getCurrentVC].view animated:YES];
|
||||||
|
UIWindow *keyWindow = UIApplication.sharedApplication.windows.firstObject;
|
||||||
|
for (UIWindow *window in UIApplication.sharedApplication.windows) {
|
||||||
|
if (window.isKeyWindow) {
|
||||||
|
keyWindow = window;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MBProgressHUD hideHUDForView:keyWindow animated:YES];
|
||||||
|
[EasyTextView showErrorText:@"请求超时"];
|
||||||
|
}
|
||||||
|
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -572,5 +642,38 @@ typedef NS_ENUM(NSInteger, RequestType) {
|
|||||||
self.requestDelegate=nil;
|
self.requestDelegate=nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark:外部加密sign
|
||||||
|
- (NSString *)signWithTimestamp:(NSString *)timestamp
|
||||||
|
body:(NSDictionary *)bodyDict
|
||||||
|
secretKey:(NSString *)secretKey {
|
||||||
|
|
||||||
|
// 1 字典转 JSON
|
||||||
|
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:bodyDict options:0 error:nil];
|
||||||
|
NSString *body = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||||
|
|
||||||
|
// 2 拼接字符串
|
||||||
|
NSString *signString = [NSString stringWithFormat:@"%@%@", timestamp, body];
|
||||||
|
|
||||||
|
// 3 HMAC-SHA256
|
||||||
|
const char *key = [secretKey UTF8String];
|
||||||
|
const char *data = [signString UTF8String];
|
||||||
|
|
||||||
|
unsigned char result[CC_SHA256_DIGEST_LENGTH];
|
||||||
|
|
||||||
|
CCHmac(kCCHmacAlgSHA256,
|
||||||
|
key,
|
||||||
|
strlen(key),
|
||||||
|
data,
|
||||||
|
strlen(data),
|
||||||
|
result);
|
||||||
|
|
||||||
|
// 4 转16进制
|
||||||
|
NSMutableString *hash = [NSMutableString string];
|
||||||
|
|
||||||
|
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
|
||||||
|
[hash appendFormat:@"%02x", result[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -27,7 +27,28 @@
|
|||||||
- (void)GetSoSHomePageResources:(NSMutableDictionary *)pamraDic;
|
- (void)GetSoSHomePageResources:(NSMutableDictionary *)pamraDic;
|
||||||
- (void)PostEndSoSIMQuestion:(NSMutableDictionary *)pamraDic;
|
- (void)PostEndSoSIMQuestion:(NSMutableDictionary *)pamraDic;
|
||||||
- (void)getSoSCarInfoLocationHome:(NSMutableDictionary *)parmDic;
|
- (void)getSoSCarInfoLocationHome:(NSMutableDictionary *)parmDic;
|
||||||
|
// 急救员 - 搜索专家
|
||||||
|
- (void)getSearchExpert:(NSMutableDictionary *)parmDic;
|
||||||
|
// 急救员 - 搜索员工
|
||||||
|
- (void)getSearchEmployee:(NSMutableDictionary *)parmDic;
|
||||||
|
// 急救员 - 我参与的应急工单
|
||||||
|
- (void)getMyParticipatedOrders:(NSMutableDictionary *)parmDic;
|
||||||
|
// 急救员 - 创建群聊(不发起音视频通话)
|
||||||
|
- (void)getCreateGroupMagFirstAider:(NSMutableDictionary *)parmDic;
|
||||||
|
// 急救员 - 邀请进群
|
||||||
|
- (void)postAddGroupUser:(NSMutableDictionary *)parmDic;
|
||||||
|
// 急救员 - 移除群成员
|
||||||
|
- (void)postRemoveGroupUser:(NSMutableDictionary *)parmDic;
|
||||||
|
// 急救员 - 判断是否联络员
|
||||||
|
- (void)getIsLiaisonUser:(NSMutableDictionary *)parmDic;
|
||||||
|
// 急救员 - 群成员列表
|
||||||
|
- (void)getGroupMemberList:(NSMutableDictionary *)parmDic;
|
||||||
|
// 急救员 - 实际群成员列表(经腾讯IM验证,含isSelf字段)
|
||||||
|
- (void)getActualGroupMemberList:(NSMutableDictionary *)parmDic;
|
||||||
|
// 急救员 - 宣教资源详情
|
||||||
|
- (void)getFirstAidResourceDetail:(NSMutableDictionary *)parmDic;
|
||||||
|
// 一人一案 - 健康档案详情
|
||||||
|
- (void)getOnePersonCase:(NSMutableDictionary *)parmDic;
|
||||||
|
|
||||||
//首页接口
|
//首页接口
|
||||||
- (void)GetQuetsionRecordsList:(NSMutableDictionary *)parmDic;
|
- (void)GetQuetsionRecordsList:(NSMutableDictionary *)parmDic;
|
||||||
@@ -151,4 +172,41 @@
|
|||||||
//恢复用户状态
|
//恢复用户状态
|
||||||
- (void)postRecoverySimulationUser:(NSMutableDictionary *)parmDic;
|
- (void)postRecoverySimulationUser:(NSMutableDictionary *)parmDic;
|
||||||
|
|
||||||
|
//消息
|
||||||
|
- (void)getUserMessageList:(NSMutableDictionary *)parmDic;
|
||||||
|
|
||||||
|
- (void)getUserMessageDetailConnet:(NSMutableDictionary *)parmDic;
|
||||||
|
|
||||||
|
- (void)getHomepageBannerList:(NSMutableDictionary *)parmDic;
|
||||||
|
|
||||||
|
//我的积分
|
||||||
|
- (void)getPointsBankHeard:(NSMutableDictionary *)parmDic;
|
||||||
|
|
||||||
|
- (void)postPointsBankRankData:(NSMutableDictionary *)parmDic;
|
||||||
|
|
||||||
|
- (void)postPointsBankSourceDetail:(NSMutableDictionary *)parmDic;
|
||||||
|
- (void)postPointsCheckInCard:(NSMutableDictionary *)parmDic;
|
||||||
|
|
||||||
|
//积分任务
|
||||||
|
- (void)postPointsTaskList:(NSMutableDictionary *)parmDic;
|
||||||
|
|
||||||
|
//图片地址
|
||||||
|
- (void)getDetailImageAddress:(NSMutableDictionary *)parmDic;
|
||||||
|
//轮播图一次性全请求
|
||||||
|
- (void)getHomeBannerAllData:(NSMutableDictionary *)parmDic;
|
||||||
|
|
||||||
|
//手表接口
|
||||||
|
- (void)getHomeWatchWearBool:(NSMutableDictionary *)parmDic;
|
||||||
|
|
||||||
|
- (void)getHomeWatchData:(NSMutableDictionary *)parmDic;
|
||||||
|
|
||||||
|
- (void)getWebNeedEncryptionKey:(NSMutableDictionary *)parmDic;
|
||||||
|
|
||||||
|
//绑定手表
|
||||||
|
- (void)getBindWatchDevice:(NSMutableDictionary *)parmDic;
|
||||||
|
//解绑手表
|
||||||
|
- (void)getUnBindWatchDevice:(NSMutableDictionary *)parmDic;
|
||||||
|
|
||||||
|
- (void)postPointsUnmberData:(NSMutableDictionary *)parmDic;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -69,6 +69,61 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 急救员 - 搜索专家
|
||||||
|
- (void)getSearchExpert:(NSMutableDictionary *)parmDic {
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-emergency/api/emergency/order/searchExpert",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 急救员 - 判断是否联络员
|
||||||
|
- (void)getIsLiaisonUser:(NSMutableDictionary *)parmDic {
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-emergency/emergency/LargeScreenNew/isLiaisonUser",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 急救员 - 创建群聊(不发起音视频通话)
|
||||||
|
- (void)getCreateGroupMagFirstAider:(NSMutableDictionary *)parmDic {
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-emergency/api/emergency/createGroupMagFirstAider",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 急救员 - 我参与的应急工单
|
||||||
|
- (void)getMyParticipatedOrders:(NSMutableDictionary *)parmDic {
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-emergency/api/emergency/order/myParticipatedOrders",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 急救员 - 搜索员工
|
||||||
|
- (void)getSearchEmployee:(NSMutableDictionary *)parmDic {
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-emergency/api/emergency/order/searchEmployee",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 急救员 - 邀请进群
|
||||||
|
- (void)postAddGroupUser:(NSMutableDictionary *)parmDic {
|
||||||
|
[httpRequest httpPostRequest:[NSString stringWithFormat:@"%@/health-emergency/api/emergency/addGroupUser",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 急救员 - 移除群成员
|
||||||
|
- (void)postRemoveGroupUser:(NSMutableDictionary *)parmDic {
|
||||||
|
[httpRequest httpPostRequest:[NSString stringWithFormat:@"%@/health-emergency/api/emergency/removeGroupUser",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 急救员 - 群成员列表
|
||||||
|
- (void)getGroupMemberList:(NSMutableDictionary *)parmDic {
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-emergency/api/emergency/order/getGroupMemberList",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 急救员 - 实际群成员列表(经腾讯IM验证,含isSelf字段)
|
||||||
|
- (void)getActualGroupMemberList:(NSMutableDictionary *)parmDic {
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-emergency/api/emergency/order/getActualGroupMemberList",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 急救员 - 宣教资源详情
|
||||||
|
- (void)getFirstAidResourceDetail:(NSMutableDictionary *)parmDic {
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-emergency/api/emergency/firstAid/resource/resource/queryById",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 一人一案 - 健康档案详情
|
||||||
|
- (void)getOnePersonCase:(NSMutableDictionary *)parmDic {
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-emergency/emergency/LargeScreenNew/onePersonCase",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)getNearbyHomePageHospitalPoint:(NSMutableDictionary *)parmDic {
|
- (void)getNearbyHomePageHospitalPoint:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/medical-center/api/resource/nearbyResource",Http] params:parmDic];
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/medical-center/api/resource/nearbyResource",Http] params:parmDic];
|
||||||
@@ -828,4 +883,105 @@
|
|||||||
[httpRequest httpPostRequest:[NSString stringWithFormat:@"%@/health-system/test/restore",Http] params:parmDic];
|
[httpRequest httpPostRequest:[NSString stringWithFormat:@"%@/health-system/test/restore",Http] params:parmDic];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)getUserMessageList:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-system/app/sys/message/notice/list",Http] params:parmDic];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getUserMessageDetailConnet:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-system/app/sys/message/notice/queryById",Http] params:parmDic];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//轮播图
|
||||||
|
- (void)getHomepageBannerList:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/sys/api/banner/selectBannerList",Http] params:parmDic];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getWebNeedEncryptionKey:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-system/api/sys/encryptInfo",Http] params:parmDic];
|
||||||
|
|
||||||
|
}
|
||||||
|
//积分银行
|
||||||
|
- (void)getPointsBankHeard:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-system/bank/userPoints/app/myPoints",Http] params:parmDic];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//积分榜单
|
||||||
|
- (void)postPointsBankRankData:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
|
[httpRequest httpPostRequest:[NSString stringWithFormat:@"%@/health-system/bank/userPoints/app/pointRanking",Http] params:parmDic];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//积分明细
|
||||||
|
- (void)postPointsBankSourceDetail:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
|
[httpRequest httpPostRequest:[NSString stringWithFormat:@"%@/health-system/bank/userPoints/app/pointRecord",Http] params:parmDic];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//积分任务
|
||||||
|
- (void)postPointsCheckInCard:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
|
[httpRequest httpPostRequest:[NSString stringWithFormat:@"%@/health-system/bank/userPoints/app/pointCheckIn",Http] params:parmDic];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//积分任务
|
||||||
|
- (void)postPointsTaskList:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
|
[httpRequest httpPostRequest:[NSString stringWithFormat:@"%@/health-system/bank/userPoints/app/pointsTaskList",Http] params:parmDic];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//图片地址
|
||||||
|
- (void)getDetailImageAddress:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-consultation/consultation/conSession/getPicUrl",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getHomeBannerAllData:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-system/sys/api/banner/selectAllBannerList",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark:手表相关
|
||||||
|
//是否佩戴手表
|
||||||
|
- (void)getHomeWatchWearBool:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-watch/api/watchData/findWatchInfo",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
|
||||||
|
//手表数据
|
||||||
|
- (void)getHomeWatchData:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-watch/api/watchData/userWatchDataAll",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)getBindWatchDevice:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-watch/watch/watchDevice/app/bindDevice",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
//解绑手表
|
||||||
|
- (void)getUnBindWatchDevice:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
|
[httpRequest httpGetRequest:[NSString stringWithFormat:@"%@/health-watch/watch/watchDevice/app/unbundleDevice",Http] params:parmDic];
|
||||||
|
}
|
||||||
|
|
||||||
|
//外部接口
|
||||||
|
- (void)postPointsUnmberData:(NSMutableDictionary *)parmDic {
|
||||||
|
|
||||||
|
[httpRequest httpOtherPostRequest:[NSString stringWithFormat:@"%@/api/v1/users/point-details",OtherHttp] params:parmDic];
|
||||||
|
}
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
[TUILogin login:sdkAppid userID:userID userSig:userSig succ:^{
|
[TUILogin login:sdkAppid userID:userID userSig:userSig succ:^{
|
||||||
|
|
||||||
// KPostNotification(KNotificationLoginIMResult, @YES);
|
// KPostNotification(KNotificationLoginIMResult, @YES);
|
||||||
|
HQUserInfo *user = [HQCommonUtils keyedUnarchiverWithKey:LoginUserInfo];
|
||||||
|
[[TUICallKit createInstance] setSelfInfo:user.realname avatar:user.avatar succ:nil fail:nil];
|
||||||
|
|
||||||
} fail:^(int code, NSString *msg) {
|
} fail:^(int code, NSString *msg) {
|
||||||
|
|
||||||
@@ -103,7 +105,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
+ (void)sendGroupVideo:(NSString *)groupID withUserIdList:(NSArray *)userList {
|
+ (void)sendGroupVideo:(NSString *)groupID withUserIdList:(NSArray *)userList {
|
||||||
|
|
||||||
[[TUICallKit createInstance] groupCall:groupID userIdList:userList callMediaType:TUICallMediaTypeVideo];
|
[[TUICallKit createInstance] groupCall:groupID userIdList:userList callMediaType:TUICallMediaTypeVideo];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
[aCoder encodeObject:self.depart_id forKey:@"depart_id"];
|
[aCoder encodeObject:self.depart_id forKey:@"depart_id"];
|
||||||
[aCoder encodeObject:self.parentId forKey:@"parentId"];
|
[aCoder encodeObject:self.parentId forKey:@"parentId"];
|
||||||
[aCoder encodeObject:self.departName forKey:@"departName"];
|
[aCoder encodeObject:self.departName forKey:@"departName"];
|
||||||
|
[aCoder encodeObject:self.workNo forKey:@"workNo"];
|
||||||
[aCoder encodeObject:self.token forKey:@"token"];
|
[aCoder encodeObject:self.token forKey:@"token"];
|
||||||
[aCoder encodeObject:self.sex_dictText forKey:@"sex_dictText"];
|
[aCoder encodeObject:self.sex_dictText forKey:@"sex_dictText"];
|
||||||
|
|
||||||
@@ -43,6 +44,8 @@
|
|||||||
self.parentId = [aDecoder decodeObjectForKey:@"parentId"];
|
self.parentId = [aDecoder decodeObjectForKey:@"parentId"];
|
||||||
self.departName = [aDecoder decodeObjectForKey:@"departName"];
|
self.departName = [aDecoder decodeObjectForKey:@"departName"];
|
||||||
self.token = [aDecoder decodeObjectForKey:@"token"];
|
self.token = [aDecoder decodeObjectForKey:@"token"];
|
||||||
|
self.workNo = [aDecoder decodeObjectForKey:@"workNo"];
|
||||||
|
|
||||||
self.sex_dictText = [aDecoder decodeObjectForKey:@"sex_dictText"];
|
self.sex_dictText = [aDecoder decodeObjectForKey:@"sex_dictText"];
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -74,6 +77,7 @@
|
|||||||
self.idCard = safeValue(userInfo[@"idCard"]);
|
self.idCard = safeValue(userInfo[@"idCard"]);
|
||||||
self.personType = safeValue(userInfo[@"personType"]);
|
self.personType = safeValue(userInfo[@"personType"]);
|
||||||
self.sex_dictText = safeValue(userInfo[@"sex_dictText"]);
|
self.sex_dictText = safeValue(userInfo[@"sex_dictText"]);
|
||||||
|
self.workNo = safeValue(userInfo[@"workNo"]);
|
||||||
|
|
||||||
NSDictionary *secondDepart = safeValue(userInfo[@"secondDepart"]);
|
NSDictionary *secondDepart = safeValue(userInfo[@"secondDepart"]);
|
||||||
if ([secondDepart isKindOfClass:[NSDictionary class]]) {
|
if ([secondDepart isKindOfClass:[NSDictionary class]]) {
|
||||||
|
|||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>AvailableLibraries</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>WechatOpenSDK.framework/WechatOpenSDK</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>ios-arm64</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>WechatOpenSDK.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>ios</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>WechatOpenSDK.framework/WechatOpenSDK</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>ios-arm64_x86_64-simulator</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>WechatOpenSDK.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
<string>x86_64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>ios</string>
|
||||||
|
<key>SupportedPlatformVariant</key>
|
||||||
|
<string>simulator</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>XFWK</string>
|
||||||
|
<key>XCFrameworkFormatVersion</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>NSPrivacyAccessedAPITypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>NSPrivacyAccessedAPIType</key>
|
||||||
|
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
||||||
|
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||||
|
<array>
|
||||||
|
<string>CA92.1</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
+167
@@ -0,0 +1,167 @@
|
|||||||
|
重要!
|
||||||
|
SDK2.0.5
|
||||||
|
1. 支持模块化集成:XCFramework 头文件引用改为标准化格式 #import <WechatOpenSDK/WXApi.h>,解决路径冲突并支持 Swift/ObjC 混合开发
|
||||||
|
2. 修复openWXApp偶现失败的问题
|
||||||
|
|
||||||
|
SDK2.0.4
|
||||||
|
1.增加privacy manifest文件
|
||||||
|
2.修复跳微信时可能卡顿的问题
|
||||||
|
|
||||||
|
SDK2.0.2
|
||||||
|
1. 优化XCFramework打包方式
|
||||||
|
|
||||||
|
SDK2.0.1
|
||||||
|
1. SDK支持XCFramework
|
||||||
|
|
||||||
|
SDK2.0.0
|
||||||
|
1. 分享能力支持内容防篡改校验
|
||||||
|
|
||||||
|
SDK1.9.9
|
||||||
|
1. 授权登录支持关闭自动授权
|
||||||
|
2. 分享支持添加签名,防止篡改
|
||||||
|
|
||||||
|
SDK1.9.7
|
||||||
|
1. 适配CocoaPods
|
||||||
|
|
||||||
|
SDK1.9.6
|
||||||
|
1. 适配iOS 16,减少读写剪切板
|
||||||
|
|
||||||
|
SDK1.9.4
|
||||||
|
1. 修复授权登录取消/拒绝时state字段没有带回
|
||||||
|
|
||||||
|
SDK1.9.3
|
||||||
|
1. 新增发起二维码支付能力
|
||||||
|
|
||||||
|
SDK1.9.2
|
||||||
|
1. 新增发起企微客服会话能力
|
||||||
|
|
||||||
|
SDK1.9.1
|
||||||
|
1. 音乐视频分享类型增加运营H5字段
|
||||||
|
|
||||||
|
SDK1.8.9
|
||||||
|
1. 增加音乐视频分享类型
|
||||||
|
|
||||||
|
SDK1.8.8
|
||||||
|
1. 增加游戏直播消息类型
|
||||||
|
|
||||||
|
SDK1.8.7.1
|
||||||
|
1. 修复Xcode11以下编译不通过
|
||||||
|
|
||||||
|
SDK1.8.7
|
||||||
|
1. 修复iPadOS,未安装微信的情况下,因为UA问题无法授权登录
|
||||||
|
2. 修复未安装微信的情况下, 适配了UIScene的App因为UIAlertView Crash
|
||||||
|
3. 增加Universal Link检测函数
|
||||||
|
|
||||||
|
SDK1.8.6.2
|
||||||
|
1. 修改包含"UIWebView"字符的类名
|
||||||
|
|
||||||
|
SDK1.8.6.1
|
||||||
|
1.短信授权登录使用的UIWebview切换成WKWebview
|
||||||
|
|
||||||
|
SDK1.8.6
|
||||||
|
1. 支持Universal Link拉起微信以及返回App
|
||||||
|
2. SDK移除MTA库
|
||||||
|
|
||||||
|
SDK1.8.5
|
||||||
|
1. 更换MTA库:取消对剪切板的访问, 防止和其他SDK竞争导致crash
|
||||||
|
2. NSMutableArray的MTA分类方法改名,减少命名冲突
|
||||||
|
3. 不含支付功能版本移除非税支付和医保支付接口
|
||||||
|
4. 分享音乐支持填写歌词和高清封面图
|
||||||
|
|
||||||
|
SDK1.8.4
|
||||||
|
1. 调整分享图片大小限制
|
||||||
|
2. 新增openBusinessView接口
|
||||||
|
|
||||||
|
SDK1.8.3
|
||||||
|
1. SDK增加调起微信刷卡支付接口
|
||||||
|
2. SDK增加小程序订阅消息接口
|
||||||
|
3. 修复小程序订阅消息接口没有resp的问题
|
||||||
|
|
||||||
|
SDK1.8.2
|
||||||
|
1. SDK增加开发票授权 WXInvoiceAuthInsert
|
||||||
|
2. SDK增加非税接口 WXNontaxPay
|
||||||
|
3. SDK增加医保接口 WXPayInsurance
|
||||||
|
4. 更换MTA库
|
||||||
|
|
||||||
|
SDK1.8.1
|
||||||
|
1. SDK打开小程序支持指定版本(体验,开发,正式版)
|
||||||
|
2. SDK分享小程序支持指定版本(体验,开发,正式版)
|
||||||
|
3. SDK支持输出log日志
|
||||||
|
|
||||||
|
SDK1.8.0
|
||||||
|
1. SDK支持打开小程序
|
||||||
|
2. SDK分享小程序支持shareTicket
|
||||||
|
|
||||||
|
SDK1.7.9
|
||||||
|
1. SDK订阅一次性消息
|
||||||
|
|
||||||
|
SDK1.7.8
|
||||||
|
1 SDK分享小程序支持大图
|
||||||
|
|
||||||
|
SDK1.7.7
|
||||||
|
1 增加SDK分享小程序
|
||||||
|
2 增加选择发票接口
|
||||||
|
|
||||||
|
SDK1.7.6
|
||||||
|
1. 提高稳定性
|
||||||
|
1 修复mta崩溃
|
||||||
|
2 新增接口支持开发者关闭mta数据统计上报
|
||||||
|
|
||||||
|
SDK1.7.5
|
||||||
|
1. 提高稳定性
|
||||||
|
2. 加快registerApp接口启动速度
|
||||||
|
|
||||||
|
SDK1.7.4
|
||||||
|
1. 更新支持iOS启用 ATS(App Transport Security)
|
||||||
|
2. 需要在工程中链接CFNetwork.framework
|
||||||
|
3. 在工程配置中的”Other Linker Flags”中加入”-Objc -all_load”
|
||||||
|
|
||||||
|
SDK1.7.3
|
||||||
|
1. 增强稳定性,适配iOS10
|
||||||
|
2. 修复小于32K的jpg格式缩略图设置失败的问题
|
||||||
|
|
||||||
|
SDK1.7.2
|
||||||
|
1. 修复因CTTeleponyNetworkInfo引起的崩溃问题
|
||||||
|
|
||||||
|
SDK1.7.1
|
||||||
|
1. 支持兼容ipv6(提升稳定性)
|
||||||
|
2. xCode Version 7.3.1 (7D1014) 编译
|
||||||
|
|
||||||
|
SDK1.7
|
||||||
|
1. 支持兼容ipv6
|
||||||
|
2. 修复若干问题增强稳定性
|
||||||
|
|
||||||
|
SDK1.6.3
|
||||||
|
1. xCode7.2 构建的sdk包。
|
||||||
|
2. 请使用xCode7.2进行编译。
|
||||||
|
3. 需要在Build Phases中Link Security.framework
|
||||||
|
4. 修复若干小问题。
|
||||||
|
|
||||||
|
SDK1.6.2
|
||||||
|
1、xCode7.1 构建的sdk包
|
||||||
|
2、请使用xCode7.1进行编译
|
||||||
|
|
||||||
|
SDK1.6.1
|
||||||
|
1、修复armv7s下,bitcode可能编译不过
|
||||||
|
2、解决warning
|
||||||
|
|
||||||
|
SDK1.6
|
||||||
|
1、iOS 9系统策略更新,限制了http协议的访问,此外应用需要在“Info.plist”中将要使用的URL Schemes列为白名单,才可正常检查其他应用是否安装。
|
||||||
|
受此影响,当你的应用在iOS 9中需要使用微信SDK的相关能力(分享、收藏、支付、登录等)时,需要在“Info.plist”里增加如下代码:
|
||||||
|
<key>LSApplicationQueriesSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>weixin</string>
|
||||||
|
</array>
|
||||||
|
<key>NSAppTransportSecurity</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSAllowsArbitraryLoads</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
2、开发者需要在工程中链接上 CoreTelephony.framework
|
||||||
|
3、解决bitcode编译不过问题
|
||||||
|
|
||||||
|
SDK1.5
|
||||||
|
1、废弃safeSendReq:接口,使用sendReq:即可。
|
||||||
|
2、新增+(BOOL) sendAuthReq:(SendAuthReq*) req viewController : (UIViewController*) viewController delegate:(id<WXApiDelegate>) delegate;
|
||||||
|
支持未安装微信情况下Auth,具体见WXApi.h接口描述
|
||||||
|
3、微信开放平台新增了微信模块用户统计功能,便于开发者统计微信功能模块的用户使用和活跃情况。开发者需要在工程中链接上:SystemConfiguration.framework,libz.dylib,libsqlite3.0.dylib。
|
||||||
+231
@@ -0,0 +1,231 @@
|
|||||||
|
//
|
||||||
|
// WXApi.h
|
||||||
|
// 所有Api接口
|
||||||
|
//
|
||||||
|
// Created by Wechat on 12-2-28.
|
||||||
|
// Copyright (c) 2012年 Tencent. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "WXApiObject.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
|
||||||
|
typedef BOOL(^WXGrantReadPasteBoardPermissionCompletion)(void);
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - WXApiDelegate
|
||||||
|
/*! @brief 接收并处理来自微信终端程序的事件消息
|
||||||
|
*
|
||||||
|
* 接收并处理来自微信终端程序的事件消息,期间微信界面会切换到第三方应用程序。
|
||||||
|
* WXApiDelegate 会在handleOpenURL:delegate:中使用并触发。
|
||||||
|
*/
|
||||||
|
@protocol WXApiDelegate <NSObject>
|
||||||
|
@optional
|
||||||
|
|
||||||
|
/*! @brief 收到一个来自微信的请求,第三方应用程序处理完后调用sendResp向微信发送结果
|
||||||
|
*
|
||||||
|
* 收到一个来自微信的请求,异步处理完成后必须调用sendResp发送处理结果给微信。
|
||||||
|
* 可能收到的请求有GetMessageFromWXReq、ShowMessageFromWXReq等。
|
||||||
|
* @param req 具体请求内容,是自动释放的
|
||||||
|
*/
|
||||||
|
- (void)onReq:(BaseReq*)req;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 发送一个sendReq后,收到微信的回应
|
||||||
|
*
|
||||||
|
* 收到一个来自微信的处理结果。调用一次sendReq后会收到onResp。
|
||||||
|
* 可能收到的处理结果有SendMessageToWXResp、SendAuthResp等。
|
||||||
|
* @param resp具体的回应内容,是自动释放的
|
||||||
|
*/
|
||||||
|
- (void)onResp:(BaseResp*)resp;
|
||||||
|
|
||||||
|
/* ! @brief 用于在iOS16以及以上系统上,控制OpenSDK是否读取剪切板中微信传递的数据以及读取的时机
|
||||||
|
* 在iOS16以及以上系统,在SDK需要读取剪切板中微信写入的数据时,会回调该方法。没有实现默认会直接读取微信通过剪切板传递过来的数据
|
||||||
|
* 注意:
|
||||||
|
* 1. 只在iOS16以及以上的系统版本上回调;
|
||||||
|
* 2. 不实现时,OpenSDK会直接调用读取剪切板接口,读取微信传递过来的数据;
|
||||||
|
* 3. 若实现该方法:开发者需要通过调用completion(), 支持异步,通知SDK允许读取剪切板中微信传递的数据,
|
||||||
|
* 不调用completion()则代表不授权OpenSDK读取剪切板,会导致收不到onReq:, onResp:回调,无法后续业务流程。请谨慎使用
|
||||||
|
* 4. 不要长时间持有completion不释放,可能会导致内存泄漏。
|
||||||
|
*/
|
||||||
|
- (void)onNeedGrantReadPasteBoardPermissionWithURL:(nonnull NSURL *)openURL completion:(nonnull WXGrantReadPasteBoardPermissionCompletion)completion;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark - WXApiLogDelegate
|
||||||
|
|
||||||
|
@protocol WXApiLogDelegate <NSObject>
|
||||||
|
|
||||||
|
- (void)onLog:(NSString*)log logLevel:(WXLogLevel)level;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - WXApi
|
||||||
|
|
||||||
|
/*! @brief 微信Api接口函数类
|
||||||
|
*
|
||||||
|
* 该类封装了微信终端SDK的所有接口
|
||||||
|
*/
|
||||||
|
@interface WXApi : NSObject
|
||||||
|
|
||||||
|
/*! @brief WXApi的成员函数,向微信终端程序注册第三方应用。
|
||||||
|
*
|
||||||
|
* 需要在每次启动第三方应用程序时调用。
|
||||||
|
* @attention 请保证在主线程中调用此函数
|
||||||
|
* @param appid 微信开发者ID
|
||||||
|
* @param universalLink 微信开发者Universal Link
|
||||||
|
* @return 成功返回YES,失败返回NO。
|
||||||
|
*/
|
||||||
|
+ (BOOL)registerApp:(NSString *)appid universalLink:(NSString *)universalLink;
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 处理旧版微信通过URL启动App时传递的数据
|
||||||
|
*
|
||||||
|
* 需要在 application:openURL:sourceApplication:annotation:或者application:handleOpenURL中调用。
|
||||||
|
* @param url 微信启动第三方应用时传递过来的URL
|
||||||
|
* @param delegate WXApiDelegate对象,用来接收微信触发的消息。
|
||||||
|
* @return 成功返回YES,失败返回NO。
|
||||||
|
*/
|
||||||
|
+ (BOOL)handleOpenURL:(NSURL *)url delegate:(nullable id<WXApiDelegate>)delegate;
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 处理微信通过Universal Link启动App时传递的数据
|
||||||
|
*
|
||||||
|
* 需要在 application:continueUserActivity:restorationHandler:中调用。
|
||||||
|
* @param userActivity 微信启动第三方应用时系统API传递过来的userActivity
|
||||||
|
* @param delegate WXApiDelegate对象,用来接收微信触发的消息。
|
||||||
|
* @return 成功返回YES,失败返回NO。
|
||||||
|
*/
|
||||||
|
+ (BOOL)handleOpenUniversalLink:(NSUserActivity *)userActivity delegate:(nullable id<WXApiDelegate>)delegate;
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 检查微信是否已被用户安装
|
||||||
|
*
|
||||||
|
* @return 微信已安装返回YES,未安装返回NO。
|
||||||
|
*/
|
||||||
|
+ (BOOL)isWXAppInstalled;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 判断当前微信的版本是否支持OpenApi
|
||||||
|
*
|
||||||
|
* @return 支持返回YES,不支持返回NO。
|
||||||
|
*/
|
||||||
|
+ (BOOL)isWXAppSupportApi;
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 判断当前微信的版本是否支持分享微信状态功能
|
||||||
|
*
|
||||||
|
* @attention 需在工程LSApplicationQueriesSchemes配置中添加weixinStateAPI
|
||||||
|
* @return 支持返回YES,不支持返回NO。
|
||||||
|
*/
|
||||||
|
+ (BOOL)isWXAppSupportStateAPI;
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef BUILD_WITHOUT_PAY
|
||||||
|
/*! @brief 判断当前微信的版本是否支持二维码拉起微信支付
|
||||||
|
*
|
||||||
|
* @attention 需在工程LSApplicationQueriesSchemes配置中添加weixinQRCodePayAPI
|
||||||
|
* @return 支持返回YES,不支持返回NO。
|
||||||
|
*/
|
||||||
|
+ (BOOL)isWXAppSupportQRCodePayAPI;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 获取微信的itunes安装地址
|
||||||
|
*
|
||||||
|
* @return 微信的安装地址字符串。
|
||||||
|
*/
|
||||||
|
+ (NSString *)getWXAppInstallUrl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 获取当前微信SDK的版本号
|
||||||
|
*
|
||||||
|
* @return 返回当前微信SDK的版本号
|
||||||
|
*/
|
||||||
|
+ (NSString *)getApiVersion;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 打开微信
|
||||||
|
*
|
||||||
|
* @return 成功返回YES,失败返回NO。
|
||||||
|
*/
|
||||||
|
+ (BOOL)openWXApp;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 发送请求到微信,等待微信返回onResp
|
||||||
|
*
|
||||||
|
* 函数调用后,会切换到微信的界面。第三方应用程序等待微信返回onResp。微信在异步处理完成后一定会调用onResp。支持以下类型
|
||||||
|
* SendAuthReq、SendMessageToWXReq、PayReq等。
|
||||||
|
* @param req 具体的发送请求。
|
||||||
|
* @param completion 调用结果回调block
|
||||||
|
*/
|
||||||
|
+ (void)sendReq:(BaseReq *)req completion:(void (^ __nullable)(BOOL success))completion;
|
||||||
|
|
||||||
|
/*! @brief 收到微信onReq的请求,发送对应的应答给微信,并切换到微信界面
|
||||||
|
*
|
||||||
|
* 函数调用后,会切换到微信的界面。第三方应用程序收到微信onReq的请求,异步处理该请求,完成后必须调用该函数。可能发送的相应有
|
||||||
|
* GetMessageFromWXResp、ShowMessageFromWXResp等。
|
||||||
|
* @param resp 具体的应答内容
|
||||||
|
* @param completion 调用结果回调block
|
||||||
|
*/
|
||||||
|
+ (void)sendResp:(BaseResp*)resp completion:(void (^ __nullable)(BOOL success))completion;
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 发送Auth请求到微信,支持用户没安装微信,等待微信返回onResp
|
||||||
|
*
|
||||||
|
* 函数调用后,会切换到微信的界面。第三方应用程序等待微信返回onResp。微信在异步处理完成后一定会调用onResp。支持SendAuthReq类型。
|
||||||
|
* @param req 具体的发送请求。
|
||||||
|
* @param viewController 当前界面对象。
|
||||||
|
* @param delegate WXApiDelegate对象,用来接收微信触发的消息。
|
||||||
|
* @param completion 调用结果回调block
|
||||||
|
*/
|
||||||
|
+ (void)sendAuthReq:(SendAuthReq *)req viewController:(UIViewController*)viewController delegate:(nullable id<WXApiDelegate>)delegate completion:(void (^ __nullable)(BOOL success))completion;
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 测试函数,用于排查当前App通过Universal Link方式分享到微信的流程
|
||||||
|
注意1: 调用自检函数之前必须要先调用registerApp:universalLink接口, 并确认调用成功
|
||||||
|
注意2: 自检过程中会有Log产生,可以先调用startLogByLevel函数,根据Log排查问题
|
||||||
|
注意3: 会多次回调block
|
||||||
|
注意4: 仅用于新接入SDK时调试使用,请勿在正式环境的调用
|
||||||
|
*
|
||||||
|
* 当completion回调的step为WXULCheckStepFinal时,表示检测通过,Universal Link接入成功
|
||||||
|
* @param completion 回调Block
|
||||||
|
*/
|
||||||
|
+ (void)checkUniversalLinkReady:(nonnull WXCheckULCompletion)completion;
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief WXApi的成员函数,接受微信的log信息。byBlock
|
||||||
|
注意1:SDK会强引用这个block,注意不要导致内存泄漏,注意不要导致内存泄漏
|
||||||
|
注意2:调用过一次startLog by block之后,如果再调用一次任意方式的startLoad,会释放上一次logBlock,不再回调上一个logBlock
|
||||||
|
*
|
||||||
|
* @param level 打印log的级别
|
||||||
|
* @param logBlock 打印log的回调block
|
||||||
|
*/
|
||||||
|
|
||||||
|
+ (void)startLogByLevel:(WXLogLevel)level logBlock:(WXLogBolock)logBlock;
|
||||||
|
|
||||||
|
/*! @brief WXApi的成员函数,接受微信的log信息。byDelegate
|
||||||
|
注意1:sdk会弱引用这个delegate,这里可加任意对象为代理,不需要与WXApiDelegate同一个对象
|
||||||
|
注意2:调用过一次startLog by delegate之后,再调用一次任意方式的startLoad,不会再回调上一个logDelegate对象
|
||||||
|
* @param level 打印log的级别
|
||||||
|
* @param logDelegate 打印log的回调代理,
|
||||||
|
*/
|
||||||
|
+ (void)startLogByLevel:(WXLogLevel)level logDelegate:(id<WXApiLogDelegate>)logDelegate;
|
||||||
|
|
||||||
|
/*! @brief 停止打印log,会清理block或者delegate为空,释放block
|
||||||
|
* @param
|
||||||
|
*/
|
||||||
|
+ (void)stopLog;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
+1410
File diff suppressed because it is too large
Load Diff
+68
@@ -0,0 +1,68 @@
|
|||||||
|
//
|
||||||
|
// WechatAuthSDK.h
|
||||||
|
// WechatAuthSDK
|
||||||
|
//
|
||||||
|
// Created by 李凯 on 13-11-29.
|
||||||
|
// Copyright (c) 2013年 Tencent. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
enum AuthErrCode {
|
||||||
|
WechatAuth_Err_Ok = 0, //Auth成功
|
||||||
|
WechatAuth_Err_NormalErr = -1, //普通错误
|
||||||
|
WechatAuth_Err_NetworkErr = -2, //网络错误
|
||||||
|
WechatAuth_Err_GetQrcodeFailed = -3, //获取二维码失败
|
||||||
|
WechatAuth_Err_Cancel = -4, //用户取消授权
|
||||||
|
WechatAuth_Err_Timeout = -5, //超时
|
||||||
|
};
|
||||||
|
|
||||||
|
@protocol WechatAuthAPIDelegate<NSObject>
|
||||||
|
@optional
|
||||||
|
|
||||||
|
- (void)onAuthGotQrcode:(UIImage *)image; //得到二维码
|
||||||
|
- (void)onQrcodeScanned; //二维码被扫描
|
||||||
|
- (void)onAuthFinish:(int)errCode AuthCode:(nullable NSString *)authCode; //成功登录
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface WechatAuthSDK : NSObject{
|
||||||
|
NSString *_sdkVersion;
|
||||||
|
__weak id<WechatAuthAPIDelegate> _delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property(nonatomic, weak, nullable) id<WechatAuthAPIDelegate> delegate;
|
||||||
|
@property(nonatomic, readonly) NSString *sdkVersion; //authSDK版本号
|
||||||
|
|
||||||
|
/*! @brief 发送登录请求,等待WechatAuthAPIDelegate回调
|
||||||
|
*
|
||||||
|
* @param appId 微信开发者ID
|
||||||
|
* @param nonceStr 一个随机的尽量不重复的字符串,用来使得每次的signature不同
|
||||||
|
* @param timeStamp 时间戳
|
||||||
|
* @param scope 应用授权作用域,拥有多个作用域用逗号(,)分隔
|
||||||
|
* @param signature 签名
|
||||||
|
* @param schemeData 会在扫码后拼在scheme后
|
||||||
|
* @return 成功返回YES,失败返回NO
|
||||||
|
注:该实现只保证同时只有一个Auth在运行,Auth未完成或未Stop再次调用Auth接口时会返回NO。
|
||||||
|
*/
|
||||||
|
|
||||||
|
- (BOOL)Auth:(NSString *)appId
|
||||||
|
nonceStr:(NSString *)nonceStr
|
||||||
|
timeStamp:(NSString *)timeStamp
|
||||||
|
scope:(NSString *)scope
|
||||||
|
signature:(NSString *)signature
|
||||||
|
schemeData:(nullable NSString *)schemeData;
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 暂停登录请求
|
||||||
|
*
|
||||||
|
* @return 成功返回YES,失败返回NO。
|
||||||
|
*/
|
||||||
|
- (BOOL)StopAuth;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// WechatOpenSDK.h
|
||||||
|
//
|
||||||
|
// Created by Wechat.
|
||||||
|
// Copyright (c) 2012年 Tencent. All rights reserved.
|
||||||
|
//
|
||||||
|
#import <WechatOpenSDK/WXApi.h>
|
||||||
|
#import <WechatOpenSDK/WXApiObject.h>
|
||||||
|
#import <WechatOpenSDK/WechatAuthSDK.h>
|
||||||
|
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.tencent.WechatOpenSDK</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1.0.0</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>MinimumOSVersion</key>
|
||||||
|
<string>12.0</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>WechatOpenSDK</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
framework module WechatOpenSDK {
|
||||||
|
umbrella header "WechatOpenSDK.h"
|
||||||
|
export *
|
||||||
|
link "WechatOpenSDK"
|
||||||
|
}
|
||||||
BIN
Binary file not shown.
+231
@@ -0,0 +1,231 @@
|
|||||||
|
//
|
||||||
|
// WXApi.h
|
||||||
|
// 所有Api接口
|
||||||
|
//
|
||||||
|
// Created by Wechat on 12-2-28.
|
||||||
|
// Copyright (c) 2012年 Tencent. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "WXApiObject.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
|
||||||
|
typedef BOOL(^WXGrantReadPasteBoardPermissionCompletion)(void);
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - WXApiDelegate
|
||||||
|
/*! @brief 接收并处理来自微信终端程序的事件消息
|
||||||
|
*
|
||||||
|
* 接收并处理来自微信终端程序的事件消息,期间微信界面会切换到第三方应用程序。
|
||||||
|
* WXApiDelegate 会在handleOpenURL:delegate:中使用并触发。
|
||||||
|
*/
|
||||||
|
@protocol WXApiDelegate <NSObject>
|
||||||
|
@optional
|
||||||
|
|
||||||
|
/*! @brief 收到一个来自微信的请求,第三方应用程序处理完后调用sendResp向微信发送结果
|
||||||
|
*
|
||||||
|
* 收到一个来自微信的请求,异步处理完成后必须调用sendResp发送处理结果给微信。
|
||||||
|
* 可能收到的请求有GetMessageFromWXReq、ShowMessageFromWXReq等。
|
||||||
|
* @param req 具体请求内容,是自动释放的
|
||||||
|
*/
|
||||||
|
- (void)onReq:(BaseReq*)req;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 发送一个sendReq后,收到微信的回应
|
||||||
|
*
|
||||||
|
* 收到一个来自微信的处理结果。调用一次sendReq后会收到onResp。
|
||||||
|
* 可能收到的处理结果有SendMessageToWXResp、SendAuthResp等。
|
||||||
|
* @param resp具体的回应内容,是自动释放的
|
||||||
|
*/
|
||||||
|
- (void)onResp:(BaseResp*)resp;
|
||||||
|
|
||||||
|
/* ! @brief 用于在iOS16以及以上系统上,控制OpenSDK是否读取剪切板中微信传递的数据以及读取的时机
|
||||||
|
* 在iOS16以及以上系统,在SDK需要读取剪切板中微信写入的数据时,会回调该方法。没有实现默认会直接读取微信通过剪切板传递过来的数据
|
||||||
|
* 注意:
|
||||||
|
* 1. 只在iOS16以及以上的系统版本上回调;
|
||||||
|
* 2. 不实现时,OpenSDK会直接调用读取剪切板接口,读取微信传递过来的数据;
|
||||||
|
* 3. 若实现该方法:开发者需要通过调用completion(), 支持异步,通知SDK允许读取剪切板中微信传递的数据,
|
||||||
|
* 不调用completion()则代表不授权OpenSDK读取剪切板,会导致收不到onReq:, onResp:回调,无法后续业务流程。请谨慎使用
|
||||||
|
* 4. 不要长时间持有completion不释放,可能会导致内存泄漏。
|
||||||
|
*/
|
||||||
|
- (void)onNeedGrantReadPasteBoardPermissionWithURL:(nonnull NSURL *)openURL completion:(nonnull WXGrantReadPasteBoardPermissionCompletion)completion;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark - WXApiLogDelegate
|
||||||
|
|
||||||
|
@protocol WXApiLogDelegate <NSObject>
|
||||||
|
|
||||||
|
- (void)onLog:(NSString*)log logLevel:(WXLogLevel)level;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - WXApi
|
||||||
|
|
||||||
|
/*! @brief 微信Api接口函数类
|
||||||
|
*
|
||||||
|
* 该类封装了微信终端SDK的所有接口
|
||||||
|
*/
|
||||||
|
@interface WXApi : NSObject
|
||||||
|
|
||||||
|
/*! @brief WXApi的成员函数,向微信终端程序注册第三方应用。
|
||||||
|
*
|
||||||
|
* 需要在每次启动第三方应用程序时调用。
|
||||||
|
* @attention 请保证在主线程中调用此函数
|
||||||
|
* @param appid 微信开发者ID
|
||||||
|
* @param universalLink 微信开发者Universal Link
|
||||||
|
* @return 成功返回YES,失败返回NO。
|
||||||
|
*/
|
||||||
|
+ (BOOL)registerApp:(NSString *)appid universalLink:(NSString *)universalLink;
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 处理旧版微信通过URL启动App时传递的数据
|
||||||
|
*
|
||||||
|
* 需要在 application:openURL:sourceApplication:annotation:或者application:handleOpenURL中调用。
|
||||||
|
* @param url 微信启动第三方应用时传递过来的URL
|
||||||
|
* @param delegate WXApiDelegate对象,用来接收微信触发的消息。
|
||||||
|
* @return 成功返回YES,失败返回NO。
|
||||||
|
*/
|
||||||
|
+ (BOOL)handleOpenURL:(NSURL *)url delegate:(nullable id<WXApiDelegate>)delegate;
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 处理微信通过Universal Link启动App时传递的数据
|
||||||
|
*
|
||||||
|
* 需要在 application:continueUserActivity:restorationHandler:中调用。
|
||||||
|
* @param userActivity 微信启动第三方应用时系统API传递过来的userActivity
|
||||||
|
* @param delegate WXApiDelegate对象,用来接收微信触发的消息。
|
||||||
|
* @return 成功返回YES,失败返回NO。
|
||||||
|
*/
|
||||||
|
+ (BOOL)handleOpenUniversalLink:(NSUserActivity *)userActivity delegate:(nullable id<WXApiDelegate>)delegate;
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 检查微信是否已被用户安装
|
||||||
|
*
|
||||||
|
* @return 微信已安装返回YES,未安装返回NO。
|
||||||
|
*/
|
||||||
|
+ (BOOL)isWXAppInstalled;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 判断当前微信的版本是否支持OpenApi
|
||||||
|
*
|
||||||
|
* @return 支持返回YES,不支持返回NO。
|
||||||
|
*/
|
||||||
|
+ (BOOL)isWXAppSupportApi;
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 判断当前微信的版本是否支持分享微信状态功能
|
||||||
|
*
|
||||||
|
* @attention 需在工程LSApplicationQueriesSchemes配置中添加weixinStateAPI
|
||||||
|
* @return 支持返回YES,不支持返回NO。
|
||||||
|
*/
|
||||||
|
+ (BOOL)isWXAppSupportStateAPI;
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef BUILD_WITHOUT_PAY
|
||||||
|
/*! @brief 判断当前微信的版本是否支持二维码拉起微信支付
|
||||||
|
*
|
||||||
|
* @attention 需在工程LSApplicationQueriesSchemes配置中添加weixinQRCodePayAPI
|
||||||
|
* @return 支持返回YES,不支持返回NO。
|
||||||
|
*/
|
||||||
|
+ (BOOL)isWXAppSupportQRCodePayAPI;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 获取微信的itunes安装地址
|
||||||
|
*
|
||||||
|
* @return 微信的安装地址字符串。
|
||||||
|
*/
|
||||||
|
+ (NSString *)getWXAppInstallUrl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 获取当前微信SDK的版本号
|
||||||
|
*
|
||||||
|
* @return 返回当前微信SDK的版本号
|
||||||
|
*/
|
||||||
|
+ (NSString *)getApiVersion;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 打开微信
|
||||||
|
*
|
||||||
|
* @return 成功返回YES,失败返回NO。
|
||||||
|
*/
|
||||||
|
+ (BOOL)openWXApp;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 发送请求到微信,等待微信返回onResp
|
||||||
|
*
|
||||||
|
* 函数调用后,会切换到微信的界面。第三方应用程序等待微信返回onResp。微信在异步处理完成后一定会调用onResp。支持以下类型
|
||||||
|
* SendAuthReq、SendMessageToWXReq、PayReq等。
|
||||||
|
* @param req 具体的发送请求。
|
||||||
|
* @param completion 调用结果回调block
|
||||||
|
*/
|
||||||
|
+ (void)sendReq:(BaseReq *)req completion:(void (^ __nullable)(BOOL success))completion;
|
||||||
|
|
||||||
|
/*! @brief 收到微信onReq的请求,发送对应的应答给微信,并切换到微信界面
|
||||||
|
*
|
||||||
|
* 函数调用后,会切换到微信的界面。第三方应用程序收到微信onReq的请求,异步处理该请求,完成后必须调用该函数。可能发送的相应有
|
||||||
|
* GetMessageFromWXResp、ShowMessageFromWXResp等。
|
||||||
|
* @param resp 具体的应答内容
|
||||||
|
* @param completion 调用结果回调block
|
||||||
|
*/
|
||||||
|
+ (void)sendResp:(BaseResp*)resp completion:(void (^ __nullable)(BOOL success))completion;
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 发送Auth请求到微信,支持用户没安装微信,等待微信返回onResp
|
||||||
|
*
|
||||||
|
* 函数调用后,会切换到微信的界面。第三方应用程序等待微信返回onResp。微信在异步处理完成后一定会调用onResp。支持SendAuthReq类型。
|
||||||
|
* @param req 具体的发送请求。
|
||||||
|
* @param viewController 当前界面对象。
|
||||||
|
* @param delegate WXApiDelegate对象,用来接收微信触发的消息。
|
||||||
|
* @param completion 调用结果回调block
|
||||||
|
*/
|
||||||
|
+ (void)sendAuthReq:(SendAuthReq *)req viewController:(UIViewController*)viewController delegate:(nullable id<WXApiDelegate>)delegate completion:(void (^ __nullable)(BOOL success))completion;
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 测试函数,用于排查当前App通过Universal Link方式分享到微信的流程
|
||||||
|
注意1: 调用自检函数之前必须要先调用registerApp:universalLink接口, 并确认调用成功
|
||||||
|
注意2: 自检过程中会有Log产生,可以先调用startLogByLevel函数,根据Log排查问题
|
||||||
|
注意3: 会多次回调block
|
||||||
|
注意4: 仅用于新接入SDK时调试使用,请勿在正式环境的调用
|
||||||
|
*
|
||||||
|
* 当completion回调的step为WXULCheckStepFinal时,表示检测通过,Universal Link接入成功
|
||||||
|
* @param completion 回调Block
|
||||||
|
*/
|
||||||
|
+ (void)checkUniversalLinkReady:(nonnull WXCheckULCompletion)completion;
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief WXApi的成员函数,接受微信的log信息。byBlock
|
||||||
|
注意1:SDK会强引用这个block,注意不要导致内存泄漏,注意不要导致内存泄漏
|
||||||
|
注意2:调用过一次startLog by block之后,如果再调用一次任意方式的startLoad,会释放上一次logBlock,不再回调上一个logBlock
|
||||||
|
*
|
||||||
|
* @param level 打印log的级别
|
||||||
|
* @param logBlock 打印log的回调block
|
||||||
|
*/
|
||||||
|
|
||||||
|
+ (void)startLogByLevel:(WXLogLevel)level logBlock:(WXLogBolock)logBlock;
|
||||||
|
|
||||||
|
/*! @brief WXApi的成员函数,接受微信的log信息。byDelegate
|
||||||
|
注意1:sdk会弱引用这个delegate,这里可加任意对象为代理,不需要与WXApiDelegate同一个对象
|
||||||
|
注意2:调用过一次startLog by delegate之后,再调用一次任意方式的startLoad,不会再回调上一个logDelegate对象
|
||||||
|
* @param level 打印log的级别
|
||||||
|
* @param logDelegate 打印log的回调代理,
|
||||||
|
*/
|
||||||
|
+ (void)startLogByLevel:(WXLogLevel)level logDelegate:(id<WXApiLogDelegate>)logDelegate;
|
||||||
|
|
||||||
|
/*! @brief 停止打印log,会清理block或者delegate为空,释放block
|
||||||
|
* @param
|
||||||
|
*/
|
||||||
|
+ (void)stopLog;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
+1410
File diff suppressed because it is too large
Load Diff
+68
@@ -0,0 +1,68 @@
|
|||||||
|
//
|
||||||
|
// WechatAuthSDK.h
|
||||||
|
// WechatAuthSDK
|
||||||
|
//
|
||||||
|
// Created by 李凯 on 13-11-29.
|
||||||
|
// Copyright (c) 2013年 Tencent. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
enum AuthErrCode {
|
||||||
|
WechatAuth_Err_Ok = 0, //Auth成功
|
||||||
|
WechatAuth_Err_NormalErr = -1, //普通错误
|
||||||
|
WechatAuth_Err_NetworkErr = -2, //网络错误
|
||||||
|
WechatAuth_Err_GetQrcodeFailed = -3, //获取二维码失败
|
||||||
|
WechatAuth_Err_Cancel = -4, //用户取消授权
|
||||||
|
WechatAuth_Err_Timeout = -5, //超时
|
||||||
|
};
|
||||||
|
|
||||||
|
@protocol WechatAuthAPIDelegate<NSObject>
|
||||||
|
@optional
|
||||||
|
|
||||||
|
- (void)onAuthGotQrcode:(UIImage *)image; //得到二维码
|
||||||
|
- (void)onQrcodeScanned; //二维码被扫描
|
||||||
|
- (void)onAuthFinish:(int)errCode AuthCode:(nullable NSString *)authCode; //成功登录
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface WechatAuthSDK : NSObject{
|
||||||
|
NSString *_sdkVersion;
|
||||||
|
__weak id<WechatAuthAPIDelegate> _delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property(nonatomic, weak, nullable) id<WechatAuthAPIDelegate> delegate;
|
||||||
|
@property(nonatomic, readonly) NSString *sdkVersion; //authSDK版本号
|
||||||
|
|
||||||
|
/*! @brief 发送登录请求,等待WechatAuthAPIDelegate回调
|
||||||
|
*
|
||||||
|
* @param appId 微信开发者ID
|
||||||
|
* @param nonceStr 一个随机的尽量不重复的字符串,用来使得每次的signature不同
|
||||||
|
* @param timeStamp 时间戳
|
||||||
|
* @param scope 应用授权作用域,拥有多个作用域用逗号(,)分隔
|
||||||
|
* @param signature 签名
|
||||||
|
* @param schemeData 会在扫码后拼在scheme后
|
||||||
|
* @return 成功返回YES,失败返回NO
|
||||||
|
注:该实现只保证同时只有一个Auth在运行,Auth未完成或未Stop再次调用Auth接口时会返回NO。
|
||||||
|
*/
|
||||||
|
|
||||||
|
- (BOOL)Auth:(NSString *)appId
|
||||||
|
nonceStr:(NSString *)nonceStr
|
||||||
|
timeStamp:(NSString *)timeStamp
|
||||||
|
scope:(NSString *)scope
|
||||||
|
signature:(NSString *)signature
|
||||||
|
schemeData:(nullable NSString *)schemeData;
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief 暂停登录请求
|
||||||
|
*
|
||||||
|
* @return 成功返回YES,失败返回NO。
|
||||||
|
*/
|
||||||
|
- (BOOL)StopAuth;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// WechatOpenSDK.h
|
||||||
|
//
|
||||||
|
// Created by Wechat.
|
||||||
|
// Copyright (c) 2012年 Tencent. All rights reserved.
|
||||||
|
//
|
||||||
|
#import <WechatOpenSDK/WXApi.h>
|
||||||
|
#import <WechatOpenSDK/WXApiObject.h>
|
||||||
|
#import <WechatOpenSDK/WechatAuthSDK.h>
|
||||||
|
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.tencent.WechatOpenSDK</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1.0.0</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>MinimumOSVersion</key>
|
||||||
|
<string>12.0</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>WechatOpenSDK</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
framework module WechatOpenSDK {
|
||||||
|
umbrella header "WechatOpenSDK.h"
|
||||||
|
export *
|
||||||
|
link "WechatOpenSDK"
|
||||||
|
}
|
||||||
BIN
Binary file not shown.
@@ -0,0 +1,81 @@
|
|||||||
|
//
|
||||||
|
// XJWeChatManager.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// 微信分享管理类(手动集成 WechatOpenSDK-NoPay)
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/// 微信分享结果回调
|
||||||
|
typedef void(^XJWeChatShareCompletion)(BOOL success, NSString *_Nullable errorMsg);
|
||||||
|
|
||||||
|
@interface XJWeChatManager : NSObject
|
||||||
|
|
||||||
|
+ (instancetype)sharedManager;
|
||||||
|
|
||||||
|
#pragma mark - 注册
|
||||||
|
/// 注册微信 SDK(需在 AppDelegate didFinishLaunching 中调用)
|
||||||
|
/// @param appID 微信开放平台 AppID
|
||||||
|
/// @param universalLink 通用链接
|
||||||
|
- (BOOL)registerWithAppID:(NSString *)appID universalLink:(NSString *)universalLink;
|
||||||
|
|
||||||
|
/// 处理微信 URL 回调(AppDelegate handleOpenURL 中调用)
|
||||||
|
- (BOOL)handleOpenURL:(NSURL *)url;
|
||||||
|
|
||||||
|
/// 处理微信 Universal Link 回调(AppDelegate continueUserActivity 中调用)
|
||||||
|
- (BOOL)handleOpenUniversalLink:(NSUserActivity *)userActivity;
|
||||||
|
|
||||||
|
#pragma mark - 分享
|
||||||
|
/// 分享文字
|
||||||
|
- (void)shareText:(NSString *)text
|
||||||
|
toScene:(int)scene
|
||||||
|
completion:(XJWeChatShareCompletion _Nullable)completion;
|
||||||
|
|
||||||
|
/// 分享图片(NSData)
|
||||||
|
- (void)shareImageData:(NSData *)imageData
|
||||||
|
toScene:(int)scene
|
||||||
|
completion:(XJWeChatShareCompletion _Nullable)completion;
|
||||||
|
|
||||||
|
/// 分享网页
|
||||||
|
/// @param title 标题
|
||||||
|
/// @param desc 描述
|
||||||
|
/// @param webpageUrl 网页链接
|
||||||
|
/// @param thumbImage 缩略图(不超过 32KB)
|
||||||
|
/// @param scene 分享目标:WXSceneSession=好友, WXSceneTimeline=朋友圈
|
||||||
|
- (void)shareWebpageWithTitle:(NSString *)title
|
||||||
|
desc:(NSString *)desc
|
||||||
|
webpageUrl:(NSString *)webpageUrl
|
||||||
|
thumbImage:(UIImage *_Nullable)thumbImage
|
||||||
|
toScene:(int)scene
|
||||||
|
completion:(XJWeChatShareCompletion _Nullable)completion;
|
||||||
|
|
||||||
|
/// 分享小程序卡片
|
||||||
|
/// @param title 标题
|
||||||
|
/// @param desc 描述
|
||||||
|
/// @param webpageUrl 兼容低版本网页链接
|
||||||
|
/// @param userName 小程序原始ID(gh_ 开头)
|
||||||
|
/// @param path 小程序页面路径
|
||||||
|
/// @param miniProgramType 小程序类型:0=正式版, 1=开发版, 2=体验版
|
||||||
|
- (void)shareMiniProgramWithTitle:(NSString *)title
|
||||||
|
desc:(NSString *)desc
|
||||||
|
webpageUrl:(NSString *)webpageUrl
|
||||||
|
userName:(NSString *)userName
|
||||||
|
path:(NSString *)path
|
||||||
|
miniProgramType:(NSUInteger)miniProgramType
|
||||||
|
thumbImage:(UIImage *_Nullable)thumbImage
|
||||||
|
completion:(XJWeChatShareCompletion _Nullable)completion;
|
||||||
|
|
||||||
|
#pragma mark - 工具
|
||||||
|
/// 是否安装微信
|
||||||
|
- (BOOL)isWeChatInstalled;
|
||||||
|
|
||||||
|
/// 微信是否支持 OpenAPI
|
||||||
|
- (BOOL)isWeChatSupportApi;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
//
|
||||||
|
// XJWeChatManager.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// 微信分享管理类
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJWeChatManager.h"
|
||||||
|
#import <WechatOpenSDK/WXApi.h>
|
||||||
|
|
||||||
|
@interface XJWeChatManager () <WXApiDelegate>
|
||||||
|
@property (nonatomic, copy) XJWeChatShareCompletion shareCompletion;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation XJWeChatManager
|
||||||
|
|
||||||
|
#pragma mark - ————— 单例 —————
|
||||||
|
+ (instancetype)sharedManager {
|
||||||
|
static XJWeChatManager *instance = nil;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
instance = [[XJWeChatManager alloc] init];
|
||||||
|
});
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— 注册 —————
|
||||||
|
- (BOOL)registerWithAppID:(NSString *)appID universalLink:(NSString *)universalLink {
|
||||||
|
return [WXApi registerApp:appID universalLink:universalLink];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)handleOpenURL:(NSURL *)url {
|
||||||
|
return [WXApi handleOpenURL:url delegate:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)handleOpenUniversalLink:(NSUserActivity *)userActivity {
|
||||||
|
return [WXApi handleOpenUniversalLink:userActivity delegate:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— 分享 —————
|
||||||
|
- (void)shareText:(NSString *)text
|
||||||
|
toScene:(int)scene
|
||||||
|
completion:(XJWeChatShareCompletion)completion {
|
||||||
|
self.shareCompletion = completion;
|
||||||
|
|
||||||
|
SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init];
|
||||||
|
req.bText = YES;
|
||||||
|
req.text = text;
|
||||||
|
req.scene = scene;
|
||||||
|
|
||||||
|
[WXApi sendReq:req completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)shareImageData:(NSData *)imageData
|
||||||
|
toScene:(int)scene
|
||||||
|
completion:(XJWeChatShareCompletion)completion {
|
||||||
|
self.shareCompletion = completion;
|
||||||
|
|
||||||
|
WXMediaMessage *message = [WXMediaMessage message];
|
||||||
|
message.thumbData = nil;
|
||||||
|
|
||||||
|
WXImageObject *imageObject = [WXImageObject object];
|
||||||
|
imageObject.imageData = imageData;
|
||||||
|
message.mediaObject = imageObject;
|
||||||
|
|
||||||
|
SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init];
|
||||||
|
req.bText = NO;
|
||||||
|
req.message = message;
|
||||||
|
req.scene = scene;
|
||||||
|
|
||||||
|
[WXApi sendReq:req completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)shareWebpageWithTitle:(NSString *)title
|
||||||
|
desc:(NSString *)desc
|
||||||
|
webpageUrl:(NSString *)webpageUrl
|
||||||
|
thumbImage:(UIImage *)thumbImage
|
||||||
|
toScene:(int)scene
|
||||||
|
completion:(XJWeChatShareCompletion)completion {
|
||||||
|
self.shareCompletion = completion;
|
||||||
|
|
||||||
|
WXMediaMessage *message = [WXMediaMessage message];
|
||||||
|
message.title = title;
|
||||||
|
message.description = desc;
|
||||||
|
|
||||||
|
if (thumbImage) {
|
||||||
|
message.thumbData = UIImageJPEGRepresentation(thumbImage, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
WXWebpageObject *webpageObject = [WXWebpageObject object];
|
||||||
|
webpageObject.webpageUrl = webpageUrl;
|
||||||
|
message.mediaObject = webpageObject;
|
||||||
|
|
||||||
|
SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init];
|
||||||
|
req.bText = NO;
|
||||||
|
req.message = message;
|
||||||
|
req.scene = scene;
|
||||||
|
|
||||||
|
[WXApi sendReq:req completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)shareMiniProgramWithTitle:(NSString *)title
|
||||||
|
desc:(NSString *)desc
|
||||||
|
webpageUrl:(NSString *)webpageUrl
|
||||||
|
userName:(NSString *)userName
|
||||||
|
path:(NSString *)path
|
||||||
|
miniProgramType:(NSUInteger)miniProgramType
|
||||||
|
thumbImage:(UIImage *)thumbImage
|
||||||
|
completion:(XJWeChatShareCompletion)completion {
|
||||||
|
self.shareCompletion = completion;
|
||||||
|
|
||||||
|
WXMediaMessage *message = [WXMediaMessage message];
|
||||||
|
message.title = title;
|
||||||
|
message.description = desc;
|
||||||
|
|
||||||
|
if (thumbImage) {
|
||||||
|
message.thumbData = UIImageJPEGRepresentation(thumbImage, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
WXMiniProgramObject *miniProgramObject = [WXMiniProgramObject object];
|
||||||
|
miniProgramObject.webpageUrl = webpageUrl;
|
||||||
|
miniProgramObject.userName = userName;
|
||||||
|
miniProgramObject.path = path;
|
||||||
|
miniProgramObject.miniProgramType = miniProgramType;
|
||||||
|
message.mediaObject = miniProgramObject;
|
||||||
|
|
||||||
|
SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init];
|
||||||
|
req.bText = NO;
|
||||||
|
req.message = message;
|
||||||
|
req.scene = WXSceneSession;
|
||||||
|
|
||||||
|
[WXApi sendReq:req completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— 工具 —————
|
||||||
|
- (BOOL)isWeChatInstalled {
|
||||||
|
return [WXApi isWXAppInstalled];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isWeChatSupportApi {
|
||||||
|
return [WXApi isWXAppSupportApi];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— WXApiDelegate —————
|
||||||
|
- (void)onResp:(BaseResp *)resp {
|
||||||
|
if ([resp isKindOfClass:[SendMessageToWXResp class]]) {
|
||||||
|
if (self.shareCompletion) {
|
||||||
|
if (resp.errCode == WXSuccess) {
|
||||||
|
self.shareCompletion(YES, nil);
|
||||||
|
} else if (resp.errCode == WXErrCodeUserCancel) {
|
||||||
|
self.shareCompletion(NO, @"用户取消分享");
|
||||||
|
} else {
|
||||||
|
self.shareCompletion(NO, resp.errStr ?: @"分享失败");
|
||||||
|
}
|
||||||
|
self.shareCompletion = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
//
|
||||||
|
// XJHealthKnowledgeManager.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/6/29.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "XJHealthCategoryModel.h"
|
||||||
|
#import "XJHealthArticleModel.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/// 健康知识网络管理器
|
||||||
|
@interface XJHealthKnowledgeManager : NSObject
|
||||||
|
|
||||||
|
+ (instancetype)sharedManager;
|
||||||
|
|
||||||
|
/// 当前 token(获取后缓存)
|
||||||
|
@property (nonatomic, copy, readonly, nullable) NSString * cachedToken;
|
||||||
|
|
||||||
|
/// 清除缓存的 token(退出登录时调用)
|
||||||
|
- (void)clearToken;
|
||||||
|
|
||||||
|
/// 获取 token
|
||||||
|
- (void)getTokenWithUserId:(NSString *)userId
|
||||||
|
workNo:(NSString *)workNo
|
||||||
|
success:(void (^)(NSString * token))success
|
||||||
|
failure:(void (^)(NSString * errorMsg))failure;
|
||||||
|
|
||||||
|
/// 获取栏目列表
|
||||||
|
- (void)getCategoryListWithToken:(NSString *)token
|
||||||
|
success:(void (^)(NSArray<XJHealthCategoryModel *> * categories))success
|
||||||
|
failure:(void (^)(NSString * errorMsg))failure;
|
||||||
|
|
||||||
|
/// 分页查询文章(showAppHomepage 固定 Y)
|
||||||
|
- (void)getArticleListWithToken:(NSString *)token
|
||||||
|
categoryId:(NSInteger)categoryId
|
||||||
|
articleType:(nullable NSString *)articleType
|
||||||
|
pageNum:(NSInteger)pageNum
|
||||||
|
pageSize:(NSInteger)pageSize
|
||||||
|
success:(void (^)(NSArray<XJHealthArticleModel *> * articles, NSInteger total))success
|
||||||
|
failure:(void (^)(NSString * errorMsg))failure;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,222 @@
|
|||||||
|
//
|
||||||
|
// XJHealthKnowledgeManager.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/6/29.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJHealthKnowledgeManager.h"
|
||||||
|
#import <CommonCrypto/CommonHMAC.h>
|
||||||
|
|
||||||
|
#pragma mark - ————— Manager —————
|
||||||
|
|
||||||
|
@interface XJHealthKnowledgeManager ()
|
||||||
|
|
||||||
|
@property (nonatomic, copy) NSString * cachedToken;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation XJHealthKnowledgeManager
|
||||||
|
|
||||||
|
+ (instancetype)sharedManager {
|
||||||
|
static XJHealthKnowledgeManager * instance = nil;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
instance = [[XJHealthKnowledgeManager alloc] init];
|
||||||
|
});
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— HMAC-SHA256 —————
|
||||||
|
|
||||||
|
- (void)clearToken {
|
||||||
|
self.cachedToken = nil;
|
||||||
|
DLog(@"[健康知识] Token 已清除");
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)hmacSHA256:(NSString *)data key:(NSString *)key {
|
||||||
|
const char * cKey = [key cStringUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
const char * cData = [data cStringUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
unsigned char result[CC_SHA256_DIGEST_LENGTH];
|
||||||
|
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), result);
|
||||||
|
|
||||||
|
NSMutableString * hash = [[NSMutableString alloc] initWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
|
||||||
|
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
|
||||||
|
[hash appendFormat:@"%02x", result[i]];
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— 获取 Token —————
|
||||||
|
|
||||||
|
- (void)getTokenWithUserId:(NSString *)userId
|
||||||
|
workNo:(NSString *)workNo
|
||||||
|
success:(void (^)(NSString *))success
|
||||||
|
failure:(void (^)(NSString *))failure {
|
||||||
|
|
||||||
|
NSString * urlString = [NSString stringWithFormat:@"%@%@", kHealthKnowledgeBaseURL, kHealthKnowledgeTokenPath];
|
||||||
|
|
||||||
|
// 构建请求体
|
||||||
|
NSDictionary * bodyDict = @{ @"userId": userId ?: @"",
|
||||||
|
@"workNo": workNo ?: @"" };
|
||||||
|
NSData * bodyData = [NSJSONSerialization dataWithJSONObject:bodyDict options:0 error:nil];
|
||||||
|
NSString * bodyString = [[NSString alloc] initWithData:bodyData encoding:NSUTF8StringEncoding];
|
||||||
|
|
||||||
|
// 签名
|
||||||
|
NSString * timestamp = [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]];
|
||||||
|
NSString * stringToSign = [NSString stringWithFormat:@"%@%@", timestamp, bodyString];
|
||||||
|
NSString * sign = [[self class] hmacSHA256:stringToSign key:kHealthKnowledgeSecretKey];
|
||||||
|
|
||||||
|
NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
|
||||||
|
request.HTTPMethod = @"POST";
|
||||||
|
[request setValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
|
||||||
|
[request setValue:timestamp forHTTPHeaderField:@"X-Timestamp"];
|
||||||
|
[request setValue:sign forHTTPHeaderField:@"X-Sign"];
|
||||||
|
request.HTTPBody = bodyData;
|
||||||
|
|
||||||
|
DLog(@"[健康知识] 请求 Token URL: %@", urlString);
|
||||||
|
DLog(@"[健康知识] 签名串: %@", stringToSign);
|
||||||
|
DLog(@"[健康知识] X-Sign: %@", sign);
|
||||||
|
|
||||||
|
[self sendRequest:request completion:^(NSDictionary * json) {
|
||||||
|
DLog(@"[健康知识] Token 响应: %@", json);
|
||||||
|
if ([json[@"code"] integerValue] == 200) {
|
||||||
|
NSString * token = json[@"data"][@"token"];
|
||||||
|
if (!ValidStr(token)) {
|
||||||
|
self.cachedToken = token;
|
||||||
|
DLog(@"[健康知识] Token 获取成功: %@", token);
|
||||||
|
if (success) success(token);
|
||||||
|
} else {
|
||||||
|
DLog(@"[健康知识] Token 为空");
|
||||||
|
if (failure) failure(@"token 为空");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DLog(@"[健康知识] Token 失败: %@", json[@"msg"]);
|
||||||
|
if (failure) failure(json[@"msg"] ?: @"获取 token 失败");
|
||||||
|
}
|
||||||
|
} failure:^(NSString * errorMsg) {
|
||||||
|
DLog(@"[健康知识] Token 请求异常: %@", errorMsg);
|
||||||
|
if (failure) failure(errorMsg);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— 栏目列表 —————
|
||||||
|
|
||||||
|
- (void)getCategoryListWithToken:(NSString *)token
|
||||||
|
success:(void (^)(NSArray<XJHealthCategoryModel *> *))success
|
||||||
|
failure:(void (^)(NSString *))failure {
|
||||||
|
|
||||||
|
NSString * urlString = [NSString stringWithFormat:@"%@%@", kHealthKnowledgeBaseURL, kHealthKnowledgeCategoryPath];
|
||||||
|
|
||||||
|
NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
|
||||||
|
request.HTTPMethod = @"GET";
|
||||||
|
[request setValue:token forHTTPHeaderField:@"token"];
|
||||||
|
|
||||||
|
[self sendRequest:request completion:^(NSDictionary * json) {
|
||||||
|
if ([json[@"code"] integerValue] == 200) {
|
||||||
|
NSArray * dataArray = json[@"data"];
|
||||||
|
NSMutableArray * categories = [[NSMutableArray alloc] init];
|
||||||
|
if ([dataArray isKindOfClass:[NSArray class]]) {
|
||||||
|
for (NSDictionary * dict in dataArray) {
|
||||||
|
XJHealthCategoryModel * m = [XJHealthCategoryModel modelWithDictionary:dict];
|
||||||
|
[categories addObject:m];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (success) success(categories);
|
||||||
|
} else {
|
||||||
|
if (failure) failure(json[@"msg"] ?: @"获取栏目列表失败");
|
||||||
|
}
|
||||||
|
} failure:^(NSString * errorMsg) {
|
||||||
|
if (failure) failure(errorMsg);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— 分页查询文章 —————
|
||||||
|
|
||||||
|
- (void)getArticleListWithToken:(NSString *)token
|
||||||
|
categoryId:(NSInteger)categoryId
|
||||||
|
articleType:(NSString *)articleType
|
||||||
|
pageNum:(NSInteger)pageNum
|
||||||
|
pageSize:(NSInteger)pageSize
|
||||||
|
success:(void (^)(NSArray<XJHealthArticleModel *> *, NSInteger))success
|
||||||
|
failure:(void (^)(NSString *))failure {
|
||||||
|
|
||||||
|
NSMutableString * urlString = [NSMutableString stringWithFormat:@"%@%@", kHealthKnowledgeBaseURL, kHealthKnowledgeArticleListPath];
|
||||||
|
[urlString appendFormat:@"?categoryId=%ld&pageNum=%ld&pageSize=%ld&showAppHomepage=Y",
|
||||||
|
(long)categoryId, (long)pageNum, (long)pageSize];
|
||||||
|
|
||||||
|
if (!ValidStr(articleType)) {
|
||||||
|
[urlString appendFormat:@"&articleType=%@", articleType];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
|
||||||
|
request.HTTPMethod = @"GET";
|
||||||
|
[request setValue:token forHTTPHeaderField:@"token"];
|
||||||
|
|
||||||
|
[self sendRequest:request completion:^(NSDictionary * json) {
|
||||||
|
if ([json[@"code"] integerValue] == 200) {
|
||||||
|
NSArray * rows = json[@"rows"];
|
||||||
|
NSInteger total = [json[@"total"] integerValue];
|
||||||
|
NSMutableArray * articles = [[NSMutableArray alloc] init];
|
||||||
|
if ([rows isKindOfClass:[NSArray class]]) {
|
||||||
|
for (NSDictionary * dict in rows) {
|
||||||
|
XJHealthArticleModel * m = [XJHealthArticleModel modelWithDictionary:dict];
|
||||||
|
[articles addObject:m];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (success) success(articles, total);
|
||||||
|
} else {
|
||||||
|
if (failure) failure(json[@"msg"] ?: @"获取文章列表失败");
|
||||||
|
}
|
||||||
|
} failure:^(NSString * errorMsg) {
|
||||||
|
if (failure) failure(errorMsg);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— 通用请求 —————
|
||||||
|
|
||||||
|
- (void)sendRequest:(NSURLRequest *)request
|
||||||
|
completion:(void (^)(NSDictionary * json))completion
|
||||||
|
failure:(void (^)(NSString * errorMsg))failure {
|
||||||
|
|
||||||
|
DLog(@"[健康知识] >>> 请求: %@ %@", request.HTTPMethod, request.URL.absoluteString);
|
||||||
|
|
||||||
|
NSURLSession * session = [NSURLSession sharedSession];
|
||||||
|
NSURLSessionDataTask * task = [session dataTaskWithRequest:request
|
||||||
|
completionHandler:^(NSData * _Nullable data,
|
||||||
|
NSURLResponse * _Nullable response,
|
||||||
|
NSError * _Nullable error) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
if (error) {
|
||||||
|
DLog(@"[健康知识] <<< 网络错误: %@", error.localizedDescription);
|
||||||
|
if (failure) failure(error.localizedDescription);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSHTTPURLResponse * httpResp = (NSHTTPURLResponse *)response;
|
||||||
|
NSInteger statusCode = httpResp.statusCode;
|
||||||
|
DLog(@"[健康知识] <<< HTTP %ld", (long)statusCode);
|
||||||
|
|
||||||
|
if (statusCode != 200) {
|
||||||
|
NSString * msg = [NSString stringWithFormat:@"HTTP %ld", (long)statusCode];
|
||||||
|
DLog(@"[健康知识] <<< 请求失败: %@", msg);
|
||||||
|
if (failure) failure(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSError * jsonError = nil;
|
||||||
|
NSDictionary * json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
|
||||||
|
if (jsonError || ![json isKindOfClass:[NSDictionary class]]) {
|
||||||
|
DLog(@"[健康知识] <<< JSON 解析失败");
|
||||||
|
if (failure) failure(@"数据解析失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DLog(@"[健康知识] <<< 响应: %@", json);
|
||||||
|
if (completion) completion(json);
|
||||||
|
});
|
||||||
|
}];
|
||||||
|
[task resume];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -34,27 +34,28 @@
|
|||||||
object:nil];
|
object:nil];
|
||||||
|
|
||||||
|
|
||||||
//切换SOStabbar
|
//切换咨询tabbar
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
selector:@selector(tabBarSoSChange:)
|
selector:@selector(tabBarQuestionChange:)
|
||||||
name:KNotificSelectSoSTabbar
|
name:KNotificSelectQuestionTabbar
|
||||||
|
object:nil];
|
||||||
|
//切换应急tabbar
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(tabBarSOSChange:)
|
||||||
|
name:KNotificSelectSOSCenterTabbar
|
||||||
object:nil];
|
object:nil];
|
||||||
|
|
||||||
//切换体检tabbar
|
//切换监测tabbar
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
selector:@selector(tabBarPhyChange:)
|
selector:@selector(tabBarMonitoringChange:)
|
||||||
name:KNotificSelectPhysicalTabbar
|
name:KNotificSelectWatchTabbar
|
||||||
object:nil];
|
object:nil];
|
||||||
|
|
||||||
//切换档案tabbar
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
||||||
selector:@selector(tabBarFileChange:)
|
|
||||||
name:KNotificSelectFileTabbar
|
|
||||||
object:nil];
|
|
||||||
if ([HQCommonUtils isLogin]) {
|
if ([HQCommonUtils isLogin]) {
|
||||||
//腾讯im
|
//腾讯im
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
// [self loginImAccount];
|
[self loginImAccount];
|
||||||
|
|
||||||
#else
|
#else
|
||||||
[self loginImAccount];
|
[self loginImAccount];
|
||||||
@@ -159,6 +160,8 @@
|
|||||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||||
//更新用户授权高德SDK隐私协议状态. since 8.1.0
|
//更新用户授权高德SDK隐私协议状态. since 8.1.0
|
||||||
[MAMapView updatePrivacyAgree:AMapPrivacyAgreeStatusDidAgree];
|
[MAMapView updatePrivacyAgree:AMapPrivacyAgreeStatusDidAgree];
|
||||||
|
KPostNotification(KNotificAgreeProtoocl, nil);
|
||||||
|
|
||||||
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
@@ -167,6 +170,8 @@
|
|||||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||||
//更新用户授权高德SDK隐私协议状态. since 8.1.0
|
//更新用户授权高德SDK隐私协议状态. since 8.1.0
|
||||||
[MAMapView updatePrivacyAgree:AMapPrivacyAgreeStatusNotAgree];
|
[MAMapView updatePrivacyAgree:AMapPrivacyAgreeStatusNotAgree];
|
||||||
|
KPostNotification(KNotificAgreeProtoocl, nil);
|
||||||
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[alert addAction:conform];
|
[alert addAction:conform];
|
||||||
@@ -244,27 +249,24 @@
|
|||||||
|
|
||||||
|
|
||||||
#pragma mark: 切换tabbar
|
#pragma mark: 切换tabbar
|
||||||
- (void)tabBarSoSChange:(NSNotification *)notification {
|
- (void)tabBarQuestionChange:(NSNotification *)notification {
|
||||||
|
|
||||||
|
self.mainTabBar.selectedIndex = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tabBarSOSChange:(NSNotification *)notification {
|
||||||
|
|
||||||
self.mainTabBar.selectedIndex = 2;
|
self.mainTabBar.selectedIndex = 2;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)tabBarPhyChange:(NSNotification *)notification {
|
- (void)tabBarMonitoringChange:(NSNotification *)notification {
|
||||||
|
|
||||||
self.mainTabBar.selectedIndex = 3;
|
self.mainTabBar.selectedIndex = 3;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)tabBarFileChange:(NSNotification *)notification {
|
|
||||||
|
|
||||||
self.mainTabBar.selectedIndex = 4;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+ (AppDelegate *)shareAppDelegate{
|
+ (AppDelegate *)shareAppDelegate{
|
||||||
return (AppDelegate *)[[UIApplication sharedApplication] delegate];
|
return (AppDelegate *)[[UIApplication sharedApplication] delegate];
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#import "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
#import "SJRotationManager.h"
|
#import "SJRotationManager.h"
|
||||||
|
#import "XJWeChatManager.h"
|
||||||
#import <SDWebImageWebPCoder/SDWebImageWebPCoder.h>
|
#import <SDWebImageWebPCoder/SDWebImageWebPCoder.h>
|
||||||
|
|
||||||
@implementation AppDelegate
|
@implementation AppDelegate
|
||||||
@@ -34,13 +35,9 @@
|
|||||||
SDImageWebPCoder*webPCoder = [SDImageWebPCoder sharedCoder];
|
SDImageWebPCoder*webPCoder = [SDImageWebPCoder sharedCoder];
|
||||||
[[SDImageCodersManager sharedManager] addCoder:webPCoder];
|
[[SDImageCodersManager sharedManager] addCoder:webPCoder];
|
||||||
|
|
||||||
#if DEBUG
|
// 注册微信 SDK
|
||||||
|
[[XJWeChatManager sharedManager] registerWithAppID:kAppKey_Wechat
|
||||||
#else
|
universalLink:kUniversalLink_Wechat];
|
||||||
// [CheckProjectTool testAll];
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
@@ -62,6 +59,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
|
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
|
||||||
|
if (window == self.window) {
|
||||||
|
// 遍历找到最顶层的 presented VC
|
||||||
|
UIViewController *vc = self.window.rootViewController;
|
||||||
|
while (vc.presentedViewController) { vc = vc.presentedViewController; }
|
||||||
|
// WKWebView 视频全屏(WKFullScreenViewController)或 AVPlayer 全屏时放行横屏
|
||||||
|
NSString *className = NSStringFromClass(vc.class);
|
||||||
|
if ([className containsString:@"FullScreen"] || [className containsString:@"AVPlayer"]) {
|
||||||
|
return UIInterfaceOrientationMaskAllButUpsideDown;
|
||||||
|
}
|
||||||
|
return UIInterfaceOrientationMaskPortrait;
|
||||||
|
}
|
||||||
return [SJRotationManager supportedInterfaceOrientationsForWindow:window];
|
return [SJRotationManager supportedInterfaceOrientationsForWindow:window];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,10 +88,15 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
|
||||||
|
return [[XJWeChatManager sharedManager] handleOpenURL:url];
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void(^)(NSArray<id<UIUserActivityRestoring>> * __nullable restorableObjects))restorationHandler {
|
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void(^)(NSArray<id<UIUserActivityRestoring>> * __nullable restorableObjects))restorationHandler {
|
||||||
|
if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
|
||||||
|
return [[XJWeChatManager sharedManager] handleOpenUniversalLink:userActivity];
|
||||||
|
}
|
||||||
return YES;
|
return YES;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// PointsBankHModel.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/6.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface PointsBankHModel : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic, assign) double points;
|
||||||
|
@property (nonatomic, assign) double addPointsSum;
|
||||||
|
@property (nonatomic, assign) double exchangePointsSum;
|
||||||
|
|
||||||
|
//RANK
|
||||||
|
@property (nonatomic, assign) double frequency;
|
||||||
|
@property (nonatomic, assign) double ruleCategory;
|
||||||
|
@property (nonatomic, copy) NSString * ruleDesc;
|
||||||
|
@property (nonatomic, copy) NSString * icon;
|
||||||
|
@property (nonatomic, assign) double status;
|
||||||
|
@property (nonatomic, assign) double delFlag;
|
||||||
|
@property (nonatomic, copy) NSString * createUser;
|
||||||
|
@property (nonatomic, copy) NSString * createTime;
|
||||||
|
@property (nonatomic, copy) NSString * lastModifyDate;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
//
|
||||||
|
// PointsBankHModel.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/6.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "PointsBankHModel.h"
|
||||||
|
|
||||||
|
@implementation PointsBankHModel
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// PointsBankDetailViewController.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/6.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJBaseViewController.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface PointsBankDetailViewController : XJBaseViewController
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,263 @@
|
|||||||
|
//
|
||||||
|
// PointsBankDetailViewController.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/6.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "PointsBankDetailViewController.h"
|
||||||
|
#import "PointsBankHModel.h"
|
||||||
|
#import "PointsBankHomeTopView.h"
|
||||||
|
|
||||||
|
@interface PointsBankDetailViewController ()<UITableViewDelegate,UITableViewDataSource>
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UITableView * homeTable;
|
||||||
|
|
||||||
|
@property (nonatomic, assign) NSInteger pageNo;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) PointsBankHomeTopView * topView;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) NSMutableArray * dataArray;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation PointsBankDetailViewController
|
||||||
|
|
||||||
|
- (NSMutableArray *)dataArray {
|
||||||
|
if (!_dataArray) {
|
||||||
|
_dataArray = [[NSMutableArray alloc] init];
|
||||||
|
}
|
||||||
|
return _dataArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidLoad {
|
||||||
|
[super viewDidLoad];
|
||||||
|
self.view.backgroundColor = KWhiteColor;
|
||||||
|
self.pageNo = 1;
|
||||||
|
[self createData];
|
||||||
|
[self createUI];
|
||||||
|
// Do any additional setup after loading the view.
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)createUI {
|
||||||
|
|
||||||
|
self.topView= [[PointsBankHomeTopView alloc] init];
|
||||||
|
|
||||||
|
[self.view addSubview:self.topView];
|
||||||
|
|
||||||
|
[self.topView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.top.right.mas_offset(0);
|
||||||
|
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
self.homeTable = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
|
||||||
|
if ([[UIDevice currentDevice].systemVersion floatValue] >= 11) {
|
||||||
|
self.homeTable.estimatedRowHeight = 60;
|
||||||
|
if (@available(iOS 15.0, *)) {
|
||||||
|
self.homeTable.sectionHeaderTopPadding = 0;
|
||||||
|
} else {
|
||||||
|
// Fallback on earlier versions
|
||||||
|
}
|
||||||
|
self.homeTable.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||||
|
}
|
||||||
|
self.homeTable.delegate = self;
|
||||||
|
self.homeTable.dataSource = self;
|
||||||
|
self.homeTable.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
|
||||||
|
self.homeTable.showsVerticalScrollIndicator = NO;
|
||||||
|
self.homeTable.backgroundColor = KClearColor;
|
||||||
|
self.homeTable.rowHeight = UITableViewAutomaticDimension;
|
||||||
|
self.homeTable.estimatedRowHeight = 80;
|
||||||
|
|
||||||
|
|
||||||
|
[self.view addSubview:self.homeTable];
|
||||||
|
|
||||||
|
[self.homeTable mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.mas_equalTo(_topView.mas_bottom);
|
||||||
|
make.left.bottom.right.mas_offset(0);
|
||||||
|
|
||||||
|
}];
|
||||||
|
|
||||||
|
__weak __typeof(self) weakSelf = self;
|
||||||
|
self.homeTable.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
||||||
|
|
||||||
|
weakSelf.pageNo = 1;
|
||||||
|
[weakSelf.dataArray removeAllObjects];
|
||||||
|
[weakSelf createData];
|
||||||
|
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.homeTable.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{
|
||||||
|
|
||||||
|
weakSelf.pageNo++;
|
||||||
|
[weakSelf createData];
|
||||||
|
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
LYEmptyView *emptyView = [LYEmptyView emptyViewWithImageStr:@"noDataBox" titleStr:@"暂无数据" detailStr:@""];
|
||||||
|
//元素竖直方向的间距
|
||||||
|
emptyView.subViewMargin = 20.f;
|
||||||
|
//标题颜色
|
||||||
|
emptyView.titleLabTextColor = [UIColor blackColor];
|
||||||
|
//描述字体
|
||||||
|
emptyView.detailLabFont = [UIFont systemFontOfSize:17];
|
||||||
|
//按钮背景色
|
||||||
|
emptyView.actionBtnBackGroundColor = KWhiteColor;
|
||||||
|
emptyView.actionBtnWidth = CGFLOAT_MIN;
|
||||||
|
emptyView.actionBtnHeight = CGFLOAT_MIN;
|
||||||
|
//设置空内容占位图
|
||||||
|
self.homeTable.ly_emptyView = emptyView;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)createData {
|
||||||
|
|
||||||
|
[self showMBProgressHUDWithString:@"加载中,请稍候..." autoHidden:false];
|
||||||
|
NSMutableDictionary * parmDic = [[NSMutableDictionary alloc] init];
|
||||||
|
[parmDic setObject:@(self.pageNo) forKey:@"pageNo"];
|
||||||
|
[parmDic setObject:@"10" forKey:@"pageSize"];
|
||||||
|
|
||||||
|
XJPNetAPI * listApi = [[XJPNetAPI alloc] init:self tag:@"LIST" NeedToken:@""];
|
||||||
|
[listApi getUserMessageList:parmDic];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - DataSource
|
||||||
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||||
|
{
|
||||||
|
|
||||||
|
return self.dataArray.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
|
||||||
|
return UITableViewCell.new;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat )tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
|
||||||
|
{
|
||||||
|
return CGFLOAT_MIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat )tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
|
||||||
|
{
|
||||||
|
return CGFLOAT_MIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
|
||||||
|
|
||||||
|
return UIView.new;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)chageDataType:(UIButton *)typeBtn {
|
||||||
|
|
||||||
|
//请求接口
|
||||||
|
if (typeBtn.tag == 0) {
|
||||||
|
[self creeateRankDataWithTyep:@"1"];
|
||||||
|
}
|
||||||
|
if (typeBtn.tag == 1) {
|
||||||
|
[self creeateRankDataWithTyep:@"2"];
|
||||||
|
}
|
||||||
|
if (typeBtn.tag == 2) {
|
||||||
|
[self creeateRankDataWithTyep:@"0"];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)creeateRankDataWithTyep:(NSString *)type {
|
||||||
|
|
||||||
|
//rankType(榜单类型,0总榜,1周榜,2月榜)
|
||||||
|
[self showMBProgressHUDWithString:@"加载中,请稍候..." autoHidden:false];
|
||||||
|
|
||||||
|
NSMutableDictionary * parmDic = [[NSMutableDictionary alloc] init];
|
||||||
|
[parmDic setObject:@(self.pageNo) forKey:@"pageNo"];
|
||||||
|
[parmDic setObject:@"10" forKey:@"pageSize"];
|
||||||
|
[parmDic setObject:type forKey:@"rankType"];
|
||||||
|
|
||||||
|
|
||||||
|
XJPNetAPI * listApi = [[XJPNetAPI alloc] init:self tag:@"DETAIL" NeedToken:@""];
|
||||||
|
[listApi postPointsBankSourceDetail:parmDic];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)Failed:(NSString*)message tag:(NSString*)tag
|
||||||
|
{
|
||||||
|
|
||||||
|
[self.homeTable.mj_header endRefreshing];
|
||||||
|
[self.homeTable.mj_footer endRefreshing];
|
||||||
|
|
||||||
|
[self hiddenAllMBProgressHUD];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)Sucess:(id)response tag:(NSString*)tag
|
||||||
|
{
|
||||||
|
[self.homeTable.mj_header endRefreshing];
|
||||||
|
[self.homeTable.mj_footer endRefreshing];
|
||||||
|
if ([tag isEqualToString:@"DETAIL"]) {
|
||||||
|
|
||||||
|
[self hiddenAllMBProgressHUD];
|
||||||
|
NSDictionary * responseDic = response;
|
||||||
|
|
||||||
|
PointsBankHModel * model = [PointsBankHModel modelWithDictionary:responseDic];
|
||||||
|
//points 可用积分 addPointsSum 累计积分 exchangePointsSum 累计兑换
|
||||||
|
self.topView.model = model;
|
||||||
|
|
||||||
|
}
|
||||||
|
if ([tag isEqualToString:@"RANK"]) {
|
||||||
|
NSDictionary * dic = response;
|
||||||
|
if ([dic.allKeys containsObject:@"page"]) {
|
||||||
|
NSDictionary * pageDic = [dic objectForKey:@"page"];
|
||||||
|
//取到排名
|
||||||
|
if ([pageDic.allKeys containsObject:@"records"]) {
|
||||||
|
NSArray * array = [pageDic objectForKey:@"records"];
|
||||||
|
for (NSDictionary * rankDic in array) {
|
||||||
|
PointsBankHModel * mdoel = [PointsBankHModel modelWithDictionary:rankDic];
|
||||||
|
[self.dataArray addObject:mdoel];
|
||||||
|
|
||||||
|
}
|
||||||
|
//处理结束 给数据
|
||||||
|
[self.homeTable reloadData];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
#pragma mark - Navigation
|
||||||
|
|
||||||
|
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||||
|
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||||
|
// Get the new view controller using [segue destinationViewController].
|
||||||
|
// Pass the selected object to the new view controller.
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// PointsBankHomeTopView.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/6.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import "PointsBankHModel.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface PointsBankHomeTopView : UIView
|
||||||
|
|
||||||
|
@property (nonatomic, strong) PointsBankHModel * model;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
//
|
||||||
|
// PointsBankHomeTopView.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/6.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "PointsBankHomeTopView.h"
|
||||||
|
|
||||||
|
@interface PointsBankHomeTopView ()
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UILabel * pointsDataLabel;
|
||||||
|
@property (nonatomic, strong) UILabel * pointsAddLabel;
|
||||||
|
@property (nonatomic, strong) UILabel * exchangeLabel;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation PointsBankHomeTopView
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Only override drawRect: if you perform custom drawing.
|
||||||
|
// An empty implementation adversely affects performance during animation.
|
||||||
|
- (void)drawRect:(CGRect)rect {
|
||||||
|
// Drawing code
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame {
|
||||||
|
|
||||||
|
if (self = [super initWithFrame:frame]) {
|
||||||
|
|
||||||
|
[self createUI];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)createUI {
|
||||||
|
|
||||||
|
UILabel * haveLab = [[UILabel alloc] init];
|
||||||
|
haveLab.text = @"可用积分";
|
||||||
|
haveLab.textColor = CFontColor1;
|
||||||
|
haveLab.font = [UIFont systemFontOfSize:13 weight:UIFontWeightRegular];
|
||||||
|
[self addSubview:haveLab];
|
||||||
|
|
||||||
|
[haveLab mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(15);
|
||||||
|
make.top.mas_offset(15);
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.pointsDataLabel = [[UILabel alloc] init];
|
||||||
|
self.pointsDataLabel.text = @"--";
|
||||||
|
self.pointsDataLabel.textColor = CFontColor1;
|
||||||
|
self.pointsDataLabel.font = [UIFont systemFontOfSize:28 weight:UIFontWeightBold];
|
||||||
|
[self addSubview:self.pointsDataLabel];
|
||||||
|
|
||||||
|
[self.pointsDataLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_equalTo(haveLab);
|
||||||
|
make.top.mas_equalTo(haveLab.mas_bottom).offset(12);
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
UIButton * sourceBtn = [[UIButton alloc] init];
|
||||||
|
[sourceBtn setTitle:@"获取积分" forState:UIControlStateNormal];
|
||||||
|
[sourceBtn setTitleColor:KWhiteColor forState:UIControlStateNormal];
|
||||||
|
sourceBtn.titleLabel.font = SYSTEMFONT(15);
|
||||||
|
sourceBtn.layer.cornerRadius = 4;
|
||||||
|
sourceBtn.layer.masksToBounds = true;
|
||||||
|
sourceBtn.backgroundColor = UIColorHex(#21BEBE);
|
||||||
|
[self addSubview:sourceBtn];
|
||||||
|
|
||||||
|
[sourceBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.mas_offset(-15);
|
||||||
|
make.width.mas_offset(80);
|
||||||
|
make.height.mas_offset(32);
|
||||||
|
make.top.mas_offset(53);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UILabel * addLab = [[UILabel alloc] init];
|
||||||
|
addLab.text = @"累计积分:";
|
||||||
|
addLab.textColor = CFontColor1;
|
||||||
|
addLab.font = [UIFont systemFontOfSize:13 weight:UIFontWeightRegular];
|
||||||
|
self.pointsAddLabel = addLab;
|
||||||
|
[self addSubview:addLab];
|
||||||
|
|
||||||
|
[addLab mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_equalTo(haveLab.mas_right).offset(81);
|
||||||
|
make.top.mas_equalTo(haveLab.mas_bottom).offset(11);
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.exchangeLabel = [[UILabel alloc] init];
|
||||||
|
self.exchangeLabel.text = @"累计兑换:";
|
||||||
|
self.exchangeLabel.textColor = CFontColor1;
|
||||||
|
self.exchangeLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightRegular];
|
||||||
|
[self addSubview:self.exchangeLabel];
|
||||||
|
|
||||||
|
[self.exchangeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_equalTo(haveLab.mas_right).offset(81);
|
||||||
|
make.top.mas_equalTo(addLab.mas_bottom).offset(11);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UIView *dashedView = [[UIView alloc] init];
|
||||||
|
[self addSubview:dashedView];
|
||||||
|
|
||||||
|
// Masonry 布局
|
||||||
|
[dashedView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_equalTo(20);
|
||||||
|
make.right.mas_equalTo(-20);
|
||||||
|
make.top.mas_equalTo(self.pointsDataLabel.mas_bottom).offset(10);
|
||||||
|
make.height.mas_equalTo(1); // 高度可以随意
|
||||||
|
make.bottom.mas_equalTo(-10);
|
||||||
|
}];
|
||||||
|
//虚线
|
||||||
|
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
|
||||||
|
shapeLayer.strokeColor = [UIColor lightGrayColor].CGColor; // 线颜色
|
||||||
|
shapeLayer.lineWidth = 1; // 线宽
|
||||||
|
shapeLayer.lineDashPattern = @[@4, @2]; // 虚线:4pt 实线,2pt 空白
|
||||||
|
|
||||||
|
// 创建路径
|
||||||
|
CGMutablePathRef path = CGPathCreateMutable();
|
||||||
|
CGPathMoveToPoint(path, NULL, 0, 0); // 起点
|
||||||
|
CGPathAddLineToPoint(path, NULL, [UIScreen mainScreen].bounds.size.width - 40, 0); // 终点
|
||||||
|
shapeLayer.path = path;
|
||||||
|
CGPathRelease(path);
|
||||||
|
|
||||||
|
// 添加到 view
|
||||||
|
[dashedView.layer addSublayer:shapeLayer];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-(void)setModel:(PointsBankHModel *)model {
|
||||||
|
|
||||||
|
_model = model;
|
||||||
|
|
||||||
|
self.pointsDataLabel.text = [NSString stringWithFormat:@"%.0f",_model.points];
|
||||||
|
|
||||||
|
self.pointsAddLabel.text = [NSString stringWithFormat:@"累计积分:%.0f",_model.addPointsSum];
|
||||||
|
|
||||||
|
self.exchangeLabel.text = [NSString stringWithFormat:@"累计兑换%.0f",_model.exchangePointsSum];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
@end
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// myPointsBankHomeViewController.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/6.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJBaseViewController.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface myPointsBankHomeViewController : XJBaseViewController
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,439 @@
|
|||||||
|
//
|
||||||
|
// myPointsBankHomeViewController.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/6.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "myPointsBankHomeViewController.h"
|
||||||
|
#import "PointsBankHModel.h"
|
||||||
|
#import "PointsBankHomeTopView.h"
|
||||||
|
|
||||||
|
@interface myPointsBankHomeViewController ()<UITableViewDelegate,UITableViewDataSource>
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UITableView * homeTable;
|
||||||
|
@property (nonatomic, assign) NSInteger pageNo;
|
||||||
|
@property (nonatomic, strong) NSMutableArray * dataArray;
|
||||||
|
@property (nonatomic, strong) NSMutableArray * buttonArray;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) PointsBankHomeTopView * topView;
|
||||||
|
@property (nonatomic, strong) UIView * lineView;
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation myPointsBankHomeViewController
|
||||||
|
|
||||||
|
- (NSMutableArray *)dataArray {
|
||||||
|
|
||||||
|
if (!_dataArray ) {
|
||||||
|
_dataArray = [[NSMutableArray alloc] init];
|
||||||
|
}
|
||||||
|
return _dataArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSMutableArray *)buttonArray {
|
||||||
|
|
||||||
|
if (!_buttonArray ) {
|
||||||
|
_buttonArray = [[NSMutableArray alloc] init];
|
||||||
|
}
|
||||||
|
return _buttonArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)viewDidLoad {
|
||||||
|
[super viewDidLoad];
|
||||||
|
// Do any additional setup after loading the view.
|
||||||
|
self.isHidenNaviBar = false;
|
||||||
|
self.navigationItem.title = @"我的积分银行";
|
||||||
|
|
||||||
|
[self createData];
|
||||||
|
//默认总榜单
|
||||||
|
[self creeateRankDataWithTyep:@"0"];
|
||||||
|
[self createUI];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)createUI {
|
||||||
|
|
||||||
|
//首页
|
||||||
|
self.topView = [[PointsBankHomeTopView alloc] init];
|
||||||
|
[self.view addSubview:self.topView];
|
||||||
|
|
||||||
|
[self.topView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.top.mas_offset(0);
|
||||||
|
// make.height.mas_offset(185);
|
||||||
|
}];
|
||||||
|
|
||||||
|
//功能栏
|
||||||
|
NSArray * toolsArray = @[@[@"积分兑换",@"img1"],@[@"积分明细",@"img2"],@[@"兑换记录",@"img3"]];
|
||||||
|
|
||||||
|
CGFloat itemWidth = 60;
|
||||||
|
CGFloat itemHeight = 110;
|
||||||
|
NSInteger count = toolsArray.count;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
|
||||||
|
NSArray *item = toolsArray[i];
|
||||||
|
|
||||||
|
// 1️⃣ 容器 view
|
||||||
|
UIView *itemView = [[UIView alloc] init];
|
||||||
|
itemView.tag = i;
|
||||||
|
itemView.userInteractionEnabled = YES;
|
||||||
|
[self.view addSubview:itemView];
|
||||||
|
|
||||||
|
// 2️⃣ 点击手势
|
||||||
|
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(itemTap:)];
|
||||||
|
[itemView addGestureRecognizer:tap];
|
||||||
|
|
||||||
|
// 3️⃣ 布局 container(每个 item 占 1/3 屏幕宽)
|
||||||
|
CGFloat thirdWidth = UIScreen.mainScreen.bounds.size.width / count;
|
||||||
|
|
||||||
|
[itemView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.mas_equalTo(self.topView.mas_bottom).offset(20);
|
||||||
|
make.width.mas_equalTo(itemWidth);
|
||||||
|
make.height.mas_equalTo(itemHeight);
|
||||||
|
make.centerX.mas_equalTo(self.view.mas_left).offset(thirdWidth * i + thirdWidth / 2);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 4️⃣ 图片
|
||||||
|
UIImageView *icon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:item[1]]];
|
||||||
|
icon.contentMode = UIViewContentModeScaleAspectFit;
|
||||||
|
[itemView addSubview:icon];
|
||||||
|
|
||||||
|
[icon mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.mas_equalTo(0);
|
||||||
|
make.centerX.equalTo(itemView);
|
||||||
|
make.width.height.mas_equalTo(40);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 5️⃣ 文字
|
||||||
|
UILabel *label = [[UILabel alloc] init];
|
||||||
|
label.text = item[0];
|
||||||
|
label.font = [UIFont systemFontOfSize:14];
|
||||||
|
label.textAlignment = NSTextAlignmentCenter;
|
||||||
|
[itemView addSubview:label];
|
||||||
|
|
||||||
|
[label mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.equalTo(icon.mas_bottom).offset(8);
|
||||||
|
make.left.right.equalTo(itemView);
|
||||||
|
make.height.mas_equalTo(20);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
//排行
|
||||||
|
UIView * rankView = [[UIView alloc] init];
|
||||||
|
rankView.backgroundColor = KWhiteColor;
|
||||||
|
[self.view addSubview:rankView];
|
||||||
|
|
||||||
|
|
||||||
|
UILabel * rankTitleLab = [[UILabel alloc] init];
|
||||||
|
rankTitleLab.text = @"积分排行(单位)";
|
||||||
|
rankTitleLab.textColor = CFontColor1;
|
||||||
|
[rankView addSubview:rankTitleLab];
|
||||||
|
|
||||||
|
[rankTitleLab mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(15);
|
||||||
|
make.top.mas_offset(15);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UILabel * detailLab = [[UILabel alloc] init];
|
||||||
|
detailLab.text = @"以员工累计获得积分进行排名";
|
||||||
|
detailLab.textColor = CFontColor1;
|
||||||
|
[rankView addSubview:detailLab];
|
||||||
|
|
||||||
|
[detailLab mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(15);
|
||||||
|
make.top.mas_equalTo(rankTitleLab.mas_bottom).offset(8);
|
||||||
|
}];
|
||||||
|
|
||||||
|
//周排名 月排名 年排名
|
||||||
|
UIView * lineView = [[UIView alloc] init];
|
||||||
|
lineView.backgroundColor = UIColor.blueColor;
|
||||||
|
self.lineView = lineView;
|
||||||
|
[rankView addSubview:lineView];
|
||||||
|
|
||||||
|
[lineView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.width.mas_offset(80);
|
||||||
|
make.height.mas_offset(2);
|
||||||
|
}];
|
||||||
|
|
||||||
|
NSArray * array = @[@"周排名",@"月排名",@"年排名"];
|
||||||
|
UIButton * lastBtn = nil;
|
||||||
|
for (int i= 0; i < 3; i ++) {
|
||||||
|
|
||||||
|
UIButton * btn = [[UIButton alloc] init];
|
||||||
|
[btn setTitle:array[i] forState:UIControlStateNormal];
|
||||||
|
[btn setTitleColor:UIColor.blueColor forState:UIControlStateSelected];
|
||||||
|
[btn setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
|
||||||
|
btn.titleLabel.font = MEDIUMFONT(13);
|
||||||
|
btn.tag = i;
|
||||||
|
[btn addTarget:self action:@selector(chageDataType:) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
btn.selected = false;
|
||||||
|
if (i == 2) {
|
||||||
|
btn.selected = true;
|
||||||
|
lastBtn = btn;
|
||||||
|
|
||||||
|
}
|
||||||
|
[rankView addSubview:btn];
|
||||||
|
|
||||||
|
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.width.mas_offset(80);
|
||||||
|
make.height.mas_offset(32);
|
||||||
|
make.top.mas_equalTo(detailLab.mas_bottom).offset(10);
|
||||||
|
if (i == 0) {
|
||||||
|
make.left.mas_offset(82);
|
||||||
|
}
|
||||||
|
if (i == 1) {
|
||||||
|
make.centerX.mas_equalTo(rankView);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (i == 2) {
|
||||||
|
make.right.mas_offset(-82);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
[self.buttonArray addObject:btn];
|
||||||
|
|
||||||
|
}
|
||||||
|
if (lastBtn) {
|
||||||
|
[lineView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.centerX.mas_equalTo(lastBtn);
|
||||||
|
make.top.mas_equalTo(lastBtn.mas_bottom).offset(5);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
[rankView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.mas_offset(0);
|
||||||
|
make.top.mas_equalTo(self.topView.mas_bottom).offset(15);
|
||||||
|
make.bottom.mas_equalTo(lastBtn.mas_bottom).offset(20);
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.homeTable = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
|
||||||
|
if ([[UIDevice currentDevice].systemVersion floatValue] >= 11) {
|
||||||
|
self.homeTable.estimatedRowHeight = 60;
|
||||||
|
if (@available(iOS 15.0, *)) {
|
||||||
|
self.homeTable.sectionHeaderTopPadding = 0;
|
||||||
|
} else {
|
||||||
|
// Fallback on earlier versions
|
||||||
|
}
|
||||||
|
self.homeTable.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||||
|
}
|
||||||
|
self.homeTable.delegate = self;
|
||||||
|
self.homeTable.dataSource = self;
|
||||||
|
self.homeTable.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
|
||||||
|
self.homeTable.showsVerticalScrollIndicator = NO;
|
||||||
|
self.homeTable.backgroundColor = KClearColor;
|
||||||
|
self.homeTable.rowHeight = UITableViewAutomaticDimension;
|
||||||
|
self.homeTable.estimatedRowHeight = 80;
|
||||||
|
|
||||||
|
|
||||||
|
[self.view addSubview:self.homeTable];
|
||||||
|
|
||||||
|
[self.homeTable mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.mas_equalTo(rankView.mas_bottom);
|
||||||
|
make.left.bottom.right.mas_offset(0);
|
||||||
|
|
||||||
|
}];
|
||||||
|
|
||||||
|
__weak __typeof(self) weakSelf = self;
|
||||||
|
self.homeTable.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
||||||
|
|
||||||
|
weakSelf.pageNo = 1;
|
||||||
|
[weakSelf.dataArray removeAllObjects];
|
||||||
|
[weakSelf createData];
|
||||||
|
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.homeTable.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{
|
||||||
|
|
||||||
|
weakSelf.pageNo++;
|
||||||
|
[weakSelf createData];
|
||||||
|
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
LYEmptyView *emptyView = [LYEmptyView emptyViewWithImageStr:@"noDataBox" titleStr:@"暂无数据" detailStr:@""];
|
||||||
|
//元素竖直方向的间距
|
||||||
|
emptyView.subViewMargin = 20.f;
|
||||||
|
//标题颜色
|
||||||
|
emptyView.titleLabTextColor = [UIColor blackColor];
|
||||||
|
//描述字体
|
||||||
|
emptyView.detailLabFont = [UIFont systemFontOfSize:17];
|
||||||
|
//按钮背景色
|
||||||
|
emptyView.actionBtnBackGroundColor = KWhiteColor;
|
||||||
|
emptyView.actionBtnWidth = CGFLOAT_MIN;
|
||||||
|
emptyView.actionBtnHeight = CGFLOAT_MIN;
|
||||||
|
//设置空内容占位图
|
||||||
|
self.homeTable.ly_emptyView = emptyView;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)createData {
|
||||||
|
|
||||||
|
[self showMBProgressHUDWithString:@"加载中,请稍候..." autoHidden:false];
|
||||||
|
NSMutableDictionary * parmDic = [[NSMutableDictionary alloc] init];
|
||||||
|
XJPNetAPI * listApi = [[XJPNetAPI alloc] init:self tag:@"HEARD" NeedToken:@""];
|
||||||
|
[listApi getPointsBankHeard:parmDic];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - DataSource
|
||||||
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||||
|
{
|
||||||
|
|
||||||
|
return self.dataArray.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
|
||||||
|
return UITableViewCell.new;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat )tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
|
||||||
|
{
|
||||||
|
return CGFLOAT_MIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat )tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
|
||||||
|
{
|
||||||
|
return CGFLOAT_MIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
|
||||||
|
|
||||||
|
return UIView.new;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)chageDataType:(UIButton *)typeBtn {
|
||||||
|
|
||||||
|
for (UIButton * seleBtn in self.buttonArray) {
|
||||||
|
if (seleBtn == typeBtn) {
|
||||||
|
seleBtn.selected = true;
|
||||||
|
|
||||||
|
[self.lineView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.mas_equalTo(typeBtn);
|
||||||
|
make.bottom.mas_equalTo(typeBtn.mas_bottom).offset(8);
|
||||||
|
make.height.mas_offset(1);
|
||||||
|
make.centerX.mas_equalTo(typeBtn);
|
||||||
|
}];
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
seleBtn.selected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//请求接口
|
||||||
|
if (typeBtn.tag == 0) {
|
||||||
|
[self creeateRankDataWithTyep:@"1"];
|
||||||
|
}
|
||||||
|
if (typeBtn.tag == 1) {
|
||||||
|
[self creeateRankDataWithTyep:@"2"];
|
||||||
|
}
|
||||||
|
if (typeBtn.tag == 2) {
|
||||||
|
[self creeateRankDataWithTyep:@"0"];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)creeateRankDataWithTyep:(NSString *)type {
|
||||||
|
|
||||||
|
//rankType(榜单类型,0总榜,1周榜,2月榜)
|
||||||
|
[self showMBProgressHUDWithString:@"加载中,请稍候..." autoHidden:false];
|
||||||
|
|
||||||
|
NSMutableDictionary * parmDic = [[NSMutableDictionary alloc] init];
|
||||||
|
[parmDic setObject:@(self.pageNo) forKey:@"pageNo"];
|
||||||
|
[parmDic setObject:@"10" forKey:@"pageSize"];
|
||||||
|
[parmDic setObject:type forKey:@"rankType"];
|
||||||
|
|
||||||
|
|
||||||
|
XJPNetAPI * listApi = [[XJPNetAPI alloc] init:self tag:@"RANK" NeedToken:@""];
|
||||||
|
[listApi postPointsBankRankData:parmDic];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)Failed:(NSString*)message tag:(NSString*)tag
|
||||||
|
{
|
||||||
|
|
||||||
|
[self.homeTable.mj_header endRefreshing];
|
||||||
|
[self.homeTable.mj_footer endRefreshing];
|
||||||
|
|
||||||
|
[self hiddenAllMBProgressHUD];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)Sucess:(id)response tag:(NSString*)tag
|
||||||
|
{
|
||||||
|
[self.homeTable.mj_header endRefreshing];
|
||||||
|
[self.homeTable.mj_footer endRefreshing];
|
||||||
|
if ([tag isEqualToString:@"HEARD"]) {
|
||||||
|
|
||||||
|
[self hiddenAllMBProgressHUD];
|
||||||
|
NSDictionary * responseDic = response;
|
||||||
|
|
||||||
|
PointsBankHModel * model = [PointsBankHModel modelWithDictionary:responseDic];
|
||||||
|
//points 可用积分 addPointsSum 累计积分 exchangePointsSum 累计兑换
|
||||||
|
self.topView.model = model;
|
||||||
|
|
||||||
|
}
|
||||||
|
if ([tag isEqualToString:@"RANK"]) {
|
||||||
|
NSDictionary * dic = response;
|
||||||
|
if ([dic.allKeys containsObject:@"page"]) {
|
||||||
|
NSDictionary * pageDic = [dic objectForKey:@"page"];
|
||||||
|
//取到排名
|
||||||
|
if ([pageDic.allKeys containsObject:@"records"]) {
|
||||||
|
NSArray * array = [pageDic objectForKey:@"records"];
|
||||||
|
for (NSDictionary * rankDic in array) {
|
||||||
|
PointsBankHModel * mdoel = [PointsBankHModel modelWithDictionary:rankDic];
|
||||||
|
[self.dataArray addObject:mdoel];
|
||||||
|
|
||||||
|
}
|
||||||
|
//处理结束 给数据
|
||||||
|
[self.homeTable reloadData];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)itemTap:(UITapGestureRecognizer *)tap {
|
||||||
|
NSInteger index = tap.view.tag;
|
||||||
|
NSLog(@"点击了第 %ld 个", index);
|
||||||
|
|
||||||
|
if(index == 1 || index == 2) {
|
||||||
|
[EasyTextView showInfoText:@"开发者,敬请期待!"];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
#pragma mark - Navigation
|
||||||
|
|
||||||
|
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||||
|
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||||
|
// Get the new view controller using [segue destinationViewController].
|
||||||
|
// Pass the selected object to the new view controller.
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@@ -14,7 +14,9 @@
|
|||||||
#import "XJSosCenterViewController.h"
|
#import "XJSosCenterViewController.h"
|
||||||
#import "MonitoringWarchViewController.h"
|
#import "MonitoringWarchViewController.h"
|
||||||
|
|
||||||
//干预二期
|
//新版首页
|
||||||
|
#import "XJHomePageV2ViewController.h"
|
||||||
|
|
||||||
|
|
||||||
@interface XJBaseTabBarController ()<UITabBarControllerDelegate>
|
@interface XJBaseTabBarController ()<UITabBarControllerDelegate>
|
||||||
|
|
||||||
@@ -39,8 +41,6 @@
|
|||||||
- (void)viewDidLoad {
|
- (void)viewDidLoad {
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
self.delegate = self;
|
self.delegate = self;
|
||||||
|
|
||||||
|
|
||||||
//初始化tabbar
|
//初始化tabbar
|
||||||
[self setUpTabBar];
|
[self setUpTabBar];
|
||||||
//添加子控制器
|
//添加子控制器
|
||||||
@@ -73,6 +73,11 @@
|
|||||||
-(void)setUpAllChildViewController{
|
-(void)setUpAllChildViewController{
|
||||||
_VCS = @[].mutableCopy;
|
_VCS = @[].mutableCopy;
|
||||||
|
|
||||||
|
//新增首页
|
||||||
|
|
||||||
|
XJHomePageV2ViewController * homeVC = [[XJHomePageV2ViewController alloc]init];
|
||||||
|
[self setupChildViewController:homeVC title:@"首页" imageName:@"xjHomeTabBar_nomal" seleceImageName:@"xjHomeTabBar_selected"];
|
||||||
|
|
||||||
QuestionViewController * questionVC = [[QuestionViewController alloc]init];
|
QuestionViewController * questionVC = [[QuestionViewController alloc]init];
|
||||||
[self setupChildViewController:questionVC title:@"咨询" imageName:@"questionTabBar_nomal" seleceImageName:@"questionTabBar_selected"];
|
[self setupChildViewController:questionVC title:@"咨询" imageName:@"questionTabBar_nomal" seleceImageName:@"questionTabBar_selected"];
|
||||||
|
|
||||||
@@ -141,6 +146,10 @@
|
|||||||
return [self.selectedViewController supportedInterfaceOrientations];
|
return [self.selectedViewController supportedInterfaceOrientations];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)selectedQuestion {
|
||||||
|
|
||||||
|
self.selectedIndex = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#pragma mark - Navigation
|
#pragma mark - Navigation
|
||||||
|
|||||||
@@ -9,15 +9,42 @@
|
|||||||
|
|
||||||
@interface XJBaseWebViewVC ()<UINavigationControllerDelegate, UIImagePickerControllerDelegate>
|
@interface XJBaseWebViewVC ()<UINavigationControllerDelegate, UIImagePickerControllerDelegate>
|
||||||
|
|
||||||
@property (nonatomic, strong)NSURL *originalUrl;
|
// 以下三个属性声明后未使用,暂时保留
|
||||||
@property (nonatomic, copy)NSString *videoUrl;
|
//@property (nonatomic, strong)NSURL *originalUrl;
|
||||||
@property (nonatomic, copy)NSString *messageType;
|
//@property (nonatomic, copy)NSString *videoUrl;
|
||||||
|
//@property (nonatomic, copy)NSString *messageType;
|
||||||
|
|
||||||
|
/// 网页加载进度条
|
||||||
|
@property (nonatomic, strong) UIProgressView *progressView;
|
||||||
|
/// 加载失败占位视图
|
||||||
|
@property (nonatomic, strong) UIView *errorView;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation XJBaseWebViewVC
|
// ── 弱引用代理 ──────────────────────────────────────────────────────────────
|
||||||
|
// WKUserContentController 对 addScriptMessageHandler 的 handler 是强引用。
|
||||||
|
// 如果直接传 self,self → wkWebView → configuration → userContentController → self,
|
||||||
|
// 形成循环引用,VC 永远无法释放。
|
||||||
|
// 解决方案:用一个弱引用中间对象转发消息。
|
||||||
|
@interface XJWeakScriptMessageHandler : NSObject <WKScriptMessageHandler>
|
||||||
|
@property (nonatomic, weak) id<WKScriptMessageHandler> delegate;
|
||||||
|
+ (instancetype)handlerWithDelegate:(id<WKScriptMessageHandler>)delegate;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation XJWeakScriptMessageHandler
|
||||||
|
+ (instancetype)handlerWithDelegate:(id<WKScriptMessageHandler>)delegate {
|
||||||
|
XJWeakScriptMessageHandler *handler = [[XJWeakScriptMessageHandler alloc] init];
|
||||||
|
handler.delegate = delegate;
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
- (void)userContentController:(WKUserContentController *)userContentController
|
||||||
|
didReceiveScriptMessage:(WKScriptMessage *)message {
|
||||||
|
[self.delegate userContentController:userContentController didReceiveScriptMessage:message];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
// ────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@implementation XJBaseWebViewVC
|
||||||
|
|
||||||
#pragma mark - LifeCycle
|
#pragma mark - LifeCycle
|
||||||
- (void)viewDidLoad {
|
- (void)viewDidLoad {
|
||||||
@@ -36,6 +63,16 @@
|
|||||||
[self.navigationController popViewControllerAnimated:YES];
|
[self.navigationController popViewControllerAnimated:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
// 移除进度条 KVO
|
||||||
|
[self.wkWebView removeObserver:self forKeyPath:@"estimatedProgress"];
|
||||||
|
// 移除所有 scriptMessageHandler,配合 XJWeakScriptMessageHandler 彻底避免内存泄漏
|
||||||
|
WKUserContentController *ucc = self.wkWebView.configuration.userContentController;
|
||||||
|
[ucc removeScriptMessageHandlerForName:@"JSCallback"];
|
||||||
|
[ucc removeScriptMessageHandlerForName:@"htmlBack"];
|
||||||
|
[ucc removeScriptMessageHandlerForName:@"finishActivity"];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)viewWillAppear:(BOOL)animated{
|
- (void)viewWillAppear:(BOOL)animated{
|
||||||
[super viewWillAppear:animated];
|
[super viewWillAppear:animated];
|
||||||
if (_wkWebView) {
|
if (_wkWebView) {
|
||||||
@@ -51,14 +88,14 @@
|
|||||||
[super viewWillDisappear:animated];
|
[super viewWillDisappear:animated];
|
||||||
_wkWebView.navigationDelegate = nil;
|
_wkWebView.navigationDelegate = nil;
|
||||||
_wkWebView.UIDelegate = nil;
|
_wkWebView.UIDelegate = nil;
|
||||||
//清除cookies
|
// ⚠️ 以下代码会清除整个 App 的所有 Cookie,影响其他模块登录状态,已注释
|
||||||
NSHTTPCookie *cookie;
|
// NSHTTPCookie *cookie;
|
||||||
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
|
// NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
|
||||||
for (cookie in [storage cookies]) {
|
// for (cookie in [storage cookies]) {
|
||||||
[storage deleteCookie:cookie];
|
// [storage deleteCookie:cookie];
|
||||||
}
|
// }
|
||||||
[[NSURLCache sharedURLCache] removeAllCachedResponses];
|
// [[NSURLCache sharedURLCache] removeAllCachedResponses];
|
||||||
[self clearWebViewCache];
|
// [self clearWebViewCache];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Create UI
|
#pragma mark - Create UI
|
||||||
@@ -69,20 +106,58 @@
|
|||||||
preferences.javaScriptCanOpenWindowsAutomatically = YES;
|
preferences.javaScriptCanOpenWindowsAutomatically = YES;
|
||||||
preferences.minimumFontSize = 10;
|
preferences.minimumFontSize = 10;
|
||||||
configuration.preferences = preferences;
|
configuration.preferences = preferences;
|
||||||
[configuration.userContentController addScriptMessageHandler:self name:@"JSCallback"];
|
// 允许视频内联播放,避免全屏时布局计算错误导致显示不完整
|
||||||
[configuration.userContentController addScriptMessageHandler:self name:@"htmlBack"];
|
configuration.allowsInlineMediaPlayback = YES;
|
||||||
|
// ── 统一使用 configuration 自带的 userContentController ──────────────────
|
||||||
|
// Bug 修复:原先在下方又新建了 wkUController 并覆盖 configuration.userContentController,
|
||||||
|
// 导致此处注册的 JSCallback / htmlBack 被丢弃,永远收不到 JS 消息。
|
||||||
|
// Bug 修复:改用 XJWeakScriptMessageHandler 代理,防止循环引用内存泄漏。
|
||||||
|
XJWeakScriptMessageHandler *weakHandler = [XJWeakScriptMessageHandler handlerWithDelegate:self];
|
||||||
|
[configuration.userContentController addScriptMessageHandler:weakHandler name:@"JSCallback"];
|
||||||
|
[configuration.userContentController addScriptMessageHandler:weakHandler name:@"htmlBack"];
|
||||||
|
[configuration.userContentController addScriptMessageHandler:weakHandler name:@"finishActivity"]; // 不带参数的调用
|
||||||
|
|
||||||
|
// 原写法(已废弃):直接传 self 会造成循环引用
|
||||||
|
// [configuration.userContentController addScriptMessageHandler:self name:@"JSCallback"];
|
||||||
|
// [configuration.userContentController addScriptMessageHandler:self name:@"htmlBack"];
|
||||||
|
// ────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
//防止搜索框自动放大 注入js代码
|
//防止搜索框自动放大 注入js代码
|
||||||
WKUserContentController *userController = [WKUserContentController new];
|
// 原代码中 userController 声明后从未使用,已移除
|
||||||
|
// WKUserContentController *userController = [WKUserContentController new];
|
||||||
NSString *jScript = @"var script = document.createElement('meta');script.name = 'viewport';script.content='width=device-width,user-scalable=no';document.getElementsByTagName('head')[0].appendChild(script);";
|
NSString *jScript = @"var script = document.createElement('meta');script.name = 'viewport';script.content='width=device-width,user-scalable=no';document.getElementsByTagName('head')[0].appendChild(script);";
|
||||||
|
|
||||||
WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
|
WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
|
||||||
WKUserContentController * wkUController = [[WKUserContentController alloc] init];
|
|
||||||
[wkUController addScriptMessageHandler: self name: @"finishActivity"];//不带参数的调用
|
|
||||||
|
|
||||||
[wkUController addUserScript:wkUScript];
|
// 原写法(已废弃):新建 wkUController 并覆盖 configuration.userContentController,
|
||||||
configuration.userContentController= wkUController;
|
// 导致上方注册的 JSCallback / htmlBack 全部失效
|
||||||
|
// WKUserContentController * wkUController = [[WKUserContentController alloc] init];
|
||||||
|
// [wkUController addScriptMessageHandler: self name: @"finishActivity"];
|
||||||
|
// [wkUController addUserScript:wkUScript];
|
||||||
|
// configuration.userContentController = wkUController;
|
||||||
|
|
||||||
|
[configuration.userContentController addUserScript:wkUScript];
|
||||||
|
|
||||||
|
// 禁用网页长按文字选中和复制粘贴菜单
|
||||||
|
NSString *noSelectJS = @"document.documentElement.style.webkitUserSelect='none';"
|
||||||
|
"document.documentElement.style.webkitTouchCallout='none';";
|
||||||
|
WKUserScript *noSelectScript = [[WKUserScript alloc] initWithSource:noSelectJS
|
||||||
|
injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
|
||||||
|
forMainFrameOnly:NO];
|
||||||
|
[configuration.userContentController addUserScript:noSelectScript];
|
||||||
|
|
||||||
self.wkWebView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, WIDTH, MyViewHEIGHT) configuration:configuration];
|
self.wkWebView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, WIDTH, MyViewHEIGHT) configuration:configuration];
|
||||||
|
if (@available(iOS 16.4, *)) {
|
||||||
|
self.wkWebView.inspectable = YES;
|
||||||
|
}
|
||||||
|
// 伪装成 Safari User-Agent,排查 H5 API 请求因 UA 差异被拒的问题
|
||||||
|
{
|
||||||
|
NSString *osVer = [UIDevice currentDevice].systemVersion;
|
||||||
|
NSString *osVerUnder = [osVer stringByReplacingOccurrencesOfString:@"." withString:@"_"];
|
||||||
|
self.wkWebView.customUserAgent = [NSString stringWithFormat:
|
||||||
|
@"Mozilla/5.0 (iPhone; CPU iPhone OS %@ like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/%@ Mobile/15E148 Safari/604.1",
|
||||||
|
osVerUnder, osVer];
|
||||||
|
}
|
||||||
self.wkWebView.navigationDelegate = self;
|
self.wkWebView.navigationDelegate = self;
|
||||||
self.wkWebView.UIDelegate = self;
|
self.wkWebView.UIDelegate = self;
|
||||||
if (@available(iOS 11.0, *)) {
|
if (@available(iOS 11.0, *)) {
|
||||||
@@ -90,31 +165,104 @@
|
|||||||
}
|
}
|
||||||
[self.view addSubview:self.wkWebView];
|
[self.view addSubview:self.wkWebView];
|
||||||
self.wkWebView.scrollView.bounces = false;//禁止滑动
|
self.wkWebView.scrollView.bounces = false;//禁止滑动
|
||||||
|
|
||||||
|
// 进度条,居中偏上
|
||||||
|
self.progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
|
||||||
|
self.progressView.trackTintColor = [UIColor clearColor];
|
||||||
|
[self.view addSubview:self.progressView];
|
||||||
|
[self.progressView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.centerX.equalTo(self.wkWebView);
|
||||||
|
make.centerY.equalTo(self.wkWebView).offset(-60);
|
||||||
|
make.width.mas_offset(200);
|
||||||
|
make.height.mas_offset(2);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// KVO 监听加载进度
|
||||||
|
[self.wkWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
|
||||||
|
|
||||||
|
// 加载失败占位视图(默认隐藏)
|
||||||
|
self.errorView = [[UIView alloc] init];
|
||||||
|
self.errorView.backgroundColor = [UIColor whiteColor];
|
||||||
|
self.errorView.hidden = YES;
|
||||||
|
[self.view addSubview:self.errorView];
|
||||||
|
[self.errorView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.edges.equalTo(self.wkWebView);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UILabel *tipLabel = [[UILabel alloc] init];
|
||||||
|
tipLabel.text = @"网络加载失败\n请检查网络后重试";
|
||||||
|
tipLabel.textAlignment = NSTextAlignmentCenter;
|
||||||
|
tipLabel.numberOfLines = 0;
|
||||||
|
tipLabel.textColor = [UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:1.0];
|
||||||
|
tipLabel.font = [UIFont systemFontOfSize:15];
|
||||||
|
[self.errorView addSubview:tipLabel];
|
||||||
|
[tipLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.centerX.equalTo(self.errorView);
|
||||||
|
make.centerY.equalTo(self.errorView).offset(-40);
|
||||||
|
make.left.greaterThanOrEqualTo(self.errorView).offset(20);
|
||||||
|
make.right.lessThanOrEqualTo(self.errorView).offset(-20);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UIButton *reloadBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
|
[reloadBtn setTitle:@"重新加载" forState:UIControlStateNormal];
|
||||||
|
[reloadBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||||
|
reloadBtn.titleLabel.font = [UIFont systemFontOfSize:15];
|
||||||
|
reloadBtn.backgroundColor = [UIColor colorWithRed:0.0 green:0.68 blue:0.41 alpha:1.0];
|
||||||
|
reloadBtn.layer.cornerRadius = 20;
|
||||||
|
reloadBtn.layer.masksToBounds = YES;
|
||||||
|
[reloadBtn addTarget:self action:@selector(reloadWebView) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
[self.errorView addSubview:reloadBtn];
|
||||||
|
[reloadBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.equalTo(tipLabel.mas_bottom).offset(24);
|
||||||
|
make.right.equalTo(self.errorView.mas_centerX).offset(-8);
|
||||||
|
make.width.mas_offset(110);
|
||||||
|
make.height.mas_offset(40);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
|
[backBtn setTitle:@"返回" forState:UIControlStateNormal];
|
||||||
|
[backBtn setTitleColor:[UIColor colorWithRed:0.0 green:0.68 blue:0.41 alpha:1.0] forState:UIControlStateNormal];
|
||||||
|
backBtn.titleLabel.font = [UIFont systemFontOfSize:15];
|
||||||
|
backBtn.backgroundColor = [UIColor whiteColor];
|
||||||
|
backBtn.layer.cornerRadius = 20;
|
||||||
|
backBtn.layer.masksToBounds = YES;
|
||||||
|
backBtn.layer.borderWidth = 1;
|
||||||
|
backBtn.layer.borderColor = [UIColor colorWithRed:0.0 green:0.68 blue:0.41 alpha:1.0].CGColor;
|
||||||
|
[backBtn addTarget:self action:@selector(backVC) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
[self.errorView addSubview:backBtn];
|
||||||
|
[backBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.equalTo(reloadBtn);
|
||||||
|
make.left.equalTo(self.errorView.mas_centerX).offset(8);
|
||||||
|
make.width.height.equalTo(reloadBtn);
|
||||||
|
}];
|
||||||
|
|
||||||
[self webViewRequest];
|
[self webViewRequest];
|
||||||
/*
|
|
||||||
[self.wkWebView evaluateJavaScript:@"htmlBack" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
|
|
||||||
NSLog(@"response: %@ error: %@", response, error);
|
|
||||||
if (response) {
|
|
||||||
[self back];
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)finishActivity {
|
- (void)finishActivity {
|
||||||
|
// H5 调用 finishActivity 的默认行为:pop 返回上一页
|
||||||
|
// 语义等同于 Android 的 finish(),即关闭当前页面
|
||||||
|
// 子类如需特殊处理(如 dismiss、发通知等),override 此方法即可
|
||||||
|
[self.navigationController popViewControllerAnimated:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)reloadWebView {
|
||||||
|
self.errorView.hidden = YES;
|
||||||
|
[self webViewRequest];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)webViewRequest{
|
- (void)webViewRequest{
|
||||||
|
[self clearWebViewCache];
|
||||||
NSString *urlString = self.webUrl;
|
NSString *urlString = self.webUrl;
|
||||||
|
DLog(@"[WebView] 请求加载: %@", urlString);
|
||||||
[self hiddenAllMBProgressHUD];
|
[self hiddenAllMBProgressHUD];
|
||||||
if (urlString.length > 0) {
|
if (urlString.length > 0) {
|
||||||
[self showMBProgressHUDOnlyWithString:@"加载中"];
|
[self showMBProgressHUDOnlyWithString:@"加载中"];
|
||||||
NSURL *url = [NSURL URLWithString:urlString];
|
NSURL *url = [NSURL URLWithString:urlString];
|
||||||
|
if (!url) {
|
||||||
|
DLog(@"[WebView] URL 无效: %@", urlString);
|
||||||
|
}
|
||||||
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
|
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
|
||||||
if (self.wkWebView) {
|
if (self.wkWebView) {
|
||||||
[self.wkWebView loadRequest:urlRequest];
|
[self.wkWebView loadRequest:urlRequest];
|
||||||
@@ -125,6 +273,24 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - KVO
|
||||||
|
|
||||||
|
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||||
|
if ([keyPath isEqualToString:@"estimatedProgress"]) {
|
||||||
|
float progress = [change[NSKeyValueChangeNewKey] floatValue];
|
||||||
|
self.progressView.alpha = 1.0;
|
||||||
|
[self.progressView setProgress:progress animated:YES];
|
||||||
|
if (progress >= 1.0) {
|
||||||
|
// 加载完成后渐隐进度条
|
||||||
|
[UIView animateWithDuration:0.3 delay:0.2 options:0 animations:^{
|
||||||
|
self.progressView.alpha = 0;
|
||||||
|
} completion:^(BOOL finished) {
|
||||||
|
[self.progressView setProgress:0 animated:NO];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - WKNavigationDelegate
|
#pragma mark - WKNavigationDelegate
|
||||||
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
|
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
|
||||||
if ([message.name isEqualToString:@"JSCallback"]) {
|
if ([message.name isEqualToString:@"JSCallback"]) {
|
||||||
@@ -139,7 +305,7 @@
|
|||||||
WkJSMessageType messageType = [[dic objectForKey:@"messageType"] intValue];
|
WkJSMessageType messageType = [[dic objectForKey:@"messageType"] intValue];
|
||||||
switch (messageType) {
|
switch (messageType) {
|
||||||
case WkJSMessageTypeBack:{
|
case WkJSMessageTypeBack:{
|
||||||
// [self.navigationController popViewControllerAnimated:YES];
|
[self.navigationController popViewControllerAnimated:YES];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -149,6 +315,12 @@
|
|||||||
|
|
||||||
} else if ([message.name isEqualToString:@"htmlBack"]) {
|
} else if ([message.name isEqualToString:@"htmlBack"]) {
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"fromWebToReloadData" object:nil];
|
[[NSNotificationCenter defaultCenter] postNotificationName:@"fromWebToReloadData" object:nil];
|
||||||
|
|
||||||
|
} else if ([message.name isEqualToString:@"finishActivity"]) {
|
||||||
|
// JS 调用 window.webkit.messageHandlers.finishActivity.postMessage({}) 时触发
|
||||||
|
// 调用 finishActivity 方法,子类可 override 实现各自的关闭逻辑
|
||||||
|
// 基类默认实现为空,不做任何操作
|
||||||
|
[self finishActivity];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,14 +334,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
|
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
|
||||||
|
DLog(@"[WebView] 开始加载: %@", webView.URL);
|
||||||
|
self.errorView.hidden = YES;
|
||||||
if (!self.webTitle) {
|
if (!self.webTitle) {
|
||||||
self.title = @"加载中...";
|
self.title = @"加载中...";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{
|
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{
|
||||||
|
DLog(@"[WebView] 加载完成: %@", webView.URL);
|
||||||
[self hiddenAllMBProgressHUD];
|
[self hiddenAllMBProgressHUD];
|
||||||
|
self.errorView.hidden = YES;
|
||||||
if (!self.webTitle) {
|
if (!self.webTitle) {
|
||||||
self.title = webView.title;
|
self.title = webView.title;
|
||||||
}
|
}
|
||||||
@@ -177,7 +352,82 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(nonnull NSError *)error{
|
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(nonnull NSError *)error{
|
||||||
|
NSLog(@"[WebView] 加载失败 URL=%@ errorCode=%ld domain=%@ desc=%@",
|
||||||
|
webView.URL, (long)error.code, error.domain, error.localizedDescription);
|
||||||
[self hiddenAllMBProgressHUD];
|
[self hiddenAllMBProgressHUD];
|
||||||
|
// NSURLErrorCancelled (-999) 是主动取消导航(如跳转第三方 App),不算真实网络错误
|
||||||
|
if (error.code != NSURLErrorCancelled) {
|
||||||
|
self.errorView.hidden = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
|
||||||
|
NSLog(@"[WebView] 导航失败 URL=%@ errorCode=%ld domain=%@ desc=%@",
|
||||||
|
webView.URL, (long)error.code, error.domain, error.localizedDescription);
|
||||||
|
[self hiddenAllMBProgressHUD];
|
||||||
|
// NSURLErrorCancelled (-999) 是主动取消导航,不算真实网络错误
|
||||||
|
if (error.code != NSURLErrorCancelled) {
|
||||||
|
self.errorView.hidden = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - 白屏修复
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拦截所有导航请求,处理非 HTTP/HTTPS scheme。
|
||||||
|
*
|
||||||
|
* 问题根源:
|
||||||
|
* 银行 H5 点击支付/跳转按钮时,会触发 alipay:// weixin:// tel:// 等 URL Scheme。
|
||||||
|
* WKWebView 默认会尝试自己加载这些 scheme,加载失败后清空页面内容 → 永久白屏。
|
||||||
|
*
|
||||||
|
* 解决方案:
|
||||||
|
* 在此方法中拦截非 HTTP/HTTPS 的请求,交由系统(UIApplication)处理,
|
||||||
|
* WKWebView 自身取消该次导航,页面内容保持不变。
|
||||||
|
*/
|
||||||
|
- (void)webView:(WKWebView *)webView
|
||||||
|
decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
|
||||||
|
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
|
||||||
|
|
||||||
|
NSURL *url = navigationAction.request.URL;
|
||||||
|
NSString *scheme = url.scheme.lowercaseString;
|
||||||
|
|
||||||
|
// HTTP / HTTPS:正常加载,交给 WKWebView 处理
|
||||||
|
if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]) {
|
||||||
|
decisionHandler(WKNavigationActionPolicyAllow);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// about:blank:WKWebView 内部使用,直接放行
|
||||||
|
if ([scheme isEqualToString:@"about"]) {
|
||||||
|
decisionHandler(WKNavigationActionPolicyAllow);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他 scheme(alipay:// weixin:// tel:// mailto:// 等):
|
||||||
|
// 交由系统打开对应 App 或拨号,WKWebView 取消此次导航,避免白屏
|
||||||
|
if ([[UIApplication sharedApplication] canOpenURL:url]) {
|
||||||
|
[[UIApplication sharedApplication] openURL:url
|
||||||
|
options:@{}
|
||||||
|
completionHandler:nil];
|
||||||
|
}
|
||||||
|
decisionHandler(WKNavigationActionPolicyCancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebContent 进程被系统终止时的兜底处理。
|
||||||
|
*
|
||||||
|
* 触发场景:
|
||||||
|
* 设备内存严重不足时,系统会强制 kill 掉 WKWebView 的 WebContent 进程。
|
||||||
|
* 此时 WKWebView 会立即变成空白页,且无法响应任何操作。
|
||||||
|
* 若不处理,用户只能退出页面重新进入。
|
||||||
|
*
|
||||||
|
* 解决方案:
|
||||||
|
* 检测到进程终止后,重新加载当前 URL,让用户无感知恢复。
|
||||||
|
*/
|
||||||
|
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {
|
||||||
|
NSLog(@"[XJBaseWebViewVC] WebContent 进程被系统终止,自动 reload");
|
||||||
|
// 重新加载,恢复页面内容
|
||||||
|
[webView reload];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -201,10 +451,13 @@
|
|||||||
|
|
||||||
#pragma mark - 自定义
|
#pragma mark - 自定义
|
||||||
- (void)onBackClicked{
|
- (void)onBackClicked{
|
||||||
if ( self.wkWebView.canGoBack){
|
if (self.wkWebView.canGoBack) {
|
||||||
[self.wkWebView goBack];
|
[self.wkWebView goBack];
|
||||||
} else {
|
} else {
|
||||||
|
// 原写法:只清缓存没有 pop,页面会卡住
|
||||||
|
// [self clearWebViewCache];
|
||||||
[self clearWebViewCache];
|
[self clearWebViewCache];
|
||||||
|
[self.navigationController popViewControllerAnimated:YES];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +466,7 @@
|
|||||||
NSSet *websiteDataTypes = [WKWebsiteDataStore allWebsiteDataTypes];
|
NSSet *websiteDataTypes = [WKWebsiteDataStore allWebsiteDataTypes];
|
||||||
NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0];
|
NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0];
|
||||||
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{
|
[[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{
|
||||||
NSLog(@"-----clear webView cache success------");
|
DLog(@"-----clear webView cache success------");
|
||||||
}];
|
}];
|
||||||
} else {
|
} else {
|
||||||
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
|
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
|
||||||
@@ -221,24 +474,23 @@
|
|||||||
NSError *errors;
|
NSError *errors;
|
||||||
[[NSFileManager defaultManager] removeItemAtPath:cookiesFolderPath error:&errors];
|
[[NSFileManager defaultManager] removeItemAtPath:cookiesFolderPath error:&errors];
|
||||||
if (!errors) {
|
if (!errors) {
|
||||||
NSLog(@"-----clear wkWebView cache success------");
|
DLog(@"-----clear wkWebView cache success------");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
- (NSString *)URLEncodedString:(NSString *)urlString{
|
- (NSString *)URLEncodedString:(NSString *)urlString{
|
||||||
NSString *encodePath ;
|
NSString *encodePath;
|
||||||
if (!IOS7) {
|
|
||||||
encodePath = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
|
||||||
}else{
|
|
||||||
encodePath = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
|
encodePath = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
|
||||||
}return encodePath;
|
return encodePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - SETTER
|
#pragma mark - SETTER
|
||||||
- (void)setRightType:(RightNavType)rightType{
|
// setRightType: 与自动合成的 setter 完全相同,无需 override,保留注释备查
|
||||||
_rightType = rightType;
|
//- (void)setRightType:(RightNavType)rightType{
|
||||||
}
|
// _rightType = rightType;
|
||||||
|
//}
|
||||||
|
|
||||||
- (void)setWebUrl:(NSString *)webUrl{
|
- (void)setWebUrl:(NSString *)webUrl{
|
||||||
_webUrl = webUrl;
|
_webUrl = webUrl;
|
||||||
|
|||||||
+1
@@ -39,6 +39,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
//地图
|
//地图
|
||||||
@property (nonatomic, assign) CGFloat Longitude;
|
@property (nonatomic, assign) CGFloat Longitude;
|
||||||
@property (nonatomic, assign) CGFloat Latitude;
|
@property (nonatomic, assign) CGFloat Latitude;
|
||||||
|
@property (nonatomic, copy) NSString * address;//地址描述
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -134,8 +134,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (MsgBody *msgBody in model.MsgBody) {
|
for (MsgBody *msgBody in model.MsgBody) {
|
||||||
NSLog(@"MsgType: %@", msgBody.MsgType);
|
DLog(@"MsgType: %@", msgBody.MsgType);
|
||||||
NSLog(@"MsgContent Data - title: %@", msgBody.MsgContent.Text);
|
DLog(@"MsgContent Data - title: %@", msgBody.MsgContent.Text);
|
||||||
|
|
||||||
if([msgBody.MsgType isEqualToString:@"TIMTextElem"]) //文本消息
|
if([msgBody.MsgType isEqualToString:@"TIMTextElem"]) //文本消息
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,14 +6,12 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <TIMCommon/TUIBubbleMessageCell.h>
|
#import <TIMCommon/TUIBubbleMessageCell.h>
|
||||||
#import <TIMCommon/TUIMessageCell.h>
|
|
||||||
#import "CustomMapMessageCellData.h"
|
#import "CustomMapMessageCellData.h"
|
||||||
#import "CustomTUIHistoryModel.h"
|
#import "CustomTUIHistoryModel.h"
|
||||||
|
|
||||||
|
|
||||||
@interface CustomMapMessageCell : UITableViewCell
|
@interface CustomMapMessageCell : TUIBubbleMessageCell
|
||||||
|
|
||||||
@property (nonatomic, strong) CustomTUIHistoryModel * model;
|
@property (nonatomic, strong) CustomTUIHistoryModel * model;
|
||||||
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+150
-138
@@ -6,224 +6,161 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "CustomMapMessageCell.h"
|
#import "CustomMapMessageCell.h"
|
||||||
|
#import "XJWeChatManager.h"
|
||||||
|
#import <SDWebImage/SDImageCache.h>
|
||||||
#import<CommonCrypto/CommonDigest.h>
|
#import<CommonCrypto/CommonDigest.h>
|
||||||
|
|
||||||
@interface CustomMapMessageCell ()
|
@interface CustomMapMessageCell ()
|
||||||
|
|
||||||
@property (nonatomic, strong) UIImageView * heardImage;
|
@property (nonatomic, strong) UILabel * myTextLabel;
|
||||||
|
@property (nonatomic, strong) UIImageView * mapImage;
|
||||||
@property (nonatomic, strong) UILabel * nickNameLabel;
|
|
||||||
|
|
||||||
@property (nonatomic, strong) UILabel * myTextLabel; // 展示文本
|
|
||||||
|
|
||||||
@property (nonatomic, strong) UIImageView * mapImage; //
|
|
||||||
|
|
||||||
@property (nonatomic, strong) UIView * backView;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation CustomMapMessageCell
|
@implementation CustomMapMessageCell
|
||||||
|
|
||||||
- (void)awakeFromNib {
|
|
||||||
[super awakeFromNib];
|
|
||||||
// Initialization code
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
|
|
||||||
[super setSelected:selected animated:animated];
|
|
||||||
|
|
||||||
// Configure the view for the selected state
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
|
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
|
||||||
{
|
{
|
||||||
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
|
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
|
||||||
if (self) {
|
if (self) {
|
||||||
|
[self createMapUI];
|
||||||
[self createUI];
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)createUI {
|
- (void)createMapUI {
|
||||||
|
|
||||||
self.heardImage = [[UIImageView alloc] init];
|
|
||||||
self.heardImage.backgroundColor = KWhiteColor;
|
|
||||||
self.heardImage.image = [UIImage imageNamed:@"heard_man"];
|
|
||||||
[self.contentView addSubview:self.heardImage];
|
|
||||||
self.heardImage.layer.cornerRadius = 20;
|
|
||||||
self.heardImage.layer.masksToBounds = true;
|
|
||||||
[self.heardImage mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
||||||
|
|
||||||
make.left.mas_equalTo(@15);
|
|
||||||
make.top.mas_equalTo(@8);
|
|
||||||
make.height.width.mas_equalTo(@30);
|
|
||||||
}];
|
|
||||||
|
|
||||||
self.nickNameLabel = [[UILabel alloc] init];
|
|
||||||
self.nickNameLabel.text = @"全科医生";
|
|
||||||
[self.contentView addSubview:self.nickNameLabel];
|
|
||||||
self.nickNameLabel.font = SYSTEMFONT(12);
|
|
||||||
[self.nickNameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
||||||
|
|
||||||
make.left.mas_equalTo(self.heardImage.mas_right).offset(10);
|
|
||||||
make.top.mas_equalTo(@10);
|
|
||||||
make.width.mas_equalTo(@300.0);
|
|
||||||
make.height.mas_offset(13);
|
|
||||||
}];
|
|
||||||
|
|
||||||
//姓名
|
|
||||||
self.backView = [[UIView alloc] init];
|
|
||||||
self.backView.layer.cornerRadius = 10;
|
|
||||||
self.backView.backgroundColor = KWhiteColor;
|
|
||||||
[self.contentView addSubview:self.backView];
|
|
||||||
|
|
||||||
|
|
||||||
[self.backView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
||||||
|
|
||||||
make.left.mas_equalTo(self.heardImage.mas_right).offset(10);
|
|
||||||
make.width.mas_offset(245);
|
|
||||||
make.top.mas_equalTo(self.nickNameLabel.mas_bottom).offset(8);
|
|
||||||
make.height.mas_offset(170);
|
|
||||||
}];
|
|
||||||
|
|
||||||
|
// 隐藏默认气泡图片,改用白色圆角
|
||||||
|
self.bubbleView.image = nil;
|
||||||
|
|
||||||
self.myTextLabel = [[UILabel alloc] init];
|
self.myTextLabel = [[UILabel alloc] init];
|
||||||
self.myTextLabel.font = SYSTEMFONT(15);
|
self.myTextLabel.font = SYSTEMFONT(15);
|
||||||
self.myTextLabel.textColor = CFontColor1;
|
self.myTextLabel.textColor = CFontColor1;
|
||||||
self.myTextLabel.text = @"我的位置";
|
self.myTextLabel.numberOfLines = 0;
|
||||||
[self.backView addSubview:self.myTextLabel];
|
[self.container addSubview:self.myTextLabel];
|
||||||
|
|
||||||
[self.myTextLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
[self.myTextLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
|
||||||
make.left.mas_offset(10);
|
make.left.mas_offset(10);
|
||||||
make.top.mas_offset(0);
|
make.top.mas_offset(10);
|
||||||
make.right.mas_offset(-10);
|
make.right.mas_offset(-10);
|
||||||
make.height.mas_offset(25);
|
}];
|
||||||
}];
|
|
||||||
|
|
||||||
|
|
||||||
self.mapImage = [[UIImageView alloc] init];
|
self.mapImage = [[UIImageView alloc] init];
|
||||||
self.mapImage.backgroundColor = KRedColor;
|
self.mapImage.backgroundColor = KRedColor;
|
||||||
[self.backView addSubview:self.mapImage];
|
[self.container addSubview:self.mapImage];
|
||||||
[self.mapImage mas_makeConstraints:^(MASConstraintMaker *make) {
|
[self.mapImage mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
|
||||||
make.left.right.bottom.mas_offset(0);
|
make.left.right.bottom.mas_offset(0);
|
||||||
make.top.mas_equalTo(self.myTextLabel.mas_bottom);
|
make.top.mas_equalTo(self.myTextLabel.mas_bottom);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
// 长按转发到微信
|
||||||
|
// TUIChat 框架把长按手势注释掉了,这里重新加上。
|
||||||
|
// 需要让 container 上已有的 tap 手势等 longPress 失败后再触发,否则 tap 会抢走触摸。
|
||||||
|
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onLongPress:)];
|
||||||
|
longPress.minimumPressDuration = 0.5;
|
||||||
|
[self.container addGestureRecognizer:longPress];
|
||||||
|
|
||||||
|
for (UIGestureRecognizer *g in self.container.gestureRecognizers) {
|
||||||
|
if ([g isKindOfClass:[UITapGestureRecognizer class]]) {
|
||||||
|
[g requireGestureRecognizerToFail:longPress];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - TUIChat 实时聊天回调
|
||||||
|
|
||||||
|
- (void)fillWithData:(CustomMapMessageCellData *)data {
|
||||||
|
[super fillWithData:data];
|
||||||
|
|
||||||
|
self.myTextLabel.text = data.text.length > 0 ? data.text : @"我的位置";
|
||||||
|
[self.mapImage sd_setImageWithURL:[NSURL URLWithString:data.MapPictureImg] placeholderImage:nil];
|
||||||
|
|
||||||
|
self.nameLabel.hidden = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - 历史记录回调
|
||||||
|
|
||||||
- (void)setModel:(CustomTUIHistoryModel *)model {
|
- (void)setModel:(CustomTUIHistoryModel *)model {
|
||||||
_model = model;
|
_model = model;
|
||||||
|
|
||||||
// self.nickNameLabel.text = _model.fromAccountName;
|
self.myTextLabel.text = _model.address.length > 0 ? _model.address : @"我的位置";
|
||||||
|
|
||||||
if (_model.isSelf == true) { //头像在右
|
NSString * MapPictureImg = [self mapLocationImage:_model.Longitude Withlation:_model.Latitude];
|
||||||
|
[self.mapImage sd_setImageWithURL:[NSURL URLWithString:MapPictureImg] placeholderImage:nil];
|
||||||
|
|
||||||
[self.heardImage mas_remakeConstraints:^(MASConstraintMaker *make) {
|
// 历史记录:手动设置头像和名字
|
||||||
|
self.avatarView.image = [UIImage imageNamed:@"heard_man"];
|
||||||
|
self.nameLabel.text = @"全科医生";
|
||||||
|
self.nameLabel.hidden = NO;
|
||||||
|
|
||||||
|
if (_model.isSelf) {
|
||||||
|
self.avatarView.hidden = NO;
|
||||||
|
[self.avatarView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
make.height.width.mas_offset(40);
|
make.height.width.mas_offset(40);
|
||||||
make.top.mas_equalTo(@10);
|
make.top.mas_equalTo(@10);
|
||||||
make.right.mas_equalTo(self.contentView.mas_right).offset(-10);
|
make.right.mas_equalTo(self.contentView.mas_right).offset(-10);
|
||||||
|
|
||||||
}];
|
}];
|
||||||
self.nickNameLabel.textAlignment = NSTextAlignmentRight;
|
self.nameLabel.textAlignment = NSTextAlignmentRight;
|
||||||
[self.nickNameLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
[self.nameLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.mas_equalTo(self.avatarView.mas_left).offset(-10);
|
||||||
make.right.mas_equalTo(self.heardImage.mas_left).offset(-10);
|
|
||||||
make.top.mas_equalTo(@10);
|
make.top.mas_equalTo(@10);
|
||||||
make.width.mas_equalTo(@245.0);
|
make.width.mas_equalTo(@245.0);
|
||||||
make.height.mas_offset(13);
|
make.height.mas_offset(13);
|
||||||
}];
|
}];
|
||||||
|
[self.container mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
[self.backView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
make.top.mas_equalTo(self.nameLabel.mas_bottom).offset(8);
|
||||||
make.top.mas_equalTo(self.nickNameLabel.mas_bottom).offset(8);
|
|
||||||
make.width.mas_offset(245);
|
make.width.mas_offset(245);
|
||||||
make.right.mas_equalTo(self.heardImage.mas_left).offset(-10);
|
make.right.mas_equalTo(self.avatarView.mas_left).offset(-10);
|
||||||
make.height.mas_equalTo(@170);
|
make.height.mas_offset(170);
|
||||||
}];
|
}];
|
||||||
|
} else {
|
||||||
|
self.avatarView.hidden = NO;
|
||||||
}else
|
[self.avatarView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
{
|
|
||||||
[self.heardImage mas_remakeConstraints:^(MASConstraintMaker *make) {
|
|
||||||
|
|
||||||
make.left.mas_equalTo(@15);
|
make.left.mas_equalTo(@15);
|
||||||
make.top.mas_equalTo(@8);
|
make.top.mas_equalTo(@8);
|
||||||
make.height.width.mas_equalTo(@40);
|
make.height.width.mas_equalTo(@40);
|
||||||
}];
|
}];
|
||||||
self.nickNameLabel.textAlignment = NSTextAlignmentLeft;
|
self.nameLabel.textAlignment = NSTextAlignmentLeft;
|
||||||
|
[self.nameLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
[self.nickNameLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
make.left.mas_equalTo(self.avatarView.mas_right).offset(10);
|
||||||
|
|
||||||
make.left.mas_equalTo(self.heardImage.mas_right).offset(10);
|
|
||||||
make.top.mas_equalTo(@10);
|
make.top.mas_equalTo(@10);
|
||||||
make.width.mas_equalTo(@300.0);
|
make.width.mas_equalTo(@300.0);
|
||||||
make.height.mas_offset(13);
|
make.height.mas_offset(13);
|
||||||
}];
|
}];
|
||||||
|
[self.container mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_equalTo(self.avatarView.mas_right).offset(10);
|
||||||
[self.backView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
||||||
|
|
||||||
make.left.mas_equalTo(self.heardImage.mas_right).offset(10);
|
|
||||||
make.width.mas_offset(245);
|
make.width.mas_offset(245);
|
||||||
make.top.mas_equalTo(self.nickNameLabel.mas_bottom).offset(8);
|
make.top.mas_equalTo(self.nameLabel.mas_bottom).offset(8);
|
||||||
make.height.mas_offset(170);
|
make.height.mas_offset(170);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 加载头像
|
||||||
[self.contentView mas_updateConstraints:^(MASConstraintMaker *make) {
|
NSString * photo = [NSString stringWithFormat:@"%@%@", ResourceAddress, _model.avatar];
|
||||||
|
photo = [photo stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
|
||||||
make.top.left.right.mas_equalTo(@0);
|
|
||||||
make.bottom.mas_equalTo(self.backView.mas_bottom).offset(10);
|
|
||||||
}];
|
|
||||||
|
|
||||||
|
|
||||||
NSString * MapPictureImg = [self mapLocationImage:_model.Longitude Withlation:_model.Latitude];
|
|
||||||
|
|
||||||
[self.mapImage sd_setImageWithURL:[NSURL URLWithString:MapPictureImg] placeholderImage:nil];
|
|
||||||
|
|
||||||
NSString * photo = [NSString stringWithFormat:@"%@%@",ResourceAddress,_model.avatar];
|
|
||||||
|
|
||||||
NSString * str1 = @"\\";
|
|
||||||
|
|
||||||
photo = [photo stringByReplacingOccurrencesOfString:str1 withString:@"/"];
|
|
||||||
|
|
||||||
NSString *encodedString3 = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)photo, (CFStringRef)@"!$&'()*+,-./:;=?@_~%#[]", NULL, kCFStringEncodingUTF8));
|
NSString *encodedString3 = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)photo, (CFStringRef)@"!$&'()*+,-./:;=?@_~%#[]", NULL, kCFStringEncodingUTF8));
|
||||||
|
[self.avatarView sd_setImageWithURL:[NSURL URLWithString:encodedString3] placeholderImage:PLACEHOLD_IMG];
|
||||||
[self.heardImage sd_setImageWithURL:[NSURL URLWithString:encodedString3] placeholderImage:PLACEHOLD_IMG];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - 地图静态图
|
||||||
|
|
||||||
- (NSString *)mapLocationImage:(CGFloat)longLation Withlation:(CGFloat)lation {
|
- (NSString *)mapLocationImage:(CGFloat)longLation Withlation:(CGFloat)lation {
|
||||||
// 0: self.longLation,self.lation
|
|
||||||
//https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png
|
|
||||||
NSString * staciUrl = @"https://restapi.amap.com/v3/staticmap?key=e9926badd26aaa766d13439c88a83f2d";
|
NSString * staciUrl = @"https://restapi.amap.com/v3/staticmap?key=e9926badd26aaa766d13439c88a83f2d";
|
||||||
NSString * mapKey = @"e9926badd26aaa766d13439c88a83f2d";
|
NSString * mapKey = @"e9926badd26aaa766d13439c88a83f2d";
|
||||||
NSString * loctaionUrl = @"https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png";
|
NSString * loctaionUrl = @"https://a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png";
|
||||||
|
|
||||||
NSString * needMdString = [NSString stringWithFormat:@"key=%@&location=%f,%f&markers=-1,%@,0:%f,%f&size=700*500&zoom=15124d58f7223ac9738312a8d187a21f2b",mapKey,longLation,lation,loctaionUrl,longLation,lation];
|
NSString * needMdString = [NSString stringWithFormat:@"key=%@&location=%f,%f&markers=-1,%@,0:%f,%f&size=700*500&zoom=15124d58f7223ac9738312a8d187a21f2b",mapKey,longLation,lation,loctaionUrl,longLation,lation];
|
||||||
|
|
||||||
|
|
||||||
NSString * mapUrl = [NSString stringWithFormat:@"%@&location=%f,%f&markers=-1,%@,0:%f,%f&size=700*500&zoom=15&sig=%@",staciUrl,longLation,lation,loctaionUrl,longLation,lation,[self md5:needMdString]];
|
NSString * mapUrl = [NSString stringWithFormat:@"%@&location=%f,%f&markers=-1,%@,0:%f,%f&size=700*500&zoom=15&sig=%@",staciUrl,longLation,lation,loctaionUrl,longLation,lation,[self md5:needMdString]];
|
||||||
|
|
||||||
return mapUrl;
|
return mapUrl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
//md加密
|
|
||||||
- (NSString *)md5:(NSString *)str
|
- (NSString *)md5:(NSString *)str
|
||||||
{
|
{
|
||||||
const char *cStr = [str UTF8String];
|
const char *cStr = [str UTF8String];
|
||||||
unsigned char result[16];
|
unsigned char result[16];
|
||||||
CC_MD5(cStr, strlen(cStr), result); // This is the md5 call
|
CC_MD5(cStr, strlen(cStr), result);
|
||||||
return [NSString stringWithFormat:
|
return [NSString stringWithFormat:
|
||||||
@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||||
result[0], result[1], result[2], result[3],
|
result[0], result[1], result[2], result[3],
|
||||||
@@ -233,8 +170,83 @@
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - 长按转发微信
|
||||||
|
|
||||||
|
- (void)onLongPress:(UILongPressGestureRecognizer *)gesture {
|
||||||
|
if (gesture.state != UIGestureRecognizerStateBegan) return;
|
||||||
|
|
||||||
|
if (![[XJWeChatManager sharedManager] isWeChatInstalled]) {
|
||||||
|
[EasyTextView showErrorText:@"未安装微信"];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
|
||||||
|
[alert addAction:[UIAlertAction actionWithTitle:@"转发到微信" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
|
||||||
|
[self shareToWeChat];
|
||||||
|
}]];
|
||||||
|
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];
|
||||||
|
|
||||||
|
UIViewController *topVC = [self topViewController];
|
||||||
|
[topVC presentViewController:alert animated:YES completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)shareToWeChat {
|
||||||
|
NSString *address;
|
||||||
|
CGFloat lat = 0, lng = 0;
|
||||||
|
NSString *imageKey;
|
||||||
|
|
||||||
|
// 实时聊天数据
|
||||||
|
CustomMapMessageCellData *data = (CustomMapMessageCellData *)self.messageData;
|
||||||
|
if ([data isKindOfClass:[CustomMapMessageCellData class]]) {
|
||||||
|
address = data.text.length > 0 ? data.text : @"我的位置";
|
||||||
|
lat = data.latitude;
|
||||||
|
lng = data.longitude;
|
||||||
|
imageKey = data.MapPictureImg;
|
||||||
|
}
|
||||||
|
// 历史记录数据
|
||||||
|
else if (_model) {
|
||||||
|
address = _model.address.length > 0 ? _model.address : @"我的位置";
|
||||||
|
lat = _model.Latitude;
|
||||||
|
lng = _model.Longitude;
|
||||||
|
imageKey = [self mapLocationImage:_model.Longitude Withlation:_model.Latitude];
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *encodedAddress = [address stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
|
||||||
|
NSString *mapUrl = [NSString stringWithFormat:@"https://uri.amap.com/marker?position=%f,%f&name=%@",
|
||||||
|
lng, lat, encodedAddress ?: @"位置"];
|
||||||
|
|
||||||
|
UIImage *thumb = [[SDImageCache sharedImageCache] imageFromCacheForKey:imageKey];
|
||||||
|
|
||||||
|
[[XJWeChatManager sharedManager] shareWebpageWithTitle:address
|
||||||
|
desc:[NSString stringWithFormat:@"经度:%.6f 纬度:%.6f", lng, lat]
|
||||||
|
webpageUrl:mapUrl
|
||||||
|
thumbImage:thumb
|
||||||
|
toScene:0
|
||||||
|
completion:^(BOOL success, NSString * _Nullable errorMsg) {
|
||||||
|
if (!success && errorMsg.length > 0) {
|
||||||
|
[EasyTextView showErrorText:errorMsg];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIViewController *)topViewController {
|
||||||
|
UIViewController *rootVC = [UIApplication sharedApplication].keyWindow.rootViewController;
|
||||||
|
while (rootVC.presentedViewController) {
|
||||||
|
rootVC = rootVC.presentedViewController;
|
||||||
|
}
|
||||||
|
if ([rootVC isKindOfClass:[UINavigationController class]]) {
|
||||||
|
return [(UINavigationController *)rootVC topViewController];
|
||||||
|
}
|
||||||
|
if ([rootVC isKindOfClass:[UITabBarController class]]) {
|
||||||
|
UIViewController *selected = [(UITabBarController *)rootVC selectedViewController];
|
||||||
|
if ([selected isKindOfClass:[UINavigationController class]]) {
|
||||||
|
return [(UINavigationController *)selected topViewController];
|
||||||
|
}
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
return rootVC;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
@property (nonatomic, copy) NSString *text;
|
@property (nonatomic, copy) NSString *text;
|
||||||
@property (nonatomic, copy) NSString * MapPictureImg;
|
@property (nonatomic, copy) NSString * MapPictureImg;
|
||||||
|
@property (nonatomic, assign) CGFloat latitude;
|
||||||
|
@property (nonatomic, assign) CGFloat longitude;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+2
@@ -16,6 +16,8 @@
|
|||||||
cellData.innerMessage = message;
|
cellData.innerMessage = message;
|
||||||
cellData.msgID = message.msgID;
|
cellData.msgID = message.msgID;
|
||||||
cellData.text = message.locationElem.desc;
|
cellData.text = message.locationElem.desc;
|
||||||
|
cellData.latitude = message.locationElem.latitude;
|
||||||
|
cellData.longitude = message.locationElem.longitude;
|
||||||
cellData.MapPictureImg = [self mapLocationImage:message.locationElem.longitude Withlation:message.locationElem.latitude];
|
cellData.MapPictureImg = [self mapLocationImage:message.locationElem.longitude Withlation:message.locationElem.latitude];
|
||||||
cellData.reuseId = @"MapMessageCustomCell";
|
cellData.reuseId = @"MapMessageCustomCell";
|
||||||
cellData.showAvatar = true;
|
cellData.showAvatar = true;
|
||||||
|
|||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// EmptyFunctionDevelopmentVC.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/10.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJBaseViewController.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface EmptyFunctionDevelopmentVC : XJBaseViewController
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
+58
@@ -0,0 +1,58 @@
|
|||||||
|
//
|
||||||
|
// EmptyFunctionDevelopmentVC.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/10.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "EmptyFunctionDevelopmentVC.h"
|
||||||
|
|
||||||
|
@interface EmptyFunctionDevelopmentVC ()
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation EmptyFunctionDevelopmentVC
|
||||||
|
|
||||||
|
- (void)viewDidLoad {
|
||||||
|
[super viewDidLoad];
|
||||||
|
self.isHidenNaviBar = false;
|
||||||
|
self.view.backgroundColor = KWhiteColor;
|
||||||
|
|
||||||
|
UIImageView * deveImg = [[UIImageView alloc] init];
|
||||||
|
deveImg.image = [UIImage imageNamed:@"deveEmptyImg"];
|
||||||
|
[self.view addSubview:deveImg];
|
||||||
|
|
||||||
|
[deveImg mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.width.mas_offset(90);
|
||||||
|
make.height.mas_offset(76);
|
||||||
|
make.centerX.mas_equalTo(self.view);
|
||||||
|
make.centerY.mas_equalTo(self.view).offset(-70) ;
|
||||||
|
}];
|
||||||
|
|
||||||
|
UILabel * dataLabel = [[UILabel alloc] init];
|
||||||
|
dataLabel.text = @"~ 正在研发中,敬请期待 ~";
|
||||||
|
dataLabel.font = SYSTEMFONT(14);
|
||||||
|
dataLabel.textColor = UIColorHex(#B6B6B6);
|
||||||
|
dataLabel.textAlignment = NSTextAlignmentCenter;
|
||||||
|
[self.view addSubview:dataLabel];
|
||||||
|
|
||||||
|
[dataLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.mas_equalTo(deveImg.mas_bottom).offset(12);
|
||||||
|
make.left.right.mas_offset(0);
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
// Do any additional setup after loading the view.
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#pragma mark - Navigation
|
||||||
|
|
||||||
|
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||||
|
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||||
|
// Get the new view controller using [segue destinationViewController].
|
||||||
|
// Pass the selected object to the new view controller.
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
@end
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// PhysicalWebViewController.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/3/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJBaseWebViewVC.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface PhysicalWebViewController : XJBaseWebViewVC
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
//
|
||||||
|
// PhysicalWebViewController.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/3/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "PhysicalWebViewController.h"
|
||||||
|
|
||||||
|
@interface PhysicalWebViewController ()
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation PhysicalWebViewController
|
||||||
|
|
||||||
|
- (void)viewDidLoad {
|
||||||
|
[super viewDidLoad];
|
||||||
|
self.isHidenNaviBar = true;
|
||||||
|
[self.wkWebView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.left.right.mas_offset(0);
|
||||||
|
make.bottom.mas_offset(-SafetyAreaHeight);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - WKNavigationDelegate
|
||||||
|
|
||||||
|
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
|
||||||
|
[super webView:webView didStartProvisionalNavigation:navigation];
|
||||||
|
DLog(@"[健康H5] 开始加载: %@", webView.URL.absoluteString);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
|
||||||
|
[super webView:webView didFinishNavigation:navigation];
|
||||||
|
DLog(@"[健康H5] 加载完成: %@", webView.URL.absoluteString);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
|
||||||
|
[super webView:webView didFailProvisionalNavigation:navigation withError:error];
|
||||||
|
DLog(@"[健康H5] 加载失败: %@", error.localizedDescription);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
|
||||||
|
[super webView:webView didFailNavigation:navigation withError:error];
|
||||||
|
DLog(@"[健康H5] 导航失败: %@", error.localizedDescription);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// XJBankWebDetailViewController.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/3/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJBaseWebViewVC.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface XJBankWebDetailViewController : XJBaseWebViewVC
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// XJBankWebDetailViewController.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/3/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJBankWebDetailViewController.h"
|
||||||
|
|
||||||
|
@interface XJBankWebDetailViewController ()
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation XJBankWebDetailViewController
|
||||||
|
|
||||||
|
- (void)viewDidLoad {
|
||||||
|
[super viewDidLoad];
|
||||||
|
self.isHidenNaviBar = true;
|
||||||
|
[self.wkWebView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.left.right.mas_offset(0);
|
||||||
|
make.bottom.mas_offset(-SafetyAreaHeight);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
// finishActivity 行为与基类一致(pop 返回),无需 override
|
||||||
|
// 基类 XJBaseWebViewVC 已实现默认 pop 逻辑
|
||||||
|
|
||||||
|
@end
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// XJHealthArchiveDetailViewController.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// 一人一案 - 健康档案查看页
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJBaseViewController.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface XJHealthArchiveDetailViewController : XJBaseViewController
|
||||||
|
|
||||||
|
@property (nonatomic, copy) NSString *idCard;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
+1291
File diff suppressed because it is too large
Load Diff
+16
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// XJHomePageV2ViewController.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJBaseViewController.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface XJHomePageV2ViewController : XJBaseViewController
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
+1808
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// HomeBannerModel.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/10.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface HomeBannerModel : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic, strong) NSString * banner_id;
|
||||||
|
@property (nonatomic, strong) NSString * tfJump;
|
||||||
|
@property (nonatomic, strong) NSString * photoUrl;
|
||||||
|
@property (nonatomic, strong) NSString * jumpUrl;
|
||||||
|
@property (nonatomic, assign) NSInteger sort;
|
||||||
|
@property (nonatomic, strong) NSString * showLocation;
|
||||||
|
@property (nonatomic, strong) NSString * showLocation_dicText;
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// HomeBannerModel.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/10.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "HomeBannerModel.h"
|
||||||
|
|
||||||
|
@implementation HomeBannerModel
|
||||||
|
|
||||||
|
+ (NSDictionary *)modelCustomPropertyMapper
|
||||||
|
{
|
||||||
|
NSDictionary * dic =@{@"banner_id" :@"id"};
|
||||||
|
return dic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// XJHealthArticleModel.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/6/29.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface XJHealthArticleModel : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic, assign) NSInteger articleId;
|
||||||
|
@property (nonatomic, copy) NSString * articleTitle;
|
||||||
|
@property (nonatomic, copy) NSString * articleSubtitle;
|
||||||
|
@property (nonatomic, copy) NSString * articleExcerpt;
|
||||||
|
@property (nonatomic, copy) NSString * articleTag;
|
||||||
|
@property (nonatomic, copy) NSString * articleHeaderimage;
|
||||||
|
@property (nonatomic, copy) NSString * articleType;
|
||||||
|
@property (nonatomic, copy) NSString * createTime;
|
||||||
|
@property (nonatomic, assign) NSInteger viewCount;
|
||||||
|
@property (nonatomic, assign) NSInteger likeCount;
|
||||||
|
@property (nonatomic, assign) NSInteger favoriteCount;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
//
|
||||||
|
// XJHealthArticleModel.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/6/29.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJHealthArticleModel.h"
|
||||||
|
|
||||||
|
@implementation XJHealthArticleModel
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// XJHealthCategoryModel.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/6/29.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface XJHealthCategoryModel : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic, assign) NSInteger categoryId;
|
||||||
|
@property (nonatomic, copy) NSString * categoryName;
|
||||||
|
@property (nonatomic, strong) NSArray<XJHealthCategoryModel *> * children;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// XJHealthCategoryModel.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/6/29.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJHealthCategoryModel.h"
|
||||||
|
|
||||||
|
@implementation XJHealthCategoryModel
|
||||||
|
|
||||||
|
+ (NSDictionary *)modelContainerPropertyGenericClass {
|
||||||
|
return @{ @"children": [XJHealthCategoryModel class] };
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// XJHealthKnowledgeModel.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/6/29.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface XJHealthKnowledgeModel : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic, copy) NSString * knowledgeId;
|
||||||
|
@property (nonatomic, copy) NSString * title;
|
||||||
|
@property (nonatomic, copy) NSString * content;
|
||||||
|
@property (nonatomic, copy) NSString * imageUrl;
|
||||||
|
@property (nonatomic, copy) NSString * tags;
|
||||||
|
@property (nonatomic, copy) NSString * createTime;
|
||||||
|
@property (nonatomic, assign) NSInteger favoriteCount;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
//
|
||||||
|
// XJHealthKnowledgeModel.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/6/29.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJHealthKnowledgeModel.h"
|
||||||
|
|
||||||
|
@implementation XJHealthKnowledgeModel
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
//
|
||||||
|
// XJHomeWatchModel.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/3/2.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface XJHomeWatchModel : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic, assign) CGFloat latest;
|
||||||
|
@property (nonatomic, assign) CGFloat max;
|
||||||
|
@property (nonatomic, assign) CGFloat min;
|
||||||
|
@property (nonatomic, assign) CGFloat avg;
|
||||||
|
|
||||||
|
@property (nonatomic, copy) NSString * latestTime;
|
||||||
|
@property (nonatomic, copy) NSString * watchNo;
|
||||||
|
@property (nonatomic, copy) NSString * lastUploadDate;
|
||||||
|
@property (nonatomic, copy) NSString * watchModel;
|
||||||
|
@property (nonatomic, copy) NSString * bindDate;
|
||||||
|
|
||||||
|
@property (nonatomic, assign) BOOL hasWatch;
|
||||||
|
|
||||||
|
//手表详情
|
||||||
|
@property (nonatomic, copy) NSString * type;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
//
|
||||||
|
// XJHomeWatchModel.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/3/2.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJHomeWatchModel.h"
|
||||||
|
|
||||||
|
@implementation XJHomeWatchModel
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
//
|
||||||
|
// XJOnePersonCaseModel.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// 一人一案 - 健康档案数据模型
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface XJOnePersonCaseModel : NSObject
|
||||||
|
|
||||||
|
#pragma mark - 基本信息
|
||||||
|
@property (nonatomic, strong) NSString *archiveId; // 档案ID(JSON: id)
|
||||||
|
@property (nonatomic, strong) NSString *empId; // 员工ID
|
||||||
|
@property (nonatomic, strong) NSString *name; // 员工姓名
|
||||||
|
@property (nonatomic, assign) NSInteger age; // 年龄
|
||||||
|
@property (nonatomic, strong) NSString *sexCode; // 性别
|
||||||
|
@property (nonatomic, strong) NSString *idNo; // 身份证号
|
||||||
|
@property (nonatomic, strong) NSString *phone; // 手机号
|
||||||
|
@property (nonatomic, strong) NSString *careStatus; // 关爱状态
|
||||||
|
@property (nonatomic, strong) NSString *workUnit; // 工作单位
|
||||||
|
@property (nonatomic, strong) NSString *workUnitId; // 单位ID
|
||||||
|
@property (nonatomic, assign) NSInteger dataLevel; // 数据级别
|
||||||
|
@property (nonatomic, strong) NSString *negativeList; // 负面清单
|
||||||
|
@property (nonatomic, strong) NSString *caseInfo; // 一人一案
|
||||||
|
@property (nonatomic, strong) NSString *riskLevel; // 风险等级
|
||||||
|
@property (nonatomic, strong) NSString *year; // 年度
|
||||||
|
@property (nonatomic, strong) NSString *careLiaisonName; // 关爱联络员姓名
|
||||||
|
|
||||||
|
#pragma mark - 体重 / BMI
|
||||||
|
@property (nonatomic, assign) NSInteger flagFat; // 肥胖人员标识(1-是,2-否)
|
||||||
|
@property (nonatomic, strong) NSString *bmi; // 体检BMI
|
||||||
|
@property (nonatomic, strong) NSString *height; // 身高(cm)
|
||||||
|
@property (nonatomic, strong) NSString *weight; // 体重(kg)
|
||||||
|
@property (nonatomic, strong) NSString *targetWeight; // 体重管理目标
|
||||||
|
@property (nonatomic, strong) NSString *targetBmi; // 目标BMI
|
||||||
|
@property (nonatomic, strong) NSString *bmiCurrent; // 目前BMI监测值
|
||||||
|
@property (nonatomic, strong) NSString *waistNew; // 最新腰围
|
||||||
|
@property (nonatomic, strong) NSString *bodyFatPercentNew; // 最新体脂率
|
||||||
|
@property (nonatomic, strong) NSString *weightRiskType; // 体重风险类型
|
||||||
|
|
||||||
|
#pragma mark - 高血压
|
||||||
|
@property (nonatomic, assign) NSInteger hypertension; // 高血压标识(0-否,1-是)
|
||||||
|
@property (nonatomic, strong) NSString *systolicPressureAvg; // 收缩压均值
|
||||||
|
@property (nonatomic, strong) NSString *systolicPressureTarget; // 收缩压控制目标
|
||||||
|
@property (nonatomic, strong) NSString *systolicPressureCurrent; // 收缩压当前检测值
|
||||||
|
@property (nonatomic, strong) NSString *diastolicPressureAvg; // 舒张压平均值
|
||||||
|
@property (nonatomic, strong) NSString *diastolicPressureTarget; // 舒张压控制目标值
|
||||||
|
@property (nonatomic, strong) NSString *diastolicPressureCurrent; // 舒张压当前检测值
|
||||||
|
|
||||||
|
#pragma mark - 糖尿病 / 血糖
|
||||||
|
@property (nonatomic, assign) NSInteger diabetes; // 糖尿病标识(0-否,1-是)
|
||||||
|
@property (nonatomic, strong) NSString *glu; // 空腹葡萄糖(GLU)
|
||||||
|
@property (nonatomic, strong) NSString *bloodSugarTarget; // 血糖控制目标值
|
||||||
|
@property (nonatomic, strong) NSString *bloodSugarCurrent; // 目前血糖监测值
|
||||||
|
|
||||||
|
#pragma mark - 血脂
|
||||||
|
@property (nonatomic, strong) NSString *ldl; // 低密度脂蛋白
|
||||||
|
@property (nonatomic, strong) NSString *ldlTarget; // 低密度脂蛋白目标控制值
|
||||||
|
@property (nonatomic, strong) NSString *ldlCurrent; // 低密度脂蛋白当前检测值
|
||||||
|
@property (nonatomic, strong) NSString *tc; // 总胆固醇
|
||||||
|
@property (nonatomic, strong) NSString *tcTarget; // 总胆固醇目标控制值
|
||||||
|
@property (nonatomic, strong) NSString *tcCurrent; // 总胆固醇目前监测值
|
||||||
|
@property (nonatomic, strong) NSString *tg; // 甘油三酯
|
||||||
|
@property (nonatomic, strong) NSString *tgTarget; // 甘油三酯目标控制值
|
||||||
|
@property (nonatomic, strong) NSString *tgCurrent; // 甘油三酯当前监测值
|
||||||
|
|
||||||
|
#pragma mark - 尿酸 / 同型半胱氨酸 / 其他指标
|
||||||
|
@property (nonatomic, strong) NSString *uricAcid; // 尿酸
|
||||||
|
@property (nonatomic, strong) NSString *uricAcidTarget; // 尿酸目标控制值
|
||||||
|
@property (nonatomic, strong) NSString *uricAcidCurrent; // 尿酸当前监测值
|
||||||
|
@property (nonatomic, strong) NSString *homocysteine; // 同型半胱氨酸
|
||||||
|
@property (nonatomic, strong) NSString *homocysteineTarget; // 同型半胱氨酸目标控制值
|
||||||
|
@property (nonatomic, strong) NSString *homocysteineCurrent; // 同型半胱氨酸当前监测值
|
||||||
|
@property (nonatomic, strong) NSString *bloodK; // 血钾
|
||||||
|
@property (nonatomic, strong) NSString *chd; // 冠心病
|
||||||
|
@property (nonatomic, strong) NSString *cvd; // 脑血管
|
||||||
|
@property (nonatomic, strong) NSString *af; // 心房颤动
|
||||||
|
@property (nonatomic, strong) NSString *ca; // 恶性肿瘤
|
||||||
|
@property (nonatomic, strong) NSString *indicatorListStr; // 检测指标列表
|
||||||
|
@property (nonatomic, strong) NSString *indicatorListStrOrigin; // 导入指标列表
|
||||||
|
@property (nonatomic, strong) NSString *screeningProjects; // 筛查项目汇总
|
||||||
|
|
||||||
|
#pragma mark - 方案与反馈
|
||||||
|
@property (nonatomic, strong) NSString *treatPlan; // 治疗方案
|
||||||
|
@property (nonatomic, strong) NSString *treatPlanResponse; // 治疗方案反馈
|
||||||
|
@property (nonatomic, strong) NSString *dietSuggestion; // 饮食建议
|
||||||
|
@property (nonatomic, strong) NSString *dietSuggestionResponse; // 饮食建议反馈
|
||||||
|
@property (nonatomic, strong) NSString *sportGuide; // 运动指导
|
||||||
|
@property (nonatomic, strong) NSString *sportGuideResponse; // 运动指导反馈
|
||||||
|
@property (nonatomic, strong) NSString *lifeManage; // 日常生活管理
|
||||||
|
@property (nonatomic, strong) NSString *lifeManageResponse; // 日常生活管理反馈
|
||||||
|
|
||||||
|
#pragma mark - 小屋 / 专家意见
|
||||||
|
@property (nonatomic, strong) NSString *cabinOpinion; // 小屋意见内容
|
||||||
|
@property (nonatomic, strong) NSString *cabinOpinionTime; // 小屋意见时间
|
||||||
|
@property (nonatomic, strong) NSString *cabinOpinionUserName; // 小屋意见员工姓名
|
||||||
|
@property (nonatomic, strong) NSString *expertOpinion; // 专家意见内容
|
||||||
|
@property (nonatomic, strong) NSString *expertOpinionTime; // 专家意见时间
|
||||||
|
@property (nonatomic, strong) NSString *expertOpinionUserName; // 专家意见员工姓名
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// XJOnePersonCaseModel.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// 一人一案 - 健康档案数据模型
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJOnePersonCaseModel.h"
|
||||||
|
|
||||||
|
@implementation XJOnePersonCaseModel
|
||||||
|
|
||||||
|
+ (NSDictionary *)modelCustomPropertyMapper {
|
||||||
|
return @{@"archiveId" : @"id"};
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
//
|
||||||
|
// BindWatchPopView.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/3/12.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
typedef NS_ENUM(NSInteger, BindWatchType) {
|
||||||
|
BindWatchTypeBind = 0, // 绑定
|
||||||
|
BindWatchTypeUnbind // 解绑
|
||||||
|
};
|
||||||
|
|
||||||
|
@interface BindWatchPopView : UIView
|
||||||
|
|
||||||
|
- (void)show;
|
||||||
|
|
||||||
|
@property (nonatomic, assign) BindWatchType type;
|
||||||
|
|
||||||
|
@property (nonatomic, copy) NSString *serialNumber;
|
||||||
|
|
||||||
|
@property (nonatomic, copy) void(^actionBlock)(BindWatchType type,
|
||||||
|
NSString *serialNumber);
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,364 @@
|
|||||||
|
//
|
||||||
|
// BindWatchPopView.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/3/12.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "BindWatchPopView.h"
|
||||||
|
|
||||||
|
@interface BindWatchPopView ()
|
||||||
|
|
||||||
|
@property (nonatomic,strong) UIView *bottomView;
|
||||||
|
|
||||||
|
@property (nonatomic,strong) UITextField *workNoField;
|
||||||
|
@property (nonatomic,strong) UITextField *nameField;
|
||||||
|
@property (nonatomic,strong) UITextField *numberField;
|
||||||
|
@property (nonatomic,strong) UIButton *actionBtn;
|
||||||
|
@property (nonatomic,strong) UIView *gestureView;
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation BindWatchPopView
|
||||||
|
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame {
|
||||||
|
|
||||||
|
if (self = [super initWithFrame:frame]) {
|
||||||
|
|
||||||
|
self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
|
||||||
|
|
||||||
|
[self createUI];
|
||||||
|
[self addKeyboardNotification];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UI
|
||||||
|
|
||||||
|
- (void)createUI {
|
||||||
|
|
||||||
|
|
||||||
|
self.bottomView = [[UIView alloc] init];
|
||||||
|
self.bottomView.backgroundColor = UIColor.whiteColor;
|
||||||
|
self.bottomView.layer.cornerRadius = 16;
|
||||||
|
self.bottomView.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner;
|
||||||
|
self.bottomView.layer.masksToBounds = YES;
|
||||||
|
[self addSubview:self.bottomView];
|
||||||
|
|
||||||
|
[self.bottomView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.bottom.offset(0);
|
||||||
|
make.height.offset(254 + SafetyAreaHeight);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 添加透明的手势响应区域(覆盖黑色背景)
|
||||||
|
UIView *gestureView = [[UIView alloc] init];
|
||||||
|
gestureView.backgroundColor = [UIColor clearColor];
|
||||||
|
gestureView.userInteractionEnabled = YES;
|
||||||
|
self.gestureView =gestureView;
|
||||||
|
[self addSubview:gestureView];
|
||||||
|
|
||||||
|
[gestureView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.top.offset(0);
|
||||||
|
make.bottom.equalTo(self.bottomView.mas_top);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(close)];
|
||||||
|
[gestureView addGestureRecognizer:tap];
|
||||||
|
|
||||||
|
/// 拖动条
|
||||||
|
UIView *indicator = [[UIView alloc] init];
|
||||||
|
indicator.backgroundColor = UIColorHex(#D8D8D8);
|
||||||
|
indicator.layer.cornerRadius = 3;
|
||||||
|
[self.bottomView addSubview:indicator];
|
||||||
|
|
||||||
|
[indicator mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.centerX.offset(0);
|
||||||
|
make.top.offset(8);
|
||||||
|
make.width.offset(40);
|
||||||
|
make.height.offset(6);
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
UILabel *titleLab = [[UILabel alloc] init];
|
||||||
|
titleLab.text = @"健康监测工具绑定";
|
||||||
|
titleLab.font = [UIFont boldSystemFontOfSize:16];
|
||||||
|
titleLab.textAlignment = NSTextAlignmentCenter;
|
||||||
|
[self.bottomView addSubview:titleLab];
|
||||||
|
|
||||||
|
[titleLab mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.offset(0);
|
||||||
|
make.top.offset(28);
|
||||||
|
}];
|
||||||
|
|
||||||
|
HQUserInfo * user = [HQCommonUtils keyedUnarchiverWithKey:LoginUserInfo];
|
||||||
|
|
||||||
|
UILabel * nameLabel = [[UILabel alloc] init];
|
||||||
|
nameLabel.textColor = UIColorHex(#808080);
|
||||||
|
nameLabel.font= [UIFont systemFontOfSize:15 weight:UIFontWeightRegular];
|
||||||
|
nameLabel.textAlignment = NSTextAlignmentLeft;
|
||||||
|
if (!ValidStr(user.realname)) {
|
||||||
|
nameLabel.text = [NSString stringWithFormat:@"%@",user.realname];
|
||||||
|
}
|
||||||
|
[self.bottomView addSubview:nameLabel];
|
||||||
|
|
||||||
|
// workLabel 先布局,固定右侧,宽度自适应内容,不压缩
|
||||||
|
UILabel * workLabel = [[UILabel alloc] init];
|
||||||
|
workLabel.textColor = UIColorHex(#808080);
|
||||||
|
workLabel.font = [UIFont systemFontOfSize:15 weight:UIFontWeightRegular];
|
||||||
|
workLabel.textAlignment = NSTextAlignmentRight;
|
||||||
|
// 工号不压缩、不拉伸
|
||||||
|
[workLabel setContentCompressionResistancePriority:UILayoutPriorityRequired
|
||||||
|
forAxis:UILayoutConstraintAxisHorizontal];
|
||||||
|
[workLabel setContentHuggingPriority:UILayoutPriorityRequired
|
||||||
|
forAxis:UILayoutConstraintAxisHorizontal];
|
||||||
|
if (!ValidStr(user.workNo)) {
|
||||||
|
workLabel.text = [NSString stringWithFormat:@"%@", user.workNo];
|
||||||
|
}
|
||||||
|
[self.bottomView addSubview:workLabel];
|
||||||
|
|
||||||
|
[workLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.mas_offset(-21);
|
||||||
|
make.top.mas_equalTo(titleLab.mas_bottom).offset(20);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// nameLabel 左侧固定,右侧距 workLabel 一个字符宽度,姓名优先占满剩余空间
|
||||||
|
[nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(16);
|
||||||
|
make.top.mas_equalTo(titleLab.mas_bottom).offset(20);
|
||||||
|
// 右侧距 workLabel 一个字符间距(约 15pt)
|
||||||
|
make.right.equalTo(workLabel.mas_left).offset(-15);
|
||||||
|
}];
|
||||||
|
// 姓名可压缩,优先级低于工号
|
||||||
|
[nameLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
|
||||||
|
forAxis:UILayoutConstraintAxisHorizontal];
|
||||||
|
[nameLabel setContentHuggingPriority:UILayoutPriorityDefaultLow
|
||||||
|
forAxis:UILayoutConstraintAxisHorizontal];
|
||||||
|
// self.workNoField = [self createTextField];
|
||||||
|
// self.workNoField.userInteractionEnabled = false;
|
||||||
|
// [self.bottomView addSubview:self.workNoField];
|
||||||
|
//
|
||||||
|
// [self.workNoField mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
// make.left.offset(82);
|
||||||
|
// make.right.offset(-15);
|
||||||
|
// make.height.offset(52);
|
||||||
|
// make.top.equalTo(titleLab.mas_bottom).offset(20);
|
||||||
|
// }];
|
||||||
|
//
|
||||||
|
//
|
||||||
|
UILabel * watchSNLab = [[UILabel alloc] init];
|
||||||
|
watchSNLab.text = @"心脑血管监测工具SN编码:";
|
||||||
|
watchSNLab.font = MEDIUMFONT(15);
|
||||||
|
watchSNLab.textAlignment = NSTextAlignmentLeft;
|
||||||
|
[self.bottomView addSubview:watchSNLab];
|
||||||
|
|
||||||
|
[watchSNLab mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_equalTo(nameLabel.mas_left);
|
||||||
|
make.right.mas_offset(-21);
|
||||||
|
make.top.mas_equalTo(nameLabel.mas_bottom).offset(15);
|
||||||
|
}];
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// self.nameField = [self createTextField];
|
||||||
|
// self.nameField.enabled = false;
|
||||||
|
// [self.bottomView addSubview:self.nameField];
|
||||||
|
//
|
||||||
|
// [self.nameField mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
// make.left.right.height.equalTo(self.workNoField);
|
||||||
|
// make.top.equalTo(self.workNoField.mas_bottom).offset(16);
|
||||||
|
// }];
|
||||||
|
// if (!ValidStr(user.realname)) {
|
||||||
|
// self.nameField.text = [NSString stringWithFormat:@"%@",user.realname];
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// UILabel *nameLab = [self createLabel:@"姓 名:"];
|
||||||
|
// [self.bottomView addSubview:nameLab];
|
||||||
|
//
|
||||||
|
// [nameLab mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
// make.left.offset(0);
|
||||||
|
// make.right.equalTo(self.nameField.mas_left);
|
||||||
|
// make.centerY.equalTo(self.nameField);
|
||||||
|
// }];
|
||||||
|
//
|
||||||
|
//
|
||||||
|
self.numberField = [self createTextField];
|
||||||
|
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:@"请输入SN编码" attributes:
|
||||||
|
@{NSForegroundColorAttributeName:UIColorHex(#B6B6B6),
|
||||||
|
NSFontAttributeName:[UIFont systemFontOfSize:16 weight:UIFontWeightMedium]}
|
||||||
|
];
|
||||||
|
self.numberField.attributedPlaceholder = attrString;
|
||||||
|
[self.bottomView addSubview:self.numberField];
|
||||||
|
|
||||||
|
[self.numberField mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(15);
|
||||||
|
make.right.mas_offset(-15);
|
||||||
|
make.height.mas_offset(52);
|
||||||
|
make.top.equalTo(watchSNLab.mas_bottom).offset(12);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UIView * lineV = [[UIView alloc] init];
|
||||||
|
lineV.backgroundColor = UIColorHex(#EAECF1);
|
||||||
|
[self.bottomView addSubview:lineV];
|
||||||
|
|
||||||
|
[lineV mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.mas_offset(0);
|
||||||
|
make.height.mas_offset(1);
|
||||||
|
make.top.mas_equalTo(self.numberField.mas_bottom).offset(12);
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
UIButton *bindBtn = [[UIButton alloc] init];
|
||||||
|
[bindBtn setTitle:@"解绑" forState:UIControlStateNormal];
|
||||||
|
bindBtn.backgroundColor = UIColorHex(#21BEBD);
|
||||||
|
bindBtn.layer.cornerRadius = 22;
|
||||||
|
bindBtn.titleLabel.font = [UIFont boldSystemFontOfSize:16];
|
||||||
|
[bindBtn addTarget:self action:@selector(bindwatchClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
self.actionBtn = bindBtn;
|
||||||
|
[self.bottomView addSubview:bindBtn];
|
||||||
|
|
||||||
|
[bindBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.centerX.offset(0);
|
||||||
|
make.width.offset(215);
|
||||||
|
make.height.offset(44);
|
||||||
|
make.top.equalTo(self.numberField.mas_bottom).offset(23);
|
||||||
|
}];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateUI {
|
||||||
|
|
||||||
|
if (self.type == BindWatchTypeUnbind) {
|
||||||
|
|
||||||
|
// 解绑页面:显示已绑定SN,按钮改为"绑定"并禁用(30%透明度,不可点击)
|
||||||
|
[self.actionBtn setTitle:@"绑定" forState:UIControlStateNormal];
|
||||||
|
self.actionBtn.alpha = 0.3;
|
||||||
|
self.actionBtn.userInteractionEnabled = NO;
|
||||||
|
self.numberField.text = self.serialNumber;
|
||||||
|
self.numberField.backgroundColor = UIColorHex(#F5F7FB);
|
||||||
|
self.numberField.enabled = NO;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// 绑定页面:正常可点击
|
||||||
|
[self.actionBtn setTitle:@"绑定" forState:UIControlStateNormal];
|
||||||
|
self.actionBtn.alpha = 1.0;
|
||||||
|
self.actionBtn.userInteractionEnabled = YES;
|
||||||
|
self.numberField.text = @"";
|
||||||
|
self.numberField.enabled = YES;
|
||||||
|
self.numberField.backgroundColor = KWhiteColor;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)bindwatchClick:(UIButton *)btn {
|
||||||
|
|
||||||
|
NSString *number = self.numberField.text;
|
||||||
|
|
||||||
|
if (self.actionBlock) {
|
||||||
|
self.actionBlock(self.type, number);
|
||||||
|
}
|
||||||
|
|
||||||
|
[self close];
|
||||||
|
}
|
||||||
|
#pragma mark - 创建控件
|
||||||
|
|
||||||
|
- (UILabel *)createLabel:(NSString *)text {
|
||||||
|
|
||||||
|
UILabel *lab = [[UILabel alloc] init];
|
||||||
|
lab.text = text;
|
||||||
|
lab.font = [UIFont systemFontOfSize:16];
|
||||||
|
lab.textAlignment = NSTextAlignmentCenter;
|
||||||
|
|
||||||
|
return lab;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UITextField *)createTextField {
|
||||||
|
|
||||||
|
UITextField *field = [[UITextField alloc] init];
|
||||||
|
field.backgroundColor = UIColorHex(#F5F7FB);
|
||||||
|
field.layer.cornerRadius = 8;
|
||||||
|
field.layer.borderWidth = 1;
|
||||||
|
field.layer.borderColor = UIColorHex(#E6E6EA).CGColor;
|
||||||
|
|
||||||
|
UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 12, 52)];
|
||||||
|
field.leftView = leftView;
|
||||||
|
field.leftViewMode = UITextFieldViewModeAlways;
|
||||||
|
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)close {
|
||||||
|
|
||||||
|
[self endEditing:YES];
|
||||||
|
|
||||||
|
[UIView animateWithDuration:0.25 animations:^{
|
||||||
|
self.bottomView.transform = CGAffineTransformMakeTranslation(0, 342);
|
||||||
|
self.alpha = 0;
|
||||||
|
} completion:^(BOOL finished) {
|
||||||
|
[self removeFromSuperview];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - 键盘
|
||||||
|
|
||||||
|
- (void)addKeyboardNotification {
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardShow:) name:UIKeyboardWillShowNotification object:nil];
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardHide:) name:UIKeyboardWillHideNotification object:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)keyboardShow:(NSNotification *)noti {
|
||||||
|
|
||||||
|
CGRect rect = [noti.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||||
|
CGFloat keyboardH = rect.size.height;
|
||||||
|
|
||||||
|
[UIView animateWithDuration:0.25 animations:^{
|
||||||
|
self.bottomView.transform = CGAffineTransformMakeTranslation(0, -keyboardH);
|
||||||
|
// 同步缩小 gestureView,避免手势区域覆盖 bottomView 上的按钮
|
||||||
|
[self.gestureView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.bottom.equalTo(self.bottomView.mas_top).offset(-keyboardH);
|
||||||
|
}];
|
||||||
|
[self layoutIfNeeded];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)keyboardHide:(NSNotification *)noti {
|
||||||
|
|
||||||
|
[UIView animateWithDuration:0.25 animations:^{
|
||||||
|
self.bottomView.transform = CGAffineTransformIdentity;
|
||||||
|
// 恢复 gestureView 约束
|
||||||
|
[self.gestureView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.bottom.equalTo(self.bottomView.mas_top).offset(0);
|
||||||
|
}];
|
||||||
|
[self layoutIfNeeded];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - show
|
||||||
|
|
||||||
|
- (void)show {
|
||||||
|
|
||||||
|
[self updateUI];
|
||||||
|
|
||||||
|
UIWindow *window = UIApplication.sharedApplication.keyWindow;
|
||||||
|
|
||||||
|
self.frame = window.bounds;
|
||||||
|
|
||||||
|
[window addSubview:self];
|
||||||
|
|
||||||
|
self.bottomView.transform = CGAffineTransformMakeTranslation(0, 342);
|
||||||
|
|
||||||
|
[UIView animateWithDuration:0.25 animations:^{
|
||||||
|
self.bottomView.transform = CGAffineTransformIdentity;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// XJHealthKnowledgeCell.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/6/29.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@class XJHealthKnowledgeModel;
|
||||||
|
|
||||||
|
@interface XJHealthKnowledgeCell : UITableViewCell
|
||||||
|
|
||||||
|
@property (nonatomic, strong) XJHealthKnowledgeModel * model;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
//
|
||||||
|
// XJHealthKnowledgeCell.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/6/29.
|
||||||
|
//
|
||||||
|
// ┌──────────────────────────────────────────────┐
|
||||||
|
// │ │ ← cell 高 130
|
||||||
|
// │ ┌──────────┐ ┌────────────────────────┐ │
|
||||||
|
// │ │ 图片 │ │ 标题 #252535 Bold 15 │ │ ← 标题 top = 图片 top + 5
|
||||||
|
// │ │ 100×100 │ │ │ │
|
||||||
|
// │ │ 圆角15 │ ├────────────────────────┤ │
|
||||||
|
// │ │ 上下居中 │ │ 描述 #77849E 13 Medium │ │ ← 描述 top = 标题 bottom + 15
|
||||||
|
// │ │ │ │ 最多 2 行 │ │
|
||||||
|
// │ │ │ ├────────────────────────┤ │
|
||||||
|
// │ │ │ │ [图20] 标签|标签 │ │ ← 图标 bottom = 图片 bottom - 5
|
||||||
|
// │ └──────────┘ │ 时间 → │ │ ← 时间 bottom = 图片 bottom - 9
|
||||||
|
// │ └────────────────────────┘ │
|
||||||
|
// │ ──────────────────────────────────────── │ ← 分割线 left=标题, right=-15
|
||||||
|
// └──────────────────────────────────────────────┘
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJHealthKnowledgeCell.h"
|
||||||
|
#import "XJHealthKnowledgeModel.h"
|
||||||
|
|
||||||
|
@interface XJHealthKnowledgeCell ()
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UIImageView * leftImageView;
|
||||||
|
@property (nonatomic, strong) UILabel * titleLabel;
|
||||||
|
@property (nonatomic, strong) UILabel * descLabel;
|
||||||
|
@property (nonatomic, strong) UIImageView * tagIcon;
|
||||||
|
@property (nonatomic, strong) UILabel * tagLabel;
|
||||||
|
@property (nonatomic, strong) UILabel * timeLabel;
|
||||||
|
@property (nonatomic, strong) UIView * separatorLine;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation XJHealthKnowledgeCell
|
||||||
|
|
||||||
|
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||||
|
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
|
||||||
|
self.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||||
|
[self createUI];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)createUI {
|
||||||
|
|
||||||
|
// 左侧图片 100×100 圆角 15
|
||||||
|
self.leftImageView = [[UIImageView alloc] init];
|
||||||
|
self.leftImageView.layer.cornerRadius = 15;
|
||||||
|
self.leftImageView.layer.masksToBounds = YES;
|
||||||
|
self.leftImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||||
|
[self.contentView addSubview:self.leftImageView];
|
||||||
|
|
||||||
|
[self.leftImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(15);
|
||||||
|
make.centerY.mas_equalTo(self.contentView);
|
||||||
|
make.width.height.mas_offset(100);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 标题 #252535 Bold 15,右间距 -22
|
||||||
|
self.titleLabel = [[UILabel alloc] init];
|
||||||
|
self.titleLabel.textColor = UIColorHex(#252535);
|
||||||
|
self.titleLabel.font = BOLDSYSTEMFONT(15);
|
||||||
|
self.titleLabel.textAlignment = NSTextAlignmentLeft;
|
||||||
|
self.titleLabel.numberOfLines = 1;
|
||||||
|
[self.contentView addSubview:self.titleLabel];
|
||||||
|
|
||||||
|
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_equalTo(self.leftImageView.mas_right).offset(15);
|
||||||
|
make.top.mas_equalTo(self.leftImageView.mas_top).offset(5);
|
||||||
|
make.right.mas_offset(-22);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 描述 #77849E 13 Medium,最多 2 行,距标题底部 15
|
||||||
|
self.descLabel = [[UILabel alloc] init];
|
||||||
|
self.descLabel.textColor = UIColorHex(#77849E);
|
||||||
|
self.descLabel.font = MEDIUMFONT(13);
|
||||||
|
self.descLabel.textAlignment = NSTextAlignmentLeft;
|
||||||
|
self.descLabel.numberOfLines = 2;
|
||||||
|
[self.contentView addSubview:self.descLabel];
|
||||||
|
|
||||||
|
[self.descLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_equalTo(self.titleLabel.mas_left);
|
||||||
|
make.top.mas_equalTo(self.titleLabel.mas_bottom).offset(15);
|
||||||
|
make.right.mas_offset(-22);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 时间 #77849E 11 Medium,右对齐,bottom = 图片 bottom - 9(必须放在 tagLabel 前面,tagLabel 引用了它)
|
||||||
|
self.timeLabel = [[UILabel alloc] init];
|
||||||
|
self.timeLabel.textColor = UIColorHex(#77849E);
|
||||||
|
self.timeLabel.font = MEDIUMFONT(11);
|
||||||
|
self.timeLabel.textAlignment = NSTextAlignmentRight;
|
||||||
|
self.timeLabel.numberOfLines = 1;
|
||||||
|
[self.contentView addSubview:self.timeLabel];
|
||||||
|
|
||||||
|
[self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.mas_offset(-15);
|
||||||
|
make.bottom.mas_equalTo(self.leftImageView.mas_bottom).offset(-9);
|
||||||
|
}];
|
||||||
|
[self.timeLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
|
||||||
|
|
||||||
|
// 标签图标 20×20,bottom = 图片 bottom - 5
|
||||||
|
self.tagIcon = [[UIImageView alloc] init];
|
||||||
|
self.tagIcon.image = [UIImage imageNamed:@"article_classIcon"];
|
||||||
|
self.tagIcon.contentMode = UIViewContentModeScaleAspectFit;
|
||||||
|
[self.contentView addSubview:self.tagIcon];
|
||||||
|
|
||||||
|
[self.tagIcon mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_equalTo(self.titleLabel.mas_left);
|
||||||
|
make.bottom.mas_equalTo(self.leftImageView.mas_bottom).offset(-5);
|
||||||
|
make.width.height.mas_offset(20);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 标签文字 #14BEBE 11 Medium(引用 timeLabel,已在前方创建)
|
||||||
|
self.tagLabel = [[UILabel alloc] init];
|
||||||
|
self.tagLabel.textColor = UIColorHex(#14BEBE);
|
||||||
|
self.tagLabel.font = MEDIUMFONT(11);
|
||||||
|
self.tagLabel.textAlignment = NSTextAlignmentLeft;
|
||||||
|
self.tagLabel.numberOfLines = 1;
|
||||||
|
[self.contentView addSubview:self.tagLabel];
|
||||||
|
|
||||||
|
[self.tagLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_equalTo(self.tagIcon.mas_right).offset(5);
|
||||||
|
make.centerY.mas_equalTo(self.tagIcon);
|
||||||
|
make.right.mas_lessThanOrEqualTo(self.timeLabel.mas_left).offset(-8);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 分割线 #EAECF1 h1,左对齐标题,右 -15
|
||||||
|
self.separatorLine = [[UIView alloc] init];
|
||||||
|
self.separatorLine.backgroundColor = UIColorHex(#EAECF1);
|
||||||
|
[self.contentView addSubview:self.separatorLine];
|
||||||
|
|
||||||
|
[self.separatorLine mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_equalTo(self.titleLabel.mas_left);
|
||||||
|
make.right.mas_offset(-15);
|
||||||
|
make.bottom.mas_offset(-1);
|
||||||
|
make.height.mas_offset(1);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setModel:(XJHealthKnowledgeModel *)model {
|
||||||
|
_model = model;
|
||||||
|
|
||||||
|
self.titleLabel.text = model.title;
|
||||||
|
self.descLabel.text = model.content;
|
||||||
|
self.timeLabel.text = [self dateString:model.createTime];
|
||||||
|
|
||||||
|
// 标签 #健康资讯#肝癌 → 健康资讯 | 肝癌
|
||||||
|
self.tagLabel.text = [self formatTagString:model.tags];
|
||||||
|
|
||||||
|
// 图片 URL 是完整地址,直接加载
|
||||||
|
if (!ValidStr(model.imageUrl)) {
|
||||||
|
NSString * photo = model.imageUrl;
|
||||||
|
// http → https
|
||||||
|
if ([photo hasPrefix:@"http://"]) {
|
||||||
|
photo = [photo stringByReplacingOccurrencesOfString:@"http://" withString:@"https://"];
|
||||||
|
}
|
||||||
|
[self.leftImageView sd_setImageWithURL:[NSURL URLWithString:photo] placeholderImage:[UIImage imageNamed:@"article_placholdIMg"]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// #健康资讯#肝癌 → 健康资讯 | 肝癌
|
||||||
|
- (NSString *)formatTagString:(NSString *)tagStr {
|
||||||
|
if (ValidStr(tagStr)) return tagStr ?: @"";
|
||||||
|
NSString * result = tagStr;
|
||||||
|
// 去掉首尾的 #
|
||||||
|
if ([result hasPrefix:@"#"]) result = [result substringFromIndex:1];
|
||||||
|
if ([result hasSuffix:@"#"]) result = [result substringToIndex:result.length - 1];
|
||||||
|
// 中间的 # 替换为 |
|
||||||
|
result = [result stringByReplacingOccurrencesOfString:@"#" withString:@" | "];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 截取日期部分 "2026-04-23 15:28:57" → "2026-04-23",容错处理
|
||||||
|
- (NSString *)dateString:(NSString *)datetime {
|
||||||
|
if (!datetime || ![datetime isKindOfClass:[NSString class]] || datetime.length == 0) return @"";
|
||||||
|
NSArray *parts = [datetime componentsSeparatedByString:@" "];
|
||||||
|
return parts.firstObject ?: datetime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
//
|
||||||
|
// XJHealthKnowledgeView.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/6/29.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@class XJHealthKnowledgeModel;
|
||||||
|
|
||||||
|
@interface XJHealthKnowledgeView : UIView
|
||||||
|
|
||||||
|
/// 数据源
|
||||||
|
@property (nonatomic, strong) NSArray<XJHealthKnowledgeModel *> * dataArray;
|
||||||
|
/// 标签标题数组
|
||||||
|
@property (nonatomic, strong) NSArray<NSString *> * tabTitles;
|
||||||
|
/// 当前选中标签索引
|
||||||
|
@property (nonatomic, assign) NSInteger selectedTabIndex;
|
||||||
|
|
||||||
|
/// 点击"更多"
|
||||||
|
@property (nonatomic, copy) void (^moreBlock)(void);
|
||||||
|
/// 点击搜索按钮
|
||||||
|
@property (nonatomic, copy) void (^searchBlock)(NSString * keyword);
|
||||||
|
/// 搜索框开始编辑(用于键盘避让)
|
||||||
|
@property (nonatomic, copy) void (^searchBeginBlock)(void);
|
||||||
|
/// 标签切换回调
|
||||||
|
@property (nonatomic, copy) void (^tabSelectBlock)(NSInteger index);
|
||||||
|
/// 点击 cell
|
||||||
|
@property (nonatomic, copy) void (^cellSelectBlock)(XJHealthKnowledgeModel * model);
|
||||||
|
|
||||||
|
/// 计算当前总高度
|
||||||
|
- (CGFloat)totalHeight;
|
||||||
|
|
||||||
|
/// 显示未登录占位
|
||||||
|
- (void)showNotLoggedInPlaceholder;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,434 @@
|
|||||||
|
//
|
||||||
|
// XJHealthKnowledgeView.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/6/29.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJHealthKnowledgeView.h"
|
||||||
|
#import "XJHealthKnowledgeModel.h"
|
||||||
|
#import "XJHealthKnowledgeCell.h"
|
||||||
|
|
||||||
|
static CGFloat const kHeaderHeight = 40;
|
||||||
|
static CGFloat const kSearchBoxHeight = 36;
|
||||||
|
static CGFloat const kCellHeight = 130;
|
||||||
|
static CGFloat const kMaxCellCount = 3;
|
||||||
|
static CGFloat const kTabButtonGap = 43;
|
||||||
|
static CGFloat const kDefaultEmptyHeight = 200;
|
||||||
|
|
||||||
|
// 标签区:文字 14pt(≈17) + 指示间距6 + 指示2 + 分割间距9 + 分割1 = ~35
|
||||||
|
static CGFloat const kTabAreaHeight = 48;
|
||||||
|
|
||||||
|
@interface XJHealthKnowledgeView () <UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate>
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UIView * headerView;
|
||||||
|
@property (nonatomic, strong) UIImageView * headerBgImg;
|
||||||
|
@property (nonatomic, strong) UILabel * titleLabel;
|
||||||
|
@property (nonatomic, strong) UIButton * moreBtn;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UIView * searchContainer;
|
||||||
|
@property (nonatomic, strong) UIImageView * searchIcon;
|
||||||
|
@property (nonatomic, strong) UITextField * searchTextField;
|
||||||
|
@property (nonatomic, strong) UIButton * searchBtn;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UIScrollView * tabScrollView;
|
||||||
|
@property (nonatomic, strong) NSMutableArray<UIButton *> * tabButtons;
|
||||||
|
@property (nonatomic, strong) UIView * indicatorView;
|
||||||
|
@property (nonatomic, strong) UIView * tabSeparator;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UITableView * listTableView;
|
||||||
|
@property (nonatomic, strong) UILabel * emptyLabel;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation XJHealthKnowledgeView
|
||||||
|
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame {
|
||||||
|
if (self = [super initWithFrame:frame]) {
|
||||||
|
self.backgroundColor = KWhiteColor;
|
||||||
|
self.layer.cornerRadius = 12;
|
||||||
|
self.layer.masksToBounds = YES;
|
||||||
|
self.tabButtons = [[NSMutableArray alloc] init];
|
||||||
|
[self createUI];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— UI 搭建 —————
|
||||||
|
|
||||||
|
- (void)createUI {
|
||||||
|
|
||||||
|
// 头部
|
||||||
|
self.headerView = [[UIView alloc] init];
|
||||||
|
[self addSubview:self.headerView];
|
||||||
|
[self.headerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.top.mas_offset(0);
|
||||||
|
make.height.mas_offset(kRealValue(kHeaderHeight));
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.headerBgImg = [[UIImageView alloc] init];
|
||||||
|
self.headerBgImg.image = [UIImage imageNamed:@"heaedTitleBackImg"];
|
||||||
|
[self.headerView addSubview:self.headerBgImg];
|
||||||
|
[self.headerBgImg mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.edges.mas_offset(0);
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.titleLabel = [[UILabel alloc] init];
|
||||||
|
self.titleLabel.text = @"健康知识";
|
||||||
|
self.titleLabel.textColor = CFontColor1;
|
||||||
|
self.titleLabel.font = BOLDSYSTEMFONT(16);
|
||||||
|
[self.headerView addSubview:self.titleLabel];
|
||||||
|
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(13);
|
||||||
|
make.centerY.mas_equalTo(self.headerView);
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.moreBtn = [[UIButton alloc] init];
|
||||||
|
[self.moreBtn setImage:[UIImage imageNamed:@"wacthRightAccow"] forState:UIControlStateNormal];
|
||||||
|
[self.moreBtn addTarget:self action:@selector(moreAction) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
[self.headerView addSubview:self.moreBtn];
|
||||||
|
[self.moreBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.mas_offset(-8);
|
||||||
|
make.centerY.mas_equalTo(self.headerView);
|
||||||
|
make.width.height.mas_offset(30);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 搜索框 - 圆角 18 背景 #F5F7FB
|
||||||
|
self.searchContainer = [[UIView alloc] init];
|
||||||
|
self.searchContainer.backgroundColor = UIColorHex(#F5F7FB);
|
||||||
|
self.searchContainer.layer.cornerRadius = 18;
|
||||||
|
self.searchContainer.layer.masksToBounds = YES;
|
||||||
|
self.searchContainer.hidden = YES; // 初始隐藏,等数据来了再显示
|
||||||
|
[self addSubview:self.searchContainer];
|
||||||
|
[self.searchContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(15);
|
||||||
|
make.right.mas_offset(-15);
|
||||||
|
make.top.mas_equalTo(self.headerView.mas_bottom).offset(10);
|
||||||
|
make.height.mas_offset(kSearchBoxHeight);
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.searchIcon = [[UIImageView alloc] init];
|
||||||
|
self.searchIcon.image = [UIImage imageNamed:@"searchLeftIcon"];
|
||||||
|
self.searchIcon.contentMode = UIViewContentModeScaleAspectFit;
|
||||||
|
[self.searchContainer addSubview:self.searchIcon];
|
||||||
|
[self.searchIcon mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(15);
|
||||||
|
make.centerY.mas_equalTo(self.searchContainer);
|
||||||
|
make.width.height.mas_offset(14);
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.searchBtn = [[UIButton alloc] init];
|
||||||
|
self.searchBtn.backgroundColor = UIColorHex(#14BEBE);
|
||||||
|
self.searchBtn.layer.cornerRadius = 14;
|
||||||
|
self.searchBtn.layer.masksToBounds = YES;
|
||||||
|
[self.searchBtn setTitle:@"搜索" forState:UIControlStateNormal];
|
||||||
|
[self.searchBtn setTitleColor:KWhiteColor forState:UIControlStateNormal];
|
||||||
|
self.searchBtn.titleLabel.font = MEDIUMFONT(14);
|
||||||
|
[self.searchBtn addTarget:self action:@selector(searchAction) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
[self.searchContainer addSubview:self.searchBtn];
|
||||||
|
[self.searchBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.mas_offset(0);
|
||||||
|
make.centerY.mas_equalTo(self.searchContainer);
|
||||||
|
make.width.mas_offset(55);
|
||||||
|
make.height.mas_offset(28);
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.searchTextField = [[UITextField alloc] init];
|
||||||
|
self.searchTextField.placeholder = @"请输入关键字进行搜索";
|
||||||
|
self.searchTextField.font = [UIFont systemFontOfSize:13 weight:UIFontWeightRegular];
|
||||||
|
self.searchTextField.textColor = UIColorHex(#252535);
|
||||||
|
// placeholder 颜色
|
||||||
|
self.searchTextField.attributedPlaceholder = [[NSAttributedString alloc]
|
||||||
|
initWithString:@"请输入关键字进行搜索"
|
||||||
|
attributes:@{NSForegroundColorAttributeName: UIColorHex(#B6B6B6)}];
|
||||||
|
self.searchTextField.delegate = self;
|
||||||
|
[self.searchContainer addSubview:self.searchTextField];
|
||||||
|
[self.searchTextField mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_equalTo(self.searchIcon.mas_right).offset(8);
|
||||||
|
make.right.mas_equalTo(self.searchBtn.mas_left).offset(-8);
|
||||||
|
make.centerY.mas_equalTo(self.searchContainer);
|
||||||
|
make.height.mas_equalTo(self.searchContainer);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 标签切换区
|
||||||
|
self.tabScrollView = [[UIScrollView alloc] init];
|
||||||
|
self.tabScrollView.showsHorizontalScrollIndicator = NO;
|
||||||
|
self.tabScrollView.showsVerticalScrollIndicator = NO;
|
||||||
|
self.tabScrollView.hidden = YES; // 初始隐藏
|
||||||
|
[self addSubview:self.tabScrollView];
|
||||||
|
[self.tabScrollView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.mas_offset(0);
|
||||||
|
make.top.mas_equalTo(self.searchContainer.mas_bottom).offset(12);
|
||||||
|
make.height.mas_offset(kTabAreaHeight);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 指示条 13×2
|
||||||
|
self.indicatorView = [[UIView alloc] init];
|
||||||
|
self.indicatorView.backgroundColor = UIColorHex(#14BEBE);
|
||||||
|
self.indicatorView.layer.cornerRadius = 1;
|
||||||
|
self.indicatorView.layer.masksToBounds = YES;
|
||||||
|
self.indicatorView.hidden = YES;
|
||||||
|
[self.tabScrollView addSubview:self.indicatorView];
|
||||||
|
|
||||||
|
// 分割线 在指示条底部 +9
|
||||||
|
self.tabSeparator = [[UIView alloc] init];
|
||||||
|
self.tabSeparator.backgroundColor = UIColorHex(#EAECF1);
|
||||||
|
[self.tabScrollView addSubview:self.tabSeparator];
|
||||||
|
|
||||||
|
// 列表
|
||||||
|
self.listTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
|
||||||
|
self.listTableView.delegate = self;
|
||||||
|
self.listTableView.dataSource = self;
|
||||||
|
self.listTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||||
|
self.listTableView.scrollEnabled = NO;
|
||||||
|
self.listTableView.rowHeight = kCellHeight;
|
||||||
|
self.listTableView.backgroundColor = KWhiteColor;
|
||||||
|
self.listTableView.hidden = YES; // 初始隐藏
|
||||||
|
if (@available(iOS 15.0, *)) {
|
||||||
|
self.listTableView.sectionHeaderTopPadding = 0;
|
||||||
|
}
|
||||||
|
[self addSubview:self.listTableView];
|
||||||
|
[self.listTableView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.mas_offset(0);
|
||||||
|
make.top.mas_equalTo(self.tabScrollView.mas_bottom);
|
||||||
|
make.height.mas_offset(0);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 空状态 - 放在 tabScrollView 下方
|
||||||
|
self.emptyLabel = [[UILabel alloc] init];
|
||||||
|
self.emptyLabel.text = @"暂无健康知识";
|
||||||
|
self.emptyLabel.textColor = UIColorHex(#14BEBE);
|
||||||
|
self.emptyLabel.font = [UIFont systemFontOfSize:15];
|
||||||
|
self.emptyLabel.textAlignment = NSTextAlignmentCenter;
|
||||||
|
self.emptyLabel.hidden = YES;
|
||||||
|
[self addSubview:self.emptyLabel];
|
||||||
|
[self.emptyLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.centerX.mas_equalTo(self);
|
||||||
|
make.top.mas_equalTo(self.tabScrollView.mas_bottom).offset(40);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— Setter —————
|
||||||
|
|
||||||
|
- (void)setDataArray:(NSArray<XJHealthKnowledgeModel *> *)dataArray {
|
||||||
|
_dataArray = dataArray;
|
||||||
|
|
||||||
|
BOOL hasData = dataArray.count > 0;
|
||||||
|
|
||||||
|
self.listTableView.hidden = !hasData;
|
||||||
|
self.emptyLabel.hidden = hasData;
|
||||||
|
|
||||||
|
if (hasData) {
|
||||||
|
[self.listTableView reloadData];
|
||||||
|
CGFloat tableH = MIN(dataArray.count, kMaxCellCount) * kCellHeight;
|
||||||
|
[self.listTableView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.mas_offset(0);
|
||||||
|
make.top.mas_equalTo(self.tabScrollView.mas_bottom);
|
||||||
|
make.height.mas_offset(tableH);
|
||||||
|
}];
|
||||||
|
} else {
|
||||||
|
[self.listTableView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.mas_offset(0);
|
||||||
|
make.top.mas_equalTo(self.tabScrollView.mas_bottom);
|
||||||
|
make.height.mas_offset(0);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setTabTitles:(NSArray<NSString *> *)tabTitles {
|
||||||
|
_tabTitles = tabTitles;
|
||||||
|
|
||||||
|
for (UIButton * btn in self.tabButtons) {
|
||||||
|
[btn removeFromSuperview];
|
||||||
|
}
|
||||||
|
[self.tabButtons removeAllObjects];
|
||||||
|
|
||||||
|
self.tabScrollView.hidden = (tabTitles.count == 0);
|
||||||
|
self.searchContainer.hidden = (tabTitles.count == 0);
|
||||||
|
|
||||||
|
if (tabTitles.count == 0) {
|
||||||
|
self.indicatorView.hidden = YES;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.indicatorView.hidden = NO;
|
||||||
|
|
||||||
|
// 按钮高度给满 kTabAreaHeight 让点击范围大
|
||||||
|
CGFloat btnHeight = kTabAreaHeight - 2 - 6 - 9 - 1; // 文字区域 ≈30pt
|
||||||
|
CGFloat btnTop = 0;
|
||||||
|
|
||||||
|
CGFloat leftOffset = 15;
|
||||||
|
for (NSInteger i = 0; i < tabTitles.count; i++) {
|
||||||
|
NSString * title = tabTitles[i];
|
||||||
|
|
||||||
|
CGSize textSize = [title sizeWithAttributes:@{NSFontAttributeName: BOLDSYSTEMFONT(14)}];
|
||||||
|
CGFloat btnWidth = ceil(textSize.width) + 4; // 左右各留 2pt
|
||||||
|
|
||||||
|
// 透明大按钮包住文字区域
|
||||||
|
UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
|
[btn setTitle:title forState:UIControlStateNormal];
|
||||||
|
btn.titleLabel.font = (i == self.selectedTabIndex) ? BOLDSYSTEMFONT(14) : [UIFont systemFontOfSize:14 weight:UIFontWeightRegular];
|
||||||
|
[btn setTitleColor:(i == self.selectedTabIndex) ? UIColorHex(#14BEBE) : UIColorHex(#808080) forState:UIControlStateNormal];
|
||||||
|
btn.backgroundColor = KClearColor;
|
||||||
|
btn.tag = i;
|
||||||
|
[btn addTarget:self action:@selector(tabButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
btn.frame = CGRectMake(leftOffset, btnTop, btnWidth, btnHeight);
|
||||||
|
[self.tabScrollView addSubview:btn];
|
||||||
|
[self.tabButtons addObject:btn];
|
||||||
|
|
||||||
|
leftOffset += btnWidth + kTabButtonGap;
|
||||||
|
}
|
||||||
|
|
||||||
|
leftOffset += 15 - kTabButtonGap;
|
||||||
|
self.tabScrollView.contentSize = CGSizeMake(leftOffset, kTabAreaHeight);
|
||||||
|
|
||||||
|
// 更新分割线位置:在标签区底部
|
||||||
|
self.tabSeparator.frame = CGRectMake(0, kTabAreaHeight - 1, MAX(leftOffset, self.tabScrollView.bounds.size.width), 1);
|
||||||
|
|
||||||
|
// 强制布局,确保按钮 titleLabel.frame 计算正确
|
||||||
|
[self.tabScrollView layoutIfNeeded];
|
||||||
|
|
||||||
|
if (self.tabButtons.count > 0) {
|
||||||
|
[self updateIndicatorPosition:self.selectedTabIndex animated:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setSelectedTabIndex:(NSInteger)selectedTabIndex {
|
||||||
|
if (selectedTabIndex < 0 || selectedTabIndex >= self.tabButtons.count) return;
|
||||||
|
_selectedTabIndex = selectedTabIndex;
|
||||||
|
|
||||||
|
for (NSInteger i = 0; i < self.tabButtons.count; i++) {
|
||||||
|
UIButton * btn = self.tabButtons[i];
|
||||||
|
if (i == selectedTabIndex) {
|
||||||
|
[btn setTitleColor:UIColorHex(#14BEBE) forState:UIControlStateNormal];
|
||||||
|
btn.titleLabel.font = BOLDSYSTEMFONT(14);
|
||||||
|
} else {
|
||||||
|
[btn setTitleColor:UIColorHex(#808080) forState:UIControlStateNormal];
|
||||||
|
btn.titleLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightRegular];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[self.tabScrollView layoutIfNeeded];
|
||||||
|
[self updateIndicatorPosition:selectedTabIndex animated:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)showNotLoggedInPlaceholder {
|
||||||
|
self.dataArray = @[];
|
||||||
|
self.tabTitles = nil;
|
||||||
|
self.emptyLabel.text = @"暂未登录";
|
||||||
|
self.emptyLabel.textColor = [UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:1.0];
|
||||||
|
self.emptyLabel.hidden = NO;
|
||||||
|
// 未登录时在头部下方区域上下居中
|
||||||
|
[self.emptyLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.centerX.mas_equalTo(self);
|
||||||
|
make.top.mas_equalTo(self.headerView.mas_bottom);
|
||||||
|
make.bottom.mas_equalTo(self);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— 高度计算 —————
|
||||||
|
|
||||||
|
- (CGFloat)totalHeight {
|
||||||
|
BOOL hasTabs = self.tabTitles.count > 0;
|
||||||
|
BOOL hasData = self.dataArray.count > 0;
|
||||||
|
|
||||||
|
if (!hasTabs) {
|
||||||
|
return kDefaultEmptyHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 头部(40) + 10 + 搜索(36) + 12 + 标签(48) + 列表/空区域
|
||||||
|
CGFloat base = kRealValue(kHeaderHeight) + 10 + kSearchBoxHeight + 12 + kTabAreaHeight;
|
||||||
|
if (hasData) {
|
||||||
|
CGFloat tableH = MIN(self.dataArray.count, kMaxCellCount) * kCellHeight;
|
||||||
|
return base + tableH;
|
||||||
|
} else {
|
||||||
|
return base + 80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— 私有 —————
|
||||||
|
|
||||||
|
- (void)updateIndicatorPosition:(NSInteger)index animated:(BOOL)animated {
|
||||||
|
if (index < 0 || index >= self.tabButtons.count) return;
|
||||||
|
|
||||||
|
UIButton * selectedBtn = self.tabButtons[index];
|
||||||
|
|
||||||
|
CGFloat indicatorW = 13;
|
||||||
|
CGFloat indicatorH = 2;
|
||||||
|
CGFloat indicatorX = selectedBtn.center.x - indicatorW / 2;
|
||||||
|
// 文字底部 +6
|
||||||
|
CGFloat textBottom = CGRectGetMaxY(selectedBtn.titleLabel.frame);
|
||||||
|
// 兜底:14pt 字体行高 ≈ 17,垂直居中
|
||||||
|
if (textBottom <= 0) {
|
||||||
|
CGFloat lineH = 17;
|
||||||
|
textBottom = (selectedBtn.frame.size.height - lineH) / 2.0 + lineH;
|
||||||
|
}
|
||||||
|
CGFloat indicatorY = textBottom + 6;
|
||||||
|
|
||||||
|
void (^updateBlock)(void) = ^{
|
||||||
|
self.indicatorView.frame = CGRectMake(indicatorX, indicatorY, indicatorW, indicatorH);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (animated) {
|
||||||
|
[UIView animateWithDuration:0.25 animations:updateBlock];
|
||||||
|
} else {
|
||||||
|
updateBlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— 事件 —————
|
||||||
|
|
||||||
|
- (void)moreAction {
|
||||||
|
if (self.moreBlock) self.moreBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)searchAction {
|
||||||
|
if (self.searchBlock) self.searchBlock(self.searchTextField.text ?: @"");
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tabButtonTapped:(UIButton *)sender {
|
||||||
|
if (sender.tag == self.selectedTabIndex) return;
|
||||||
|
self.selectedTabIndex = sender.tag;
|
||||||
|
if (self.tabSelectBlock) self.tabSelectBlock(sender.tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— UITextFieldDelegate —————
|
||||||
|
|
||||||
|
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)textFieldDidBeginEditing:(UITextField *)textField {
|
||||||
|
if (self.searchBeginBlock) self.searchBeginBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||||
|
[textField resignFirstResponder];
|
||||||
|
if (self.searchBlock) self.searchBlock(textField.text ?: @"");
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— UITableViewDataSource —————
|
||||||
|
|
||||||
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||||
|
return MIN(self.dataArray.count, kMaxCellCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
static NSString * cellID = @"XJHealthKnowledgeCell";
|
||||||
|
XJHealthKnowledgeCell * cell = [tableView dequeueReusableCellWithIdentifier:cellID];
|
||||||
|
if (!cell) {
|
||||||
|
cell = [[XJHealthKnowledgeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
|
||||||
|
}
|
||||||
|
cell.model = self.dataArray[indexPath.row];
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— UITableViewDelegate —————
|
||||||
|
|
||||||
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
if (self.cellSelectBlock && indexPath.row < self.dataArray.count) {
|
||||||
|
self.cellSelectBlock(self.dataArray[indexPath.row]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// XJHealthNewsCell.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/6/29.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@class XJHealthKnowledgeModel;
|
||||||
|
|
||||||
|
@interface XJHealthNewsCell : UITableViewCell
|
||||||
|
|
||||||
|
@property (nonatomic, strong) XJHealthKnowledgeModel * model;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
//
|
||||||
|
// XJHealthNewsCell.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/6/29.
|
||||||
|
//
|
||||||
|
// ┌─────────────────────────────────────────────┐
|
||||||
|
// │ │ ← cell 高 90
|
||||||
|
// │ ┌──────────────────────┐ ┌────────────┐ │
|
||||||
|
// │ │ 标题 #111225 15 │ │ 图片 │ │ ← 图片 80×60 垂直居中
|
||||||
|
// │ │ Medium 最多2行 │ │ 80×60 │ │ 右间距 -15
|
||||||
|
// │ │ 左+15 右距图-15 │ │ │ │
|
||||||
|
// │ ├──────────────────────┤ │ │ │
|
||||||
|
// │ │ 收藏1865 │ │ │ │ ← 底部-15,左对齐标题
|
||||||
|
// │ └──────────────────────┘ └────────────┘ │
|
||||||
|
// │ ─────────────────────────────────────── │ ← 分割线
|
||||||
|
// └─────────────────────────────────────────────┘
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJHealthNewsCell.h"
|
||||||
|
#import "XJHealthKnowledgeModel.h"
|
||||||
|
|
||||||
|
@interface XJHealthNewsCell ()
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UIImageView * rightImageView;
|
||||||
|
@property (nonatomic, strong) UILabel * titleLabel;
|
||||||
|
@property (nonatomic, strong) UILabel * favoriteLabel;
|
||||||
|
@property (nonatomic, strong) UIView * separatorLine;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation XJHealthNewsCell
|
||||||
|
|
||||||
|
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||||
|
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
|
||||||
|
self.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||||
|
[self createUI];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)createUI {
|
||||||
|
|
||||||
|
// 右侧图片 80×60,右间距 -15,垂直居中
|
||||||
|
self.rightImageView = [[UIImageView alloc] init];
|
||||||
|
self.rightImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||||
|
self.rightImageView.layer.cornerRadius = 4;
|
||||||
|
self.rightImageView.layer.masksToBounds = YES;
|
||||||
|
[self.contentView addSubview:self.rightImageView];
|
||||||
|
|
||||||
|
[self.rightImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.mas_offset(-15);
|
||||||
|
make.centerY.mas_equalTo(self.contentView);
|
||||||
|
make.width.mas_offset(80);
|
||||||
|
make.height.mas_offset(60);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 标题 #111225 15 Medium,最多2行,左+15,右距图片左 -15
|
||||||
|
self.titleLabel = [[UILabel alloc] init];
|
||||||
|
self.titleLabel.textColor = UIColorHex(#111225);
|
||||||
|
self.titleLabel.font = MEDIUMFONT(15);
|
||||||
|
self.titleLabel.textAlignment = NSTextAlignmentLeft;
|
||||||
|
self.titleLabel.numberOfLines = 2;
|
||||||
|
[self.contentView addSubview:self.titleLabel];
|
||||||
|
|
||||||
|
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(15);
|
||||||
|
make.top.mas_offset(14);
|
||||||
|
make.right.mas_equalTo(self.rightImageView.mas_left).offset(-15);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 收藏数 #77849E 11 Medium,底部-15,左对齐标题
|
||||||
|
self.favoriteLabel = [[UILabel alloc] init];
|
||||||
|
self.favoriteLabel.textColor = UIColorHex(#77849E);
|
||||||
|
self.favoriteLabel.font = MEDIUMFONT(11);
|
||||||
|
self.favoriteLabel.textAlignment = NSTextAlignmentLeft;
|
||||||
|
[self.contentView addSubview:self.favoriteLabel];
|
||||||
|
|
||||||
|
[self.favoriteLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_equalTo(self.titleLabel.mas_left);
|
||||||
|
make.bottom.mas_offset(-15);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 分割线 #EAECF1 h1,左对齐标题,右 -15
|
||||||
|
self.separatorLine = [[UIView alloc] init];
|
||||||
|
self.separatorLine.backgroundColor = UIColorHex(#EAECF1);
|
||||||
|
[self.contentView addSubview:self.separatorLine];
|
||||||
|
|
||||||
|
[self.separatorLine mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_equalTo(self.titleLabel.mas_left);
|
||||||
|
make.right.mas_offset(-15);
|
||||||
|
make.bottom.mas_offset(0);
|
||||||
|
make.height.mas_offset(1);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setModel:(XJHealthKnowledgeModel *)model {
|
||||||
|
_model = model;
|
||||||
|
|
||||||
|
self.titleLabel.text = model.title;
|
||||||
|
|
||||||
|
// 图片
|
||||||
|
if (!ValidStr(model.imageUrl)) {
|
||||||
|
NSString * photo = model.imageUrl;
|
||||||
|
if ([photo hasPrefix:@"http://"]) {
|
||||||
|
photo = [photo stringByReplacingOccurrencesOfString:@"http://" withString:@"https://"];
|
||||||
|
}
|
||||||
|
[self.rightImageView sd_setImageWithURL:[NSURL URLWithString:photo] placeholderImage:[UIImage imageNamed:@"article_placholdIMg"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 收藏数
|
||||||
|
self.favoriteLabel.text = [NSString stringWithFormat:@"收藏%ld", (long)model.favoriteCount];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// XJHealthNewsView.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/6/29.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@class XJHealthKnowledgeModel;
|
||||||
|
|
||||||
|
@interface XJHealthNewsView : UIView
|
||||||
|
|
||||||
|
/// 数据源
|
||||||
|
@property (nonatomic, strong) NSArray<XJHealthKnowledgeModel *> * dataArray;
|
||||||
|
/// 点击"更多"
|
||||||
|
@property (nonatomic, copy) void (^moreBlock)(void);
|
||||||
|
/// 点击 cell
|
||||||
|
@property (nonatomic, copy) void (^cellSelectBlock)(XJHealthKnowledgeModel * model);
|
||||||
|
|
||||||
|
/// 计算当前总高度
|
||||||
|
- (CGFloat)totalHeight;
|
||||||
|
|
||||||
|
/// 显示未登录占位
|
||||||
|
- (void)showNotLoggedInPlaceholder;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
//
|
||||||
|
// XJHealthNewsView.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/6/29.
|
||||||
|
//
|
||||||
|
// ┌─────────────────────────────┐
|
||||||
|
// │ 健康资讯 [>] │ ← header 40
|
||||||
|
// ├─────────────────────────────┤
|
||||||
|
// │ Cell 1 │ ← cell 90 (最多2条)
|
||||||
|
// ├─────────────────────────────┤
|
||||||
|
// │ Cell 2 │
|
||||||
|
// ├─────────────────────────────┤
|
||||||
|
// │ 暂无健康资讯(空状态) │
|
||||||
|
// └─────────────────────────────┘
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJHealthNewsView.h"
|
||||||
|
#import "XJHealthNewsCell.h"
|
||||||
|
#import "XJHealthKnowledgeModel.h"
|
||||||
|
|
||||||
|
static CGFloat const kHeaderHeight = 40;
|
||||||
|
static CGFloat const kCellHeight = 90;
|
||||||
|
static CGFloat const kMaxCellCount = 2;
|
||||||
|
static CGFloat const kDefaultEmptyHeight = 130;
|
||||||
|
|
||||||
|
@interface XJHealthNewsView () <UITableViewDelegate, UITableViewDataSource>
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UIView * headerView;
|
||||||
|
@property (nonatomic, strong) UIImageView * headerBgImg;
|
||||||
|
@property (nonatomic, strong) UILabel * titleLabel;
|
||||||
|
@property (nonatomic, strong) UIButton * moreBtn;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UITableView * listTableView;
|
||||||
|
@property (nonatomic, strong) UILabel * emptyLabel;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation XJHealthNewsView
|
||||||
|
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame {
|
||||||
|
if (self = [super initWithFrame:frame]) {
|
||||||
|
self.backgroundColor = KWhiteColor;
|
||||||
|
self.layer.cornerRadius = 12;
|
||||||
|
self.layer.masksToBounds = YES;
|
||||||
|
[self createUI];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— UI 搭建 —————
|
||||||
|
|
||||||
|
- (void)createUI {
|
||||||
|
|
||||||
|
// 头部
|
||||||
|
self.headerView = [[UIView alloc] init];
|
||||||
|
[self addSubview:self.headerView];
|
||||||
|
[self.headerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.top.mas_offset(0);
|
||||||
|
make.height.mas_offset(kRealValue(kHeaderHeight));
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.headerBgImg = [[UIImageView alloc] init];
|
||||||
|
self.headerBgImg.image = [UIImage imageNamed:@"heaedTitleBackImg"];
|
||||||
|
[self.headerView addSubview:self.headerBgImg];
|
||||||
|
[self.headerBgImg mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.edges.mas_offset(0);
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.titleLabel = [[UILabel alloc] init];
|
||||||
|
self.titleLabel.text = @"健康资讯";
|
||||||
|
self.titleLabel.textColor = CFontColor1;
|
||||||
|
self.titleLabel.font = BOLDSYSTEMFONT(16);
|
||||||
|
[self.headerView addSubview:self.titleLabel];
|
||||||
|
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(13);
|
||||||
|
make.centerY.mas_equalTo(self.headerView);
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.moreBtn = [[UIButton alloc] init];
|
||||||
|
[self.moreBtn setImage:[UIImage imageNamed:@"wacthRightAccow"] forState:UIControlStateNormal];
|
||||||
|
[self.moreBtn addTarget:self action:@selector(moreAction) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
[self.headerView addSubview:self.moreBtn];
|
||||||
|
[self.moreBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.mas_offset(-8);
|
||||||
|
make.centerY.mas_equalTo(self.headerView);
|
||||||
|
make.width.height.mas_offset(30);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 列表(直接跟在 header 下方,无搜索框无标签区)
|
||||||
|
self.listTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
|
||||||
|
self.listTableView.delegate = self;
|
||||||
|
self.listTableView.dataSource = self;
|
||||||
|
self.listTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||||
|
self.listTableView.scrollEnabled = NO;
|
||||||
|
self.listTableView.rowHeight = kCellHeight;
|
||||||
|
self.listTableView.backgroundColor = KWhiteColor;
|
||||||
|
self.listTableView.hidden = YES;
|
||||||
|
if (@available(iOS 15.0, *)) {
|
||||||
|
self.listTableView.sectionHeaderTopPadding = 0;
|
||||||
|
}
|
||||||
|
[self addSubview:self.listTableView];
|
||||||
|
[self.listTableView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.mas_offset(0);
|
||||||
|
make.top.mas_equalTo(self.headerView.mas_bottom);
|
||||||
|
make.height.mas_offset(0);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 空状态
|
||||||
|
self.emptyLabel = [[UILabel alloc] init];
|
||||||
|
self.emptyLabel.text = @"暂无健康资讯";
|
||||||
|
self.emptyLabel.textColor = UIColorHex(#14BEBE);
|
||||||
|
self.emptyLabel.font = [UIFont systemFontOfSize:15];
|
||||||
|
self.emptyLabel.textAlignment = NSTextAlignmentCenter;
|
||||||
|
self.emptyLabel.hidden = YES;
|
||||||
|
[self addSubview:self.emptyLabel];
|
||||||
|
[self.emptyLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.centerX.mas_equalTo(self);
|
||||||
|
make.top.mas_equalTo(self.headerView.mas_bottom).offset(30);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— Setter —————
|
||||||
|
|
||||||
|
- (void)setDataArray:(NSArray<XJHealthKnowledgeModel *> *)dataArray {
|
||||||
|
_dataArray = dataArray;
|
||||||
|
|
||||||
|
BOOL hasData = dataArray.count > 0;
|
||||||
|
|
||||||
|
self.listTableView.hidden = !hasData;
|
||||||
|
self.emptyLabel.hidden = hasData;
|
||||||
|
|
||||||
|
if (hasData) {
|
||||||
|
[self.listTableView reloadData];
|
||||||
|
CGFloat tableH = MIN(dataArray.count, kMaxCellCount) * kCellHeight;
|
||||||
|
[self.listTableView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.mas_offset(0);
|
||||||
|
make.top.mas_equalTo(self.headerView.mas_bottom);
|
||||||
|
make.height.mas_offset(tableH);
|
||||||
|
}];
|
||||||
|
} else {
|
||||||
|
[self.listTableView mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.mas_offset(0);
|
||||||
|
make.top.mas_equalTo(self.headerView.mas_bottom);
|
||||||
|
make.height.mas_offset(0);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)showNotLoggedInPlaceholder {
|
||||||
|
self.dataArray = @[];
|
||||||
|
self.emptyLabel.text = @"暂未登录";
|
||||||
|
self.emptyLabel.textColor = [UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:1.0];
|
||||||
|
self.emptyLabel.hidden = NO;
|
||||||
|
[self.emptyLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.centerX.mas_equalTo(self);
|
||||||
|
make.top.mas_equalTo(self.headerView.mas_bottom);
|
||||||
|
make.bottom.mas_equalTo(self);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— 高度计算 —————
|
||||||
|
|
||||||
|
- (CGFloat)totalHeight {
|
||||||
|
BOOL hasData = self.dataArray.count > 0;
|
||||||
|
|
||||||
|
CGFloat base = kRealValue(kHeaderHeight);
|
||||||
|
if (hasData) {
|
||||||
|
CGFloat tableH = MIN(self.dataArray.count, kMaxCellCount) * kCellHeight;
|
||||||
|
return base + tableH;
|
||||||
|
} else {
|
||||||
|
return base + (self.emptyLabel.hidden ? kDefaultEmptyHeight - kHeaderHeight : 80);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— 事件 —————
|
||||||
|
|
||||||
|
- (void)moreAction {
|
||||||
|
if (self.moreBlock) self.moreBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— UITableViewDataSource —————
|
||||||
|
|
||||||
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||||
|
return MIN(self.dataArray.count, kMaxCellCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
static NSString * cellID = @"XJHealthNewsCell";
|
||||||
|
XJHealthNewsCell * cell = [tableView dequeueReusableCellWithIdentifier:cellID];
|
||||||
|
if (!cell) {
|
||||||
|
cell = [[XJHealthNewsCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
|
||||||
|
}
|
||||||
|
cell.model = self.dataArray[indexPath.row];
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - ————— UITableViewDelegate —————
|
||||||
|
|
||||||
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
if (self.cellSelectBlock && indexPath.row < self.dataArray.count) {
|
||||||
|
self.cellSelectBlock(self.dataArray[indexPath.row]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// XJHomePageV2BottomTools.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
typedef void(^bottomToolsImgClick)(NSInteger imgIndex);
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface XJHomePageV2BottomTools : UIView
|
||||||
|
|
||||||
|
@property (nonatomic, strong)bottomToolsImgClick imgeBlock;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
//
|
||||||
|
// XJHomePageV2BottomTools.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJHomePageV2BottomTools.h"
|
||||||
|
|
||||||
|
@implementation XJHomePageV2BottomTools
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Only override drawRect: if you perform custom drawing.
|
||||||
|
// An empty implementation adversely affects performance during animation.
|
||||||
|
- (void)drawRect:(CGRect)rect {
|
||||||
|
// Drawing code
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame {
|
||||||
|
|
||||||
|
if (self = [super initWithFrame:frame]) {
|
||||||
|
[self createUI];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)createUI {
|
||||||
|
|
||||||
|
UIImageView * leftImage = [[UIImageView alloc] init];
|
||||||
|
leftImage.image = [UIImage imageNamed:@"bottomLeftImg"];
|
||||||
|
leftImage.userInteractionEnabled = true;
|
||||||
|
[self addSubview:leftImage];
|
||||||
|
|
||||||
|
[leftImage mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(0);
|
||||||
|
make.top.bottom.mas_offset(0);
|
||||||
|
make.width.mas_equalTo(self.mas_width).multipliedBy(0.5).offset(10);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UILabel * leftTitle = [[UILabel alloc] init];
|
||||||
|
leftTitle.text = @"智慧体重";
|
||||||
|
leftTitle.textColor = UIColorHex(#252535);
|
||||||
|
leftTitle.font = MEDIUMFONT(15);
|
||||||
|
[leftImage addSubview:leftTitle];
|
||||||
|
|
||||||
|
[leftTitle mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(27);
|
||||||
|
make.top.mas_offset(25);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UILabel * leftDetailTitle = [[UILabel alloc] init];
|
||||||
|
leftDetailTitle.text = @"智追体重 科学控重";
|
||||||
|
leftDetailTitle.textColor = UIColorHex(#808080);
|
||||||
|
leftDetailTitle.font = [UIFont systemFontOfSize:12 weight:UIFontWeightRegular];
|
||||||
|
[leftImage addSubview:leftDetailTitle];
|
||||||
|
|
||||||
|
[leftDetailTitle mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(27);
|
||||||
|
make.top.mas_equalTo(leftTitle.mas_bottom).offset(8);
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
UIImageView * rightImage = [[UIImageView alloc] init];
|
||||||
|
rightImage.image = [UIImage imageNamed:@"bottomRightImg"];
|
||||||
|
rightImage.userInteractionEnabled = true;
|
||||||
|
[self addSubview:rightImage];
|
||||||
|
|
||||||
|
[rightImage mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.mas_offset(0);
|
||||||
|
make.top.bottom.mas_offset(0);
|
||||||
|
make.width.mas_equalTo(self.mas_width).multipliedBy(0.5).offset(10);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UILabel * rightTitle = [[UILabel alloc] init];
|
||||||
|
rightTitle.text = @"一人一案";
|
||||||
|
rightTitle.textColor = UIColorHex(#252535);
|
||||||
|
rightTitle.font = MEDIUMFONT(15);
|
||||||
|
[rightImage addSubview:rightTitle];
|
||||||
|
|
||||||
|
[rightTitle mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(27);
|
||||||
|
make.top.mas_offset(25);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UILabel * rightDetailTitle = [[UILabel alloc] init];
|
||||||
|
rightDetailTitle.text = @"定制专属健康方案";
|
||||||
|
rightDetailTitle.textColor = UIColorHex(#808080);
|
||||||
|
rightDetailTitle.font = [UIFont systemFontOfSize:12 weight:UIFontWeightRegular];
|
||||||
|
[rightImage addSubview:rightDetailTitle];
|
||||||
|
|
||||||
|
[rightDetailTitle mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(27);
|
||||||
|
make.top.mas_equalTo(rightTitle.mas_bottom).offset(8);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UITapGestureRecognizer *tap1 =
|
||||||
|
[[UITapGestureRecognizer alloc] initWithTarget:self
|
||||||
|
action:@selector(leftImageTap:)];
|
||||||
|
|
||||||
|
[leftImage addGestureRecognizer:tap1];
|
||||||
|
|
||||||
|
UITapGestureRecognizer *tap2 =
|
||||||
|
[[UITapGestureRecognizer alloc] initWithTarget:self
|
||||||
|
action:@selector(rightImageTap:)];
|
||||||
|
|
||||||
|
[rightImage addGestureRecognizer:tap2];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)leftImageTap:(UITapGestureRecognizer *)tap {
|
||||||
|
if (self.imgeBlock) {
|
||||||
|
self.imgeBlock(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)rightImageTap:(UITapGestureRecognizer *)tap {
|
||||||
|
|
||||||
|
if (self.imgeBlock) {
|
||||||
|
self.imgeBlock(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
//
|
||||||
|
// XJHomePageV2HeardView.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
#import "XJHomeWatchModel.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@protocol homePageHeardDelegate <NSObject>
|
||||||
|
|
||||||
|
- (void)SDTitleItemClick;
|
||||||
|
|
||||||
|
- (void)heardTopToolsClick:(NSInteger)type;
|
||||||
|
|
||||||
|
- (void)heardImageClick:(NSInteger)imageIndex;
|
||||||
|
|
||||||
|
- (void)watchDetailClick;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface XJHomePageV2HeardView : UIView
|
||||||
|
|
||||||
|
@property (nonatomic, strong) NSArray * dataArray;
|
||||||
|
|
||||||
|
@property (nonatomic, weak) id<homePageHeardDelegate> homeTopDelegate;
|
||||||
|
|
||||||
|
|
||||||
|
@property (nonatomic, strong) NSArray * bannerArray;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) XJHomeWatchModel * model;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) NSArray * watchArray;
|
||||||
|
|
||||||
|
@property (nonatomic, copy, nullable) void (^bindDeviceBlock)(NSString * watchNo);
|
||||||
|
|
||||||
|
@property (nonatomic, strong) NSString * totalponits;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,520 @@
|
|||||||
|
//
|
||||||
|
// XJHomePageV2HeardView.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJHomePageV2HeardView.h"
|
||||||
|
#import "SDCycleScrollView.h"
|
||||||
|
#import "HealthyToolsView.h"
|
||||||
|
#import "MyMessageModel.h"
|
||||||
|
#import "HomeBannerModel.h"
|
||||||
|
#import "XJHomeWatchDataView.h"
|
||||||
|
|
||||||
|
|
||||||
|
@interface XJHomePageV2HeardView ()<SDCycleScrollViewDelegate>
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UIView *messageview;
|
||||||
|
@property (nonatomic, strong) SDCycleScrollView *adTitleView;
|
||||||
|
@property (nonatomic, strong) UILabel *nameLabel;
|
||||||
|
@property (nonatomic, strong) XJHomeWatchDataView *watchDataView;
|
||||||
|
@property (nonatomic, strong) UILabel * toolTitleLab;
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation XJHomePageV2HeardView
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Only override drawRect: if you perform custom drawing.
|
||||||
|
// An empty implementation adversely affects performance during animation.
|
||||||
|
- (void)drawRect:(CGRect)rect {
|
||||||
|
// Drawing code
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame {
|
||||||
|
|
||||||
|
if (self = [super initWithFrame:frame]) {
|
||||||
|
self.backgroundColor = CViewBgColor;
|
||||||
|
[self createUI];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)createUI {
|
||||||
|
|
||||||
|
UIImageView * backImage = [[UIImageView alloc] init];
|
||||||
|
backImage.userInteractionEnabled = true;
|
||||||
|
backImage.image = [UIImage imageNamed:@"homePageHeardTop"];
|
||||||
|
[self addSubview:backImage];
|
||||||
|
|
||||||
|
[backImage mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.mas_offset(0);
|
||||||
|
make.height.mas_offset(kRealValue(405));
|
||||||
|
make.top.mas_offset(0);
|
||||||
|
|
||||||
|
}];
|
||||||
|
|
||||||
|
UIView * messageView = [[UIView alloc] init];
|
||||||
|
messageView.layer.cornerRadius = 8;
|
||||||
|
messageView.layer.masksToBounds = true;
|
||||||
|
messageView.userInteractionEnabled = true;
|
||||||
|
self.messageview = messageView;
|
||||||
|
[backImage addSubview:messageView];
|
||||||
|
|
||||||
|
[messageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(12);
|
||||||
|
make.right.mas_offset(-12);
|
||||||
|
make.height.mas_offset(40);
|
||||||
|
make.top.mas_offset(kRealValue(145));
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
UIImageView * messageImg = [[UIImageView alloc] init];
|
||||||
|
messageImg.image = [UIImage imageNamed:@"messageBackImg"];
|
||||||
|
messageImg.userInteractionEnabled = true;
|
||||||
|
[messageView addSubview:messageImg];
|
||||||
|
|
||||||
|
[messageImg mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.edges.offset(0);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UIImageView * labaImg = [[UIImageView alloc] init];
|
||||||
|
labaImg.image = [UIImage imageNamed:@"homeLaba"];
|
||||||
|
[messageView addSubview:labaImg];
|
||||||
|
[labaImg mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(10);
|
||||||
|
make.width.height.mas_offset(17);
|
||||||
|
make.centerY.mas_equalTo(messageView);
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
self.adTitleView = [SDCycleScrollView cycleScrollViewWithFrame:CGRectZero delegate:self placeholderImage:nil];
|
||||||
|
self.adTitleView.titleLabelTextColor = UIColorHex(#77849E);
|
||||||
|
self.adTitleView.titleLabelBackgroundColor = KClearColor;
|
||||||
|
self.adTitleView.scrollDirection = UICollectionViewScrollDirectionVertical;
|
||||||
|
self.adTitleView.onlyDisplayText = YES;
|
||||||
|
NSArray *titles = @[];
|
||||||
|
|
||||||
|
self.adTitleView.titlesGroup = [titles copy];
|
||||||
|
[self.adTitleView disableScrollGesture];
|
||||||
|
[messageView addSubview:self.adTitleView];
|
||||||
|
[self.adTitleView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.equalTo(labaImg.mas_right).offset(9);
|
||||||
|
make.right.equalTo(messageView).offset(-12);
|
||||||
|
make.top.bottom.equalTo(messageView);
|
||||||
|
}];
|
||||||
|
DLog(@"%@", self.adTitleView);
|
||||||
|
|
||||||
|
if ([HQCommonUtils isLogin]) {
|
||||||
|
messageView.hidden = false;
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
messageView.hidden = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
self.nameLabel = [[UILabel alloc] init];
|
||||||
|
self.nameLabel.textColor = KWhiteColor;
|
||||||
|
self.nameLabel.font = BOLDSYSTEMFONT(12);
|
||||||
|
self.nameLabel.text = @"Hi~";
|
||||||
|
self.nameLabel.textAlignment = NSTextAlignmentLeft;
|
||||||
|
[backImage addSubview:self.nameLabel];
|
||||||
|
[self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(24);
|
||||||
|
make.right.mas_offset(-12);
|
||||||
|
if (messageView.hidden == false) {
|
||||||
|
make.top.mas_equalTo(messageView.mas_bottom).offset(10);
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
make.top.mas_offset(kRealValue(145));
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
//姓名
|
||||||
|
if ([HQCommonUtils isLogin]) {
|
||||||
|
HQUserInfo * user = [HQCommonUtils keyedUnarchiverWithKey:LoginUserInfo];
|
||||||
|
self.nameLabel.text = [NSString stringWithFormat:@"Hi~%@",user.realname];
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
UIView * toolsView = [[UIView alloc] init];
|
||||||
|
toolsView.layer.cornerRadius = 12;
|
||||||
|
toolsView.layer.masksToBounds = true;
|
||||||
|
toolsView.alpha = 0.5;
|
||||||
|
toolsView.backgroundColor = UIColorHex(#EBFFFD);
|
||||||
|
[backImage addSubview:toolsView];
|
||||||
|
|
||||||
|
[toolsView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(6);
|
||||||
|
make.right.mas_offset(-6);
|
||||||
|
make.top.mas_equalTo(self.nameLabel.mas_bottom).offset(8);
|
||||||
|
make.height.mas_offset(126);
|
||||||
|
|
||||||
|
}];
|
||||||
|
|
||||||
|
UILabel * toolTitleLab = [[UILabel alloc] init];
|
||||||
|
toolTitleLab.text = @"今日健康积分 0 | 累计积分 0";
|
||||||
|
toolTitleLab.textColor = UIColorHex(#116F6B);
|
||||||
|
toolTitleLab.font = [UIFont systemFontOfSize:12 weight:UIFontWeightRegular];
|
||||||
|
self.toolTitleLab = toolTitleLab;
|
||||||
|
[toolsView addSubview:toolTitleLab];
|
||||||
|
|
||||||
|
[toolTitleLab mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(18);
|
||||||
|
make.top.mas_offset(8);
|
||||||
|
make.right.mas_offset(0);
|
||||||
|
}];
|
||||||
|
|
||||||
|
NSArray * toolsArray = @[@[@"健康档案",@"homeTools_1"],@[@"健康体检",@"homeTools_2"],@[@"应急就医",@"homeTools_3"],@[@"健康银行",@"homeTools_4"]];
|
||||||
|
|
||||||
|
UIView * customView = [[UIView alloc] init];
|
||||||
|
customView.layer.cornerRadius = 6;
|
||||||
|
customView.layer.masksToBounds = true;
|
||||||
|
customView.backgroundColor = KWhiteColor;
|
||||||
|
[backImage addSubview:customView];
|
||||||
|
|
||||||
|
[customView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(12);
|
||||||
|
make.right.mas_offset(-12);
|
||||||
|
make.top.mas_equalTo(self.nameLabel.mas_bottom).offset(35);
|
||||||
|
make.height.mas_offset(93);
|
||||||
|
}];
|
||||||
|
|
||||||
|
NSInteger count = toolsArray.count;
|
||||||
|
NSMutableArray *itemViews = [NSMutableArray array];
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
|
||||||
|
NSArray *item = toolsArray[i];
|
||||||
|
|
||||||
|
UIView *itemView = [[UIView alloc] init];
|
||||||
|
itemView.tag = i;
|
||||||
|
itemView.userInteractionEnabled = YES;
|
||||||
|
[customView addSubview:itemView];
|
||||||
|
[itemViews addObject:itemView];
|
||||||
|
|
||||||
|
/// 点击手势
|
||||||
|
UITapGestureRecognizer *tap =
|
||||||
|
[[UITapGestureRecognizer alloc] initWithTarget:self
|
||||||
|
action:@selector(cenetrFunctionItemTap:)];
|
||||||
|
|
||||||
|
[itemView addGestureRecognizer:tap];
|
||||||
|
|
||||||
|
/// 上图
|
||||||
|
UIImageView *icon = [[UIImageView alloc] init];
|
||||||
|
icon.image = [UIImage imageNamed:item[1]];
|
||||||
|
icon.contentMode = UIViewContentModeScaleAspectFit;
|
||||||
|
[itemView addSubview:icon];
|
||||||
|
|
||||||
|
/// 下文
|
||||||
|
UILabel *title = [[UILabel alloc] init];
|
||||||
|
title.text = item[0];
|
||||||
|
title.font = MEDIUMFONT(14);
|
||||||
|
title.textColor = [UIColor blackColor];
|
||||||
|
title.textAlignment = NSTextAlignmentCenter;
|
||||||
|
[itemView addSubview:title];
|
||||||
|
|
||||||
|
/// icon 布局
|
||||||
|
[icon mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.mas_equalTo(10);
|
||||||
|
make.centerX.equalTo(itemView);
|
||||||
|
make.width.height.mas_equalTo(40);
|
||||||
|
}];
|
||||||
|
|
||||||
|
/// label 布局
|
||||||
|
[title mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.equalTo(icon.mas_bottom).offset(6);
|
||||||
|
make.left.right.equalTo(itemView);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
[itemViews mas_distributeViewsAlongAxis:MASAxisTypeHorizontal
|
||||||
|
withFixedSpacing:0
|
||||||
|
leadSpacing:0
|
||||||
|
tailSpacing:0];
|
||||||
|
|
||||||
|
[itemViews mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.bottom.equalTo(customView);
|
||||||
|
}];
|
||||||
|
// 先用图片实现
|
||||||
|
|
||||||
|
NSArray *imageConfigs = @[
|
||||||
|
@{@"img": @"heardTopImg_1", @"height": @65},
|
||||||
|
@{@"img": @"heardTopImg_2", @"height": @60},
|
||||||
|
];
|
||||||
|
SDCycleScrollView *lastImageView = nil;
|
||||||
|
|
||||||
|
for (int i = 0; i < imageConfigs.count; i++) {
|
||||||
|
|
||||||
|
NSDictionary *config = imageConfigs[i];
|
||||||
|
|
||||||
|
SDCycleScrollView * SDCycles = [SDCycleScrollView cycleScrollViewWithFrame:CGRectZero delegate:self placeholderImage: [UIImage imageNamed:@"placeholder"]];
|
||||||
|
SDCycles.layer.cornerRadius = 12;
|
||||||
|
SDCycles.layer.masksToBounds = true;
|
||||||
|
SDCycles.backgroundColor = KWhiteColor;
|
||||||
|
// UIViewContentModeScaleToFill,
|
||||||
|
// UIViewContentModeScaleAspectFit, // contents scaled to fit with fixed aspect. remainder is transparent
|
||||||
|
// UIViewContentModeScaleAspectFill,
|
||||||
|
SDCycles.bannerImageViewContentMode = UIViewContentModeScaleToFill;
|
||||||
|
SDCycles.currentPageDotImage = [UIImage imageNamed:@"pageControlDot"];
|
||||||
|
SDCycles.pageDotImage = [UIImage imageNamed:@"pageControlNomalDot"]; SDCycles.pageDotColor = KWhiteColor;
|
||||||
|
SDCycles.tag = 50 + i; //
|
||||||
|
SDCycles.pageControlAliment = SDCycleScrollViewPageContolAlimentCenter;
|
||||||
|
SDCycles.pageControlDotSize = CGSizeMake(6, 4);
|
||||||
|
[self addSubview:SDCycles];
|
||||||
|
|
||||||
|
// UIImageView *imageView = [[UIImageView alloc] init];
|
||||||
|
// imageView.image = [UIImage imageNamed:config[@"img"]];
|
||||||
|
// imageView.userInteractionEnabled = YES;
|
||||||
|
// imageView.tag = 50 + i; // 用于区分点击的是哪一个
|
||||||
|
// imageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||||
|
// imageView.layer.cornerRadius = 8;
|
||||||
|
// imageView.layer.masksToBounds = true;
|
||||||
|
// imageView.clipsToBounds = YES;
|
||||||
|
//
|
||||||
|
// [self addSubview:imageView];
|
||||||
|
|
||||||
|
/// 点击手势
|
||||||
|
// UITapGestureRecognizer *tap =
|
||||||
|
// [[UITapGestureRecognizer alloc] initWithTarget:self
|
||||||
|
// action:@selector(topImageTap:)];
|
||||||
|
//
|
||||||
|
// [SDCycles addGestureRecognizer:tap];
|
||||||
|
|
||||||
|
/// 布局
|
||||||
|
[SDCycles mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
|
||||||
|
if (lastImageView) {
|
||||||
|
make.top.equalTo(lastImageView.mas_bottom).offset(12);
|
||||||
|
} else {
|
||||||
|
make.top.equalTo(toolsView.mas_bottom).offset(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
make.left.mas_equalTo(12);
|
||||||
|
make.right.mas_equalTo(-12);
|
||||||
|
make.height.mas_equalTo([config[@"height"] floatValue]);
|
||||||
|
|
||||||
|
}];
|
||||||
|
lastImageView = SDCycles;
|
||||||
|
}
|
||||||
|
[self layoutIfNeeded];
|
||||||
|
|
||||||
|
// @{@"img": @"heardTopImg_3", @"height": @120}
|
||||||
|
|
||||||
|
//手表数据
|
||||||
|
self.watchDataView = [[XJHomeWatchDataView alloc] initWithFrame:CGRectZero];
|
||||||
|
// self.watchDataView.tabTitles = @[@"心脑血管", @"癌症", @"慢呼", @"糖尿病", @"亚健康"];
|
||||||
|
self.watchDataView.tabSelectBlock = ^(NSInteger index, NSString *title) {
|
||||||
|
DLog(@"选中 %ld - %@", index, title);
|
||||||
|
// 切换 collectionView 到对应 page
|
||||||
|
|
||||||
|
};
|
||||||
|
MJWeakSelf
|
||||||
|
// self.watchDataView.tabSelectBlock = ^(NSInteger index, NSString *title) {
|
||||||
|
// // tab 0 完整高度,其他收缩(header 40 + tab 52 + 内容区 68 = 160)
|
||||||
|
// CGFloat height = (index == 0) ? 250 : 250;
|
||||||
|
// [weakSelf.watchDataView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||||
|
// make.height.mas_equalTo(height);
|
||||||
|
// }];
|
||||||
|
// [UIView animateWithDuration:0.25 animations:^{
|
||||||
|
// [weakSelf layoutIfNeeded];
|
||||||
|
// }];
|
||||||
|
// };
|
||||||
|
self.watchDataView.watchMoreBlock = ^{
|
||||||
|
if ([self.homeTopDelegate respondsToSelector:@selector(watchDetailClick)]) {
|
||||||
|
[self.homeTopDelegate watchDetailClick];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//绑定手表
|
||||||
|
self.watchDataView.bindDeviceBlock = ^(NSString * _Nonnull number) {
|
||||||
|
|
||||||
|
weakSelf.bindDeviceBlock(number);
|
||||||
|
};
|
||||||
|
[self addSubview:self.watchDataView];
|
||||||
|
|
||||||
|
[self.watchDataView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(12);
|
||||||
|
make.right.mas_offset(-12);
|
||||||
|
make.height.mas_offset(104);
|
||||||
|
make.top.mas_equalTo(lastImageView.mas_bottom).offset(12);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 高度变化回调:无数据/未登录 104,有数据 205
|
||||||
|
self.watchDataView.heightChangeBlock = ^(CGFloat height) {
|
||||||
|
[weakSelf.watchDataView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.height.mas_equalTo(height);
|
||||||
|
}];
|
||||||
|
[UIView animateWithDuration:0.25 animations:^{
|
||||||
|
[weakSelf layoutIfNeeded];
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
SDCycleScrollView * questionSDCycles = [SDCycleScrollView cycleScrollViewWithFrame:CGRectZero delegate:self placeholderImage:[UIImage imageNamed:@"placeholder"]];
|
||||||
|
questionSDCycles.backgroundColor = KWhiteColor;
|
||||||
|
questionSDCycles.layer.cornerRadius = 12;
|
||||||
|
questionSDCycles.layer.masksToBounds = true;
|
||||||
|
questionSDCycles.bannerImageViewContentMode = UIViewContentModeScaleToFill;
|
||||||
|
questionSDCycles.currentPageDotImage = [UIImage imageNamed:@"pageControlDot"];
|
||||||
|
questionSDCycles.pageDotImage = [UIImage imageNamed:@"pageControlNomalDot"]; questionSDCycles.pageDotColor = KWhiteColor;
|
||||||
|
questionSDCycles.tag = 52; //
|
||||||
|
questionSDCycles.pageControlAliment = SDCycleScrollViewPageContolAlimentCenter;
|
||||||
|
questionSDCycles.pageControlDotSize = CGSizeMake(6, 4);
|
||||||
|
[self addSubview:questionSDCycles];
|
||||||
|
/// 布局
|
||||||
|
[questionSDCycles mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.equalTo(self.watchDataView.mas_bottom).offset(12);
|
||||||
|
make.left.mas_equalTo(12);
|
||||||
|
make.right.mas_equalTo(-12);
|
||||||
|
make.height.mas_equalTo(@120);
|
||||||
|
make.bottom.mas_offset(-12);
|
||||||
|
|
||||||
|
}];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)setTotalponits:(NSString *)totalponits {
|
||||||
|
|
||||||
|
_totalponits = totalponits;
|
||||||
|
|
||||||
|
self.toolTitleLab.text = _totalponits;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setModel:(XJHomeWatchModel *)model {
|
||||||
|
|
||||||
|
_model = model;
|
||||||
|
|
||||||
|
self.watchDataView.watchModel = _model;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setWatchArray:(NSArray *)watchArray {
|
||||||
|
|
||||||
|
_watchArray = watchArray;
|
||||||
|
|
||||||
|
self.watchDataView.dataList = _watchArray;
|
||||||
|
|
||||||
|
}
|
||||||
|
- (void)setDataArray:(NSArray *)dataArray {
|
||||||
|
|
||||||
|
_dataArray = dataArray;
|
||||||
|
|
||||||
|
|
||||||
|
NSMutableArray * titlesArray = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
|
for (MyMessageModel * model in _dataArray) {
|
||||||
|
|
||||||
|
//直接处理图片吧
|
||||||
|
[titlesArray addObject:model.title];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(titlesArray.count == 0) {
|
||||||
|
|
||||||
|
|
||||||
|
self.messageview.hidden = true;
|
||||||
|
|
||||||
|
[self.nameLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(24);
|
||||||
|
make.right.mas_offset(-12);
|
||||||
|
make.top.mas_offset(kRealValue(145));
|
||||||
|
}];
|
||||||
|
[self layoutIfNeeded];
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
self.messageview.hidden = false;
|
||||||
|
|
||||||
|
[self.nameLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(24);
|
||||||
|
make.right.mas_offset(-12);
|
||||||
|
make.top.mas_equalTo(self.messageview.mas_bottom).offset(10);
|
||||||
|
}];
|
||||||
|
[self layoutIfNeeded];
|
||||||
|
}
|
||||||
|
self.adTitleView.titlesGroup = titlesArray;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setBannerArray:(NSArray *)bannerArray {
|
||||||
|
|
||||||
|
// 1 首页体检模块。2 首页心理模块 3 健康咨询模块。4 ai随访
|
||||||
|
//处理数据
|
||||||
|
|
||||||
|
_bannerArray = bannerArray;
|
||||||
|
|
||||||
|
SDCycleScrollView * oneSDView = [self viewWithTag:50]; //体检
|
||||||
|
SDCycleScrollView * twoSDView = [self viewWithTag:51]; //EAP
|
||||||
|
SDCycleScrollView * threeSDView = [self viewWithTag:52]; //健康咨询
|
||||||
|
|
||||||
|
NSMutableArray * tijianArray = [[NSMutableArray alloc] init];
|
||||||
|
NSMutableArray * eapArray = [[NSMutableArray alloc] init];
|
||||||
|
NSMutableArray * questionArray = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
|
for (HomeBannerModel * model in _bannerArray) {
|
||||||
|
|
||||||
|
//直接处理图片吧
|
||||||
|
NSString * photo = [NSString stringWithFormat:@"%@%@",ResourceAddress,model.photoUrl];
|
||||||
|
|
||||||
|
NSString * str1 = @"\\";
|
||||||
|
|
||||||
|
photo = [ photo stringByReplacingOccurrencesOfString:str1 withString:@"/"];
|
||||||
|
|
||||||
|
NSString *encodedString3 = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef) photo, (CFStringRef)@"!$&'()*+,-./:;=?@_~%#[]", NULL, kCFStringEncodingUTF8));
|
||||||
|
|
||||||
|
if ([model.showLocation intValue] == 1) {
|
||||||
|
[tijianArray addObject:encodedString3];
|
||||||
|
}
|
||||||
|
if ([model.showLocation intValue] == 2) {
|
||||||
|
[eapArray addObject:encodedString3];
|
||||||
|
}
|
||||||
|
if ([model.showLocation intValue] == 3) {
|
||||||
|
[questionArray addObject:encodedString3];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
oneSDView.imageURLStringsGroup = tijianArray;
|
||||||
|
twoSDView.imageURLStringsGroup = eapArray;
|
||||||
|
threeSDView.imageURLStringsGroup = questionArray;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)cycleScrollView:(SDCycleScrollView *)cycleScrollView didSelectItemAtIndex:(NSInteger)index {
|
||||||
|
|
||||||
|
DLog(@"++%ld",index);
|
||||||
|
if (cycleScrollView == self.adTitleView) {
|
||||||
|
if ([self.homeTopDelegate respondsToSelector:@selector(SDTitleItemClick)]) {
|
||||||
|
[self.homeTopDelegate SDTitleItemClick];
|
||||||
|
}
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
CGFloat currentBanner = cycleScrollView.tag;
|
||||||
|
|
||||||
|
if([self.homeTopDelegate respondsToSelector:@selector(heardImageClick:)]) {
|
||||||
|
|
||||||
|
[self.homeTopDelegate heardImageClick:currentBanner];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)cenetrFunctionItemTap:(UITapGestureRecognizer *)tap {
|
||||||
|
UIView *view = tap.view;
|
||||||
|
NSInteger index = view.tag;
|
||||||
|
|
||||||
|
if([self.homeTopDelegate respondsToSelector:@selector(heardTopToolsClick:)]) {
|
||||||
|
[self.homeTopDelegate heardTopToolsClick:index];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// XJHomePageV2QuestionTableView.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import "HealthyQuestionHeardView.h"
|
||||||
|
#import "HomeQusetionRecordsModel.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
|
||||||
|
typedef void(^doctorBlock)(HomeQusetionRecordsModel * model);
|
||||||
|
typedef void(^lookMoreDoctorBlock)();
|
||||||
|
|
||||||
|
@interface XJHomePageV2QuestionTableView : UITableView
|
||||||
|
|
||||||
|
@property (nonatomic, strong) NSArray * dataArray;
|
||||||
|
|
||||||
|
@property (nonatomic, copy) doctorBlock tableBlock;
|
||||||
|
@property (nonatomic, copy) lookMoreDoctorBlock lookMoreBlock;
|
||||||
|
|
||||||
|
@property (nonatomic, weak)id <questionToolsProtocl> headDelegate;
|
||||||
|
|
||||||
|
@property (nonatomic, copy) NSString * haveSessioning;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
//
|
||||||
|
// XJHomePageV2QuestionTableView.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJHomePageV2QuestionTableView.h"
|
||||||
|
#import "HealthyQuestionTable.h"
|
||||||
|
#import "HealthyDoctorTableViewCell.h"
|
||||||
|
#import "QustionHomeRecordsCell.h"
|
||||||
|
|
||||||
|
@interface XJHomePageV2QuestionTableView ()<UITableViewDelegate,UITableViewDataSource>
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation XJHomePageV2QuestionTableView
|
||||||
|
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style
|
||||||
|
{
|
||||||
|
if (self = [super initWithFrame:frame style:style])
|
||||||
|
{
|
||||||
|
[self createUI];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)createUI
|
||||||
|
{
|
||||||
|
if (@available(iOS 11.0, *)) {
|
||||||
|
self.estimatedRowHeight = 0;
|
||||||
|
self.estimatedSectionFooterHeight = 0;
|
||||||
|
self.estimatedSectionHeaderHeight = 0;
|
||||||
|
self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||||
|
}
|
||||||
|
self.delegate = self;
|
||||||
|
self.dataSource = self;
|
||||||
|
self.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||||
|
self.showsVerticalScrollIndicator = NO;
|
||||||
|
self.estimatedRowHeight = 60;
|
||||||
|
self.rowHeight = UITableViewAutomaticDimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setDataArray:(NSArray *)dataArray
|
||||||
|
{
|
||||||
|
_dataArray = dataArray;
|
||||||
|
[self reloadData];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - DataSource
|
||||||
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||||
|
{
|
||||||
|
|
||||||
|
return self.dataArray.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static NSString * cellID = @"cellID";
|
||||||
|
|
||||||
|
|
||||||
|
QustionHomeRecordsCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
|
||||||
|
|
||||||
|
if (!cell) {
|
||||||
|
|
||||||
|
cell = [[QustionHomeRecordsCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
|
||||||
|
}
|
||||||
|
cell.model = self.dataArray[indexPath.row];
|
||||||
|
cell.backgroundColor = CViewBgColor;
|
||||||
|
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||||
|
return cell;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||||
|
{
|
||||||
|
HomeQusetionRecordsModel * model = self.dataArray[indexPath.row];
|
||||||
|
|
||||||
|
if (self.tableBlock) {
|
||||||
|
|
||||||
|
self.tableBlock(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat )tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
|
||||||
|
{
|
||||||
|
return kRealValue(40);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat )tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
|
||||||
|
{
|
||||||
|
return CGFLOAT_MIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
|
||||||
|
|
||||||
|
UIView * sectionHeardView = [[UIView alloc] initWithFrame:CGRectMake(12, 0, kScreenWidth -24, kRealValue(40))];
|
||||||
|
sectionHeardView.backgroundColor = CViewBgColor;
|
||||||
|
|
||||||
|
UIImageView * heaedImg = [[UIImageView alloc] init];
|
||||||
|
heaedImg.image = [UIImage imageNamed:@"heaedTitleBackImg"];
|
||||||
|
[sectionHeardView addSubview:heaedImg];
|
||||||
|
|
||||||
|
[heaedImg mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.edges.mas_offset(0);
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
UILabel * todayLabel = [[UILabel alloc] initWithFrame:CGRectMake(kRealValue(15), kRealValue(16), 190, 16)];
|
||||||
|
|
||||||
|
todayLabel.text = @"专家咨询记录";
|
||||||
|
|
||||||
|
todayLabel.textAlignment = NSTextAlignmentLeft;
|
||||||
|
|
||||||
|
todayLabel.textColor = CFontColor1;
|
||||||
|
|
||||||
|
todayLabel.font = BOLDSYSTEMFONT(16);
|
||||||
|
|
||||||
|
[sectionHeardView addSubview:todayLabel];
|
||||||
|
|
||||||
|
[todayLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(13);
|
||||||
|
make.top.bottom.mas_offset(0);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UIButton * moreBtn = [[UIButton alloc] init];
|
||||||
|
[moreBtn setImage:[UIImage imageNamed:@"wacthRightAccow"] forState:UIControlStateNormal];
|
||||||
|
[moreBtn addTarget:self action:@selector(moreClick) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
[sectionHeardView addSubview:moreBtn];
|
||||||
|
[moreBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.mas_offset(-8);
|
||||||
|
make.centerY.mas_equalTo(sectionHeardView);
|
||||||
|
make.width.height.mas_offset(30);
|
||||||
|
}];
|
||||||
|
return sectionHeardView;
|
||||||
|
|
||||||
|
}
|
||||||
|
- (void)moreClick {
|
||||||
|
|
||||||
|
if (self.lookMoreBlock) {
|
||||||
|
self.lookMoreBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
|
||||||
|
|
||||||
|
return [[UIView alloc] init];
|
||||||
|
}
|
||||||
|
@end
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// XJHomeWatchCollectionViewCell.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/3/2.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface XJHomeWatchCollectionViewCell : UICollectionViewCell
|
||||||
|
|
||||||
|
/// 设置数据模型(id 兼容 HomePageV2WATACHModel)
|
||||||
|
- (void)configureWithData:(nullable id)data;
|
||||||
|
|
||||||
|
/// 父 View Tab 切换时调用,更新展示类型
|
||||||
|
/// 0=心率 1=血氧 2=压力 3=体温 4=睡眠
|
||||||
|
- (void)updateTabIndex:(NSInteger)tabIndex;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,441 @@
|
|||||||
|
//
|
||||||
|
// XJHomeWatchCollectionViewCell.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/3/2.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJHomeWatchCollectionViewCell.h"
|
||||||
|
#import "XJHomeWatchModel.h"
|
||||||
|
#import <Masonry/Masonry.h>
|
||||||
|
|
||||||
|
// tabIndex 对应关系(由父 View XJHomeWatchDataView 的 Tab 传入)
|
||||||
|
// 0=心率 1=血氧 2=压力 3=体温 4=睡眠
|
||||||
|
|
||||||
|
@interface XJHomeWatchCollectionViewCell ()
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UIImageView *heartImg; // 类型图标
|
||||||
|
@property (nonatomic, strong) UILabel *updateLabel; // "最新心率"
|
||||||
|
@property (nonatomic, strong) UILabel *updateTimeLabel; // 最后更新时间(图标旁)
|
||||||
|
@property (nonatomic, strong) UILabel *dataLabel; // 右侧大数值
|
||||||
|
@property (nonatomic, strong) UILabel *backLeftLabel; // 左卡标题 "心率范围"
|
||||||
|
@property (nonatomic, strong) UILabel *leftDataLabel; // 左卡数据
|
||||||
|
@property (nonatomic, strong) UILabel *backRightLabel; // 右卡标题 "平均心率"
|
||||||
|
@property (nonatomic, strong) UILabel *rightDataLabel; // 右卡数据
|
||||||
|
//@property (nonatomic, strong) UILabel *timeLabel; // 底部更新时间
|
||||||
|
@property (nonatomic, strong) UIView *emptyView;
|
||||||
|
@property (nonatomic, strong) XJHomeWatchModel *model;
|
||||||
|
@property (nonatomic, assign) NSInteger currentTabIndex;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation XJHomeWatchCollectionViewCell
|
||||||
|
|
||||||
|
#pragma mark - Init
|
||||||
|
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame {
|
||||||
|
if (self = [super initWithFrame:frame]) {
|
||||||
|
self.layer.cornerRadius = 8.0f;
|
||||||
|
self.layer.masksToBounds = YES;
|
||||||
|
self.backgroundColor = KWhiteColor;
|
||||||
|
[self createUI];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UI
|
||||||
|
|
||||||
|
- (void)createUI {
|
||||||
|
|
||||||
|
// ── 类型图标 ──────────────────────────────────────────
|
||||||
|
self.heartImg = [[UIImageView alloc] init];
|
||||||
|
self.heartImg.image = [UIImage imageNamed:@"homePageXinlv"];
|
||||||
|
[self.contentView addSubview:self.heartImg];
|
||||||
|
|
||||||
|
[self.heartImg mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.equalTo(self.contentView).offset(15);
|
||||||
|
make.top.equalTo(self.contentView).offset(13);
|
||||||
|
make.size.mas_equalTo(CGSizeMake(32, 32));
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
// ── 类型标题 "最新心率" ───────────────────────────────
|
||||||
|
self.updateLabel = [[UILabel alloc] init];
|
||||||
|
self.updateLabel.font = BOLDSYSTEMFONT(14);
|
||||||
|
self.updateLabel.textColor = UIColorHex(#252535);
|
||||||
|
self.updateLabel.text = @"最新心率";
|
||||||
|
[self.contentView addSubview:self.updateLabel];
|
||||||
|
|
||||||
|
[self.updateLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.equalTo(self.heartImg.mas_right).offset(12);
|
||||||
|
make.top.equalTo(self.heartImg);
|
||||||
|
make.height.mas_equalTo(15);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// ── 图标旁更新时间 ───────────────────────────────────
|
||||||
|
self.updateTimeLabel = [[UILabel alloc] init];
|
||||||
|
self.updateTimeLabel.font = MEDIUMFONT(12);
|
||||||
|
self.updateTimeLabel.textColor = UIColorHex(#77849E);
|
||||||
|
self.updateTimeLabel.text = @"--";
|
||||||
|
[self.contentView addSubview:self.updateTimeLabel];
|
||||||
|
|
||||||
|
[self.updateTimeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.equalTo(self.updateLabel);
|
||||||
|
make.top.equalTo(self.updateLabel.mas_bottom).offset(11);
|
||||||
|
make.height.mas_equalTo(11);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// ── 右侧大数值 ───────────────────────────────────────
|
||||||
|
self.dataLabel = [[UILabel alloc] init];
|
||||||
|
self.dataLabel.textColor = UIColorHex(#252535);
|
||||||
|
self.dataLabel.text = @"--次/分钟";
|
||||||
|
self.dataLabel.textAlignment = NSTextAlignmentRight;
|
||||||
|
self.dataLabel.adjustsFontSizeToFitWidth = YES;
|
||||||
|
[self.contentView addSubview:self.dataLabel];
|
||||||
|
|
||||||
|
[self.dataLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.equalTo(self.contentView).offset(-15);
|
||||||
|
make.centerY.equalTo(self.heartImg);
|
||||||
|
make.width.mas_equalTo(180);
|
||||||
|
make.height.mas_equalTo(30);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// ── 左卡片 ───────────────────────────────────────────
|
||||||
|
UIView *backLeft = [[UIView alloc] init];
|
||||||
|
backLeft.layer.cornerRadius = 8;
|
||||||
|
backLeft.layer.masksToBounds = YES;
|
||||||
|
backLeft.backgroundColor = UIColorHex(#F6F6F6);
|
||||||
|
[self.contentView addSubview:backLeft];
|
||||||
|
|
||||||
|
[backLeft mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.equalTo(self.contentView).offset(15);
|
||||||
|
make.top.equalTo(self.heartImg.mas_bottom).offset(21);
|
||||||
|
make.right.equalTo(self.contentView.mas_centerX).offset(-7.5);
|
||||||
|
make.height.mas_equalTo(72);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UIView *redLine = [[UIView alloc] init];
|
||||||
|
redLine.layer.cornerRadius = 2;
|
||||||
|
redLine.layer.masksToBounds = YES;
|
||||||
|
redLine.backgroundColor = CNavBgColor;
|
||||||
|
[backLeft addSubview:redLine];
|
||||||
|
|
||||||
|
[redLine mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.equalTo(backLeft).offset(15);
|
||||||
|
make.top.equalTo(backLeft).offset(16);
|
||||||
|
make.size.mas_equalTo(CGSizeMake(4, 11));
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.backLeftLabel = [[UILabel alloc] init];
|
||||||
|
self.backLeftLabel.font = BOLDSYSTEMFONT(14);
|
||||||
|
self.backLeftLabel.textColor = UIColorHex(#252535);
|
||||||
|
self.backLeftLabel.text = @"心率范围";
|
||||||
|
[backLeft addSubview:self.backLeftLabel];
|
||||||
|
|
||||||
|
[self.backLeftLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.equalTo(redLine.mas_right).offset(8);
|
||||||
|
make.top.equalTo(backLeft).offset(13);
|
||||||
|
make.height.mas_equalTo(15);
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.leftDataLabel = [[UILabel alloc] init];
|
||||||
|
self.leftDataLabel.font = BOLDSYSTEMFONT(16);
|
||||||
|
self.leftDataLabel.textColor = UIColorHex(#252535);
|
||||||
|
self.leftDataLabel.text = @"--";
|
||||||
|
self.leftDataLabel.adjustsFontSizeToFitWidth = YES;
|
||||||
|
[backLeft addSubview:self.leftDataLabel];
|
||||||
|
|
||||||
|
[self.leftDataLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.equalTo(backLeft).offset(14);
|
||||||
|
make.right.equalTo(backLeft).offset(-5);
|
||||||
|
make.top.equalTo(self.backLeftLabel.mas_bottom).offset(13);
|
||||||
|
make.height.mas_equalTo(17);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// ── 右卡片 ───────────────────────────────────────────
|
||||||
|
UIView *backRight = [[UIView alloc] init];
|
||||||
|
backRight.layer.cornerRadius = 8;
|
||||||
|
backRight.layer.masksToBounds = YES;
|
||||||
|
backRight.backgroundColor = UIColorHex(#F6F6F6);
|
||||||
|
[self.contentView addSubview:backRight];
|
||||||
|
|
||||||
|
[backRight mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.equalTo(self.contentView).offset(-15);
|
||||||
|
make.left.equalTo(self.contentView.mas_centerX).offset(7.5);
|
||||||
|
make.top.equalTo(backLeft);
|
||||||
|
make.height.mas_equalTo(72);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UIView *blueLine = [[UIView alloc] init];
|
||||||
|
blueLine.layer.cornerRadius = 2;
|
||||||
|
blueLine.layer.masksToBounds = YES;
|
||||||
|
blueLine.backgroundColor = UIColorHex(#30A9FF);
|
||||||
|
[backRight addSubview:blueLine];
|
||||||
|
|
||||||
|
[blueLine mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.equalTo(backRight).offset(15);
|
||||||
|
make.top.equalTo(backRight).offset(16);
|
||||||
|
make.size.mas_equalTo(CGSizeMake(4, 11));
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.backRightLabel = [[UILabel alloc] init];
|
||||||
|
self.backRightLabel.font = BOLDSYSTEMFONT(14);
|
||||||
|
self.backRightLabel.textColor = UIColorHex(#252535);
|
||||||
|
self.backRightLabel.text = @"平均心率";
|
||||||
|
[backRight addSubview:self.backRightLabel];
|
||||||
|
|
||||||
|
[self.backRightLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.equalTo(blueLine.mas_right).offset(8);
|
||||||
|
make.top.equalTo(backRight).offset(13);
|
||||||
|
make.height.mas_equalTo(15);
|
||||||
|
}];
|
||||||
|
|
||||||
|
self.rightDataLabel = [[UILabel alloc] init];
|
||||||
|
self.rightDataLabel.font = BOLDSYSTEMFONT(16);
|
||||||
|
self.rightDataLabel.textColor = UIColorHex(#252535);
|
||||||
|
self.rightDataLabel.text = @"--";
|
||||||
|
self.rightDataLabel.adjustsFontSizeToFitWidth = YES;
|
||||||
|
[backRight addSubview:self.rightDataLabel];
|
||||||
|
|
||||||
|
[self.rightDataLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.equalTo(backRight).offset(14);
|
||||||
|
make.right.equalTo(backRight).offset(-5);
|
||||||
|
make.top.equalTo(self.backRightLabel.mas_bottom).offset(13);
|
||||||
|
make.height.mas_equalTo(17);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// ── 底部更新时间 ─────────────────────────────────────
|
||||||
|
// self.timeLabel = [[UILabel alloc] init];
|
||||||
|
// self.timeLabel.textColor = UIColorHex(#77849E);
|
||||||
|
// self.timeLabel.textAlignment = NSTextAlignmentLeft;
|
||||||
|
// self.timeLabel.text = @"更新时间:--:--";
|
||||||
|
// self.timeLabel.font = MEDIUMFONT(12);
|
||||||
|
// [self.contentView addSubview:self.timeLabel];
|
||||||
|
//
|
||||||
|
// [self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
// make.top.equalTo(backLeft.mas_bottom).offset(8);
|
||||||
|
// make.left.equalTo(self.contentView).offset(15);
|
||||||
|
// make.right.equalTo(self.contentView).offset(-15);
|
||||||
|
// make.height.mas_equalTo(32);
|
||||||
|
// }];
|
||||||
|
|
||||||
|
// ── 无数据占位 ───────────────────────────────────────
|
||||||
|
self.emptyView = [[UIView alloc] init];
|
||||||
|
self.emptyView.backgroundColor = KWhiteColor;
|
||||||
|
self.emptyView.hidden = YES;
|
||||||
|
[self.contentView addSubview:self.emptyView];
|
||||||
|
|
||||||
|
[self.emptyView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.edges.equalTo(self.contentView);
|
||||||
|
}];
|
||||||
|
|
||||||
|
UILabel *emptyLabel = [[UILabel alloc] init];
|
||||||
|
emptyLabel.text = @"~ 无智能监测数据 ~";
|
||||||
|
emptyLabel.textColor = UIColorHex(#77849E);
|
||||||
|
emptyLabel.font = MEDIUMFONT(13);
|
||||||
|
emptyLabel.textAlignment = NSTextAlignmentCenter;
|
||||||
|
[self.emptyView addSubview:emptyLabel];
|
||||||
|
|
||||||
|
[emptyLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.center.equalTo(self.emptyView);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Public
|
||||||
|
|
||||||
|
- (void)configureWithData:(id)data {
|
||||||
|
if ([data isKindOfClass:[XJHomeWatchModel class]]) {
|
||||||
|
self.model = (XJHomeWatchModel *)data;
|
||||||
|
} else {
|
||||||
|
self.model = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - Model Setter
|
||||||
|
|
||||||
|
- (void)setModel:(XJHomeWatchModel *)model {
|
||||||
|
_model = model;
|
||||||
|
|
||||||
|
if (!model) {
|
||||||
|
self.emptyView.hidden = NO;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.emptyView.hidden = YES;
|
||||||
|
[self p_updateLabelsForTabIndex:[_model.type intValue]];
|
||||||
|
[self changeDataShow:[_model.type intValue] withModel:_model];
|
||||||
|
|
||||||
|
if (!ValidStr(_model.latestTime)) {
|
||||||
|
self.updateTimeLabel.text = _model.latestTime;
|
||||||
|
// self.timeLabel.text = [NSString stringWithFormat:@"更新时间:%@", _model.latestTime];
|
||||||
|
} else {
|
||||||
|
self.updateTimeLabel.text = @"--:--";
|
||||||
|
// self.timeLabel.text = @"更新时间:--:--";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Tab UI Update
|
||||||
|
|
||||||
|
/// 根据 tabIndex 切换图标和文字标题(不涉及数据)
|
||||||
|
- (void)p_updateLabelsForTabIndex:(NSInteger)tabIndex {
|
||||||
|
|
||||||
|
|
||||||
|
NSArray *icons = @[@"homePageXinlv", @"homePageXueyang", @"homePageYali", @"homePageTiwen", @"homePageShuimian"];
|
||||||
|
NSArray *latest = @[@"最新心率", @"最新血氧", @"最新压力", @"最新体温", @"睡眠总时长"];
|
||||||
|
NSArray *left = @[@"心率范围", @"血氧范围", @"压力范围", @"体温范围", @"深睡时长"];
|
||||||
|
NSArray *right = @[@"平均心率", @"平均血氧", @"平均压力", @"平均体温", @"浅睡时长"];
|
||||||
|
NSArray *units = @[@"--次/分钟", @"--%", @"--", @"--℃", @"--"];
|
||||||
|
/** 数据类型:0=心率 1=血氧 2=压力 3=体温 4=睡眠 */
|
||||||
|
if (tabIndex < 0 || tabIndex >= (NSInteger)icons.count) return;
|
||||||
|
|
||||||
|
self.heartImg.image = [UIImage imageNamed:icons[tabIndex]];
|
||||||
|
self.updateLabel.text = latest[tabIndex];
|
||||||
|
self.backLeftLabel.text = left[tabIndex];
|
||||||
|
self.backRightLabel.text = right[tabIndex];
|
||||||
|
|
||||||
|
// 无数据时显示占位
|
||||||
|
if (!_model) {
|
||||||
|
self.dataLabel.text = units[tabIndex];
|
||||||
|
self.leftDataLabel.text = @"--";
|
||||||
|
self.rightDataLabel.text = @"--";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Data Display
|
||||||
|
|
||||||
|
- (void)changeDataShow:(NSInteger)isOne withModel:(XJHomeWatchModel *)model {
|
||||||
|
|
||||||
|
if (isOne == 0) { // 心率
|
||||||
|
|
||||||
|
NSString *s = [NSString stringWithFormat:@"%.0f次/分钟", model.latest];
|
||||||
|
self.dataLabel.attributedText = [self p_bigAttr:s unitLen:4];
|
||||||
|
|
||||||
|
NSString *range = [NSString stringWithFormat:@"%.0f-%.0f次/分钟", model.max, model.min];
|
||||||
|
self.leftDataLabel.attributedText = [self p_mediumAttr:range unitLen:4];
|
||||||
|
|
||||||
|
NSString *avg = [NSString stringWithFormat:@"%.0f次/分钟", model.avg];
|
||||||
|
self.rightDataLabel.attributedText = [self p_mediumAttr:avg unitLen:4];
|
||||||
|
|
||||||
|
} else if (isOne == 1) { // 血氧
|
||||||
|
|
||||||
|
NSString *s = [NSString stringWithFormat:@"%.0f%%", model.latest];
|
||||||
|
self.dataLabel.attributedText = [self p_bigAttr:s unitLen:1];
|
||||||
|
|
||||||
|
NSString *range = [NSString stringWithFormat:@"%.0f-%.0f%%", model.min, model.max];
|
||||||
|
self.leftDataLabel.attributedText = [self p_mediumAttr:range unitLen:1];
|
||||||
|
|
||||||
|
NSString *avg = [NSString stringWithFormat:@"%.0f%%", model.avg];
|
||||||
|
self.rightDataLabel.attributedText = [self p_mediumAttr:avg unitLen:1];
|
||||||
|
|
||||||
|
} else if (isOne == 2) { // 压力
|
||||||
|
|
||||||
|
NSString *s = [NSString stringWithFormat:@"%.0f", model.latest];
|
||||||
|
self.dataLabel.attributedText = [self p_plainAttr:s size:25];
|
||||||
|
|
||||||
|
NSString *range = [NSString stringWithFormat:@"%.0f-%.0f", model.min, model.max];
|
||||||
|
self.leftDataLabel.attributedText = [self p_plainAttr:range size:20];
|
||||||
|
|
||||||
|
NSString *avg = [NSString stringWithFormat:@"%.0f", model.avg];
|
||||||
|
self.rightDataLabel.attributedText = [self p_plainAttr:avg size:20];
|
||||||
|
|
||||||
|
} else if (isOne == 3) { // 体温
|
||||||
|
|
||||||
|
NSString *s = [NSString stringWithFormat:@"%.1f℃", model.latest];
|
||||||
|
self.dataLabel.attributedText = [self p_bigAttr:s unitLen:1];
|
||||||
|
|
||||||
|
NSString *range = [NSString stringWithFormat:@"%.1f-%.1f℃", model.min, model.max];
|
||||||
|
self.leftDataLabel.attributedText = [self p_mediumAttr:range unitLen:1];
|
||||||
|
|
||||||
|
NSString *avg = [NSString stringWithFormat:@"%.1f℃", model.avg];
|
||||||
|
self.rightDataLabel.attributedText = [self p_mediumAttr:avg unitLen:1];
|
||||||
|
|
||||||
|
} else if (isOne == 4) { // 睡眠
|
||||||
|
|
||||||
|
UIFont *bigFont = [UIFont systemFontOfSize:25 weight:UIFontWeightBold];
|
||||||
|
UIFont *mediumFont = [UIFont systemFontOfSize:20 weight:UIFontWeightMedium];
|
||||||
|
self.dataLabel.attributedText = [self convertMinutes:model.latest withFont:bigFont];
|
||||||
|
self.leftDataLabel.attributedText = [self convertMinutes:model.max withFont:mediumFont];
|
||||||
|
self.rightDataLabel.attributedText = [self convertMinutes:model.min withFont:mediumFont];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Attributed String Helpers
|
||||||
|
|
||||||
|
/// 大数值:主体 25pt bold #252535,末尾 unitLen 个字符 14pt #77849E
|
||||||
|
- (NSMutableAttributedString *)p_bigAttr:(NSString *)str unitLen:(NSInteger)unitLen {
|
||||||
|
NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithString:str];
|
||||||
|
NSInteger bodyLen = MAX((NSInteger)str.length - unitLen, 0);
|
||||||
|
NSInteger tail = (NSInteger)str.length - bodyLen;
|
||||||
|
|
||||||
|
[attr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:25 weight:UIFontWeightBold]
|
||||||
|
range:NSMakeRange(0, bodyLen)];
|
||||||
|
[attr addAttribute:NSForegroundColorAttributeName value:UIColorHex(#252535)
|
||||||
|
range:NSMakeRange(0, bodyLen)];
|
||||||
|
if (tail > 0) {
|
||||||
|
[attr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:14 weight:UIFontWeightMedium]
|
||||||
|
range:NSMakeRange(bodyLen, tail)];
|
||||||
|
[attr addAttribute:NSForegroundColorAttributeName value:UIColorHex(#77849E)
|
||||||
|
range:NSMakeRange(bodyLen, tail)];
|
||||||
|
}
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 卡片数值:主体 20pt bold #252535,末尾 unitLen 个字符 12pt #77849E
|
||||||
|
- (NSMutableAttributedString *)p_mediumAttr:(NSString *)str unitLen:(NSInteger)unitLen {
|
||||||
|
NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithString:str];
|
||||||
|
NSInteger bodyLen = MAX((NSInteger)str.length - unitLen, 0);
|
||||||
|
NSInteger tail = (NSInteger)str.length - bodyLen;
|
||||||
|
|
||||||
|
[attr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:20 weight:UIFontWeightBold]
|
||||||
|
range:NSMakeRange(0, bodyLen)];
|
||||||
|
[attr addAttribute:NSForegroundColorAttributeName value:UIColorHex(#252535)
|
||||||
|
range:NSMakeRange(0, bodyLen)];
|
||||||
|
if (tail > 0) {
|
||||||
|
[attr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:12 weight:UIFontWeightMedium]
|
||||||
|
range:NSMakeRange(bodyLen, tail)];
|
||||||
|
[attr addAttribute:NSForegroundColorAttributeName value:UIColorHex(#77849E)
|
||||||
|
range:NSMakeRange(bodyLen, tail)];
|
||||||
|
}
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 纯数字(压力),无单位,整体 size pt bold #252535
|
||||||
|
- (NSMutableAttributedString *)p_plainAttr:(NSString *)str size:(CGFloat)size {
|
||||||
|
NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithString:str];
|
||||||
|
[attr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:size weight:UIFontWeightBold]
|
||||||
|
range:NSMakeRange(0, str.length)];
|
||||||
|
[attr addAttribute:NSForegroundColorAttributeName value:UIColorHex(#252535)
|
||||||
|
range:NSMakeRange(0, str.length)];
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSMutableAttributedString *)convertMinutes:(float)minutes withFont:(UIFont *)font {
|
||||||
|
NSString *timeString;
|
||||||
|
if (minutes == 0) {
|
||||||
|
timeString = @"0分钟";
|
||||||
|
} else if (minutes < 60) {
|
||||||
|
timeString = [NSString stringWithFormat:@"%.0f分钟", minutes];
|
||||||
|
} else {
|
||||||
|
int h = (int)(minutes / 60);
|
||||||
|
int m = (int)(minutes) % 60;
|
||||||
|
timeString = [NSString stringWithFormat:@"%d小时%d分钟", h, m];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithString:timeString];
|
||||||
|
[attr addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, timeString.length)];
|
||||||
|
[attr addAttribute:NSForegroundColorAttributeName value:UIColorHex(#252535)
|
||||||
|
range:NSMakeRange(0, timeString.length)];
|
||||||
|
|
||||||
|
for (NSString *unit in @[@"小时", @"分钟"]) {
|
||||||
|
NSRange r = [timeString rangeOfString:unit];
|
||||||
|
if (r.location != NSNotFound) {
|
||||||
|
[attr addAttribute:NSFontAttributeName
|
||||||
|
value:[UIFont systemFontOfSize:14 weight:UIFontWeightMedium]
|
||||||
|
range:r];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
//
|
||||||
|
// XJHomeWatchDataView.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/3/2.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import "XJHomeWatchModel.h"
|
||||||
|
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/// Tab 点击回调:index 选中下标,title 选中标题
|
||||||
|
typedef void(^XJHomeWatchTabSelectBlock)(NSInteger index, NSString *title);
|
||||||
|
|
||||||
|
typedef void(^watchDataDetailBlick)();
|
||||||
|
|
||||||
|
|
||||||
|
@interface XJHomeWatchDataView : UIView
|
||||||
|
|
||||||
|
/// 设置 Tab 标题数组,赋值后自动刷新按钮
|
||||||
|
@property (nonatomic, copy) NSArray<NSString *> *tabTitles;
|
||||||
|
|
||||||
|
/// Tab 点击回调
|
||||||
|
@property (nonatomic, copy, nullable) XJHomeWatchTabSelectBlock tabSelectBlock;
|
||||||
|
|
||||||
|
@property (nonatomic, copy, nullable) watchDataDetailBlick watchMoreBlock;
|
||||||
|
|
||||||
|
/// "去绑定" 按钮点击回调
|
||||||
|
@property (nonatomic, copy, nullable) void (^bindDeviceBlock)(NSString * number);
|
||||||
|
|
||||||
|
/// 数据源,赋值后自动刷新 CollectionView,空数组时显示占位图
|
||||||
|
@property (nonatomic, copy) NSArray *dataList;
|
||||||
|
|
||||||
|
/// 底部 CollectionView(可用于外部调用 scrollToItem 等)
|
||||||
|
@property (nonatomic, strong, readonly) UICollectionView *collectionView;
|
||||||
|
|
||||||
|
/// 当前选中的 Tab 下标
|
||||||
|
@property (nonatomic, assign, readonly) NSInteger selectedIndex;
|
||||||
|
|
||||||
|
/// 手动切换 Tab(不触发 block)
|
||||||
|
- (void)selectTabAtIndex:(NSInteger)index;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) XJHomeWatchModel * watchModel;
|
||||||
|
|
||||||
|
@property (nonatomic, copy) void (^changeTimeClickBlock)(NSString *startDate);
|
||||||
|
|
||||||
|
/// 高度变化回调:无数据/未登录时返回 104,有数据时返回 205
|
||||||
|
@property (nonatomic, copy, nullable) void (^heightChangeBlock)(CGFloat height);
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,722 @@
|
|||||||
|
//
|
||||||
|
// XJHomeWatchDataView.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/3/2.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJHomeWatchDataView.h"
|
||||||
|
#import "XJHomeWatchCollectionViewCell.h"
|
||||||
|
#import <Masonry/Masonry.h>
|
||||||
|
|
||||||
|
// ── 布局常量 ──────────────────────────────────────────────
|
||||||
|
static CGFloat const kHeaderHeight = 92.0; // 头部保留高度(外部自行填充)
|
||||||
|
static CGFloat const kTabScrollH = 52.0; // Tab ScrollView 高度
|
||||||
|
static CGFloat const kButtonH = 30.0; // 按钮高度
|
||||||
|
static CGFloat const kButtonPadX = 10.0; // 按钮左右内边距
|
||||||
|
static CGFloat const kButtonGap = 10.0; // 按钮间距
|
||||||
|
|
||||||
|
|
||||||
|
// ── Private ───────────────────────────────────────────────
|
||||||
|
@interface XJHomeWatchDataView ()<UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
||||||
|
|
||||||
|
@property (nonatomic, strong) YYLabel *watchNumberLabel; //
|
||||||
|
|
||||||
|
|
||||||
|
//@property (nonatomic, strong) UIScrollView *tabScrollView;
|
||||||
|
@property (nonatomic, strong) UIView *tabContentView;
|
||||||
|
@property (nonatomic, strong) NSMutableArray<UIButton *> *tabButtons;
|
||||||
|
@property (nonatomic, strong) UICollectionView *collectionView;
|
||||||
|
@property (nonatomic, strong) UILabel *emptyLabel; // 无数据占位
|
||||||
|
@property (nonatomic, strong) UIView *emptyView; // 空状态占位整体容器
|
||||||
|
@property (nonatomic, strong) UIView *devView; // 紧急开发中占位
|
||||||
|
@property (nonatomic, assign) NSInteger selectedIndex; // 当前选中的 Tab 下标
|
||||||
|
@property (nonatomic, assign) NSInteger carouselPage; // collectionView 当前轮播页码(与 Tab 无关)
|
||||||
|
@property (nonatomic, strong) NSTimer *autoScrollTimer; // 轮播定时器
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UIView *
|
||||||
|
timeView;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UIButton *
|
||||||
|
preBtn;
|
||||||
|
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UIButton *
|
||||||
|
nextBtn;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) UILabel *
|
||||||
|
weekLabel;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) NSDate * currentDayDate; // 当前选中的日
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
@implementation XJHomeWatchDataView
|
||||||
|
|
||||||
|
#pragma mark - Init
|
||||||
|
|
||||||
|
- (instancetype)initWithFrame:(CGRect)frame {
|
||||||
|
self = [super initWithFrame:frame];
|
||||||
|
self.backgroundColor = KWhiteColor;
|
||||||
|
self.layer.cornerRadius = 12;
|
||||||
|
self.layer.masksToBounds = true;
|
||||||
|
if (self) [self p_setupUI];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UI Setup
|
||||||
|
|
||||||
|
- (void)p_setupUI {
|
||||||
|
_selectedIndex = 0;
|
||||||
|
_tabButtons = [NSMutableArray array];
|
||||||
|
self.currentDayDate = [NSDate date];
|
||||||
|
UIImageView * heaedImg = [[UIImageView alloc] init];
|
||||||
|
heaedImg.image = [UIImage imageNamed:@"heaedTitleBackImg"];
|
||||||
|
heaedImg.userInteractionEnabled = true;
|
||||||
|
[self addSubview:heaedImg];
|
||||||
|
|
||||||
|
[heaedImg mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.top.mas_offset(0);
|
||||||
|
make.height.mas_offset(40);
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
UILabel * todayLabel = [[UILabel alloc] init];
|
||||||
|
|
||||||
|
todayLabel.text = @"健康监测";
|
||||||
|
|
||||||
|
todayLabel.textAlignment = NSTextAlignmentLeft;
|
||||||
|
|
||||||
|
todayLabel.textColor = CFontColor1;
|
||||||
|
|
||||||
|
todayLabel.font = BOLDSYSTEMFONT(16);
|
||||||
|
|
||||||
|
[heaedImg addSubview:todayLabel];
|
||||||
|
|
||||||
|
[todayLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(13);
|
||||||
|
make.top.bottom.mas_offset(0);
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
UIButton * moreBtn = [[UIButton alloc] init];
|
||||||
|
[moreBtn setImage:[UIImage imageNamed:@"wacthRightAccow"] forState:UIControlStateNormal];
|
||||||
|
[moreBtn addTarget:self action:@selector(moreClick) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
[heaedImg addSubview:moreBtn];
|
||||||
|
[moreBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.mas_offset(-8);
|
||||||
|
make.centerY.mas_equalTo(heaedImg);
|
||||||
|
make.width.height.mas_offset(30);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// YYLabel * morelabel = [[YYLabel alloc] init];
|
||||||
|
// morelabel.text = @">";
|
||||||
|
// morelabel.textAlignment = NSTextAlignmentRight;
|
||||||
|
// morelabel.textColor = UIColorHex(#999999);
|
||||||
|
// morelabel.font = SYSTEMFONT(14);
|
||||||
|
// MJWeakSelf
|
||||||
|
// [morelabel setTextTapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {
|
||||||
|
// if (self.watchMoreBlock) {
|
||||||
|
// self.watchMoreBlock();
|
||||||
|
// }
|
||||||
|
// }];
|
||||||
|
// [heaedImg addSubview:morelabel];
|
||||||
|
//
|
||||||
|
// [morelabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
// make.right.mas_offset(-13);
|
||||||
|
// make.centerY.mas_equalTo(heaedImg);
|
||||||
|
// make.width.height.mas_offset(20);
|
||||||
|
// }];
|
||||||
|
//
|
||||||
|
self.watchNumberLabel = [[YYLabel alloc] init];
|
||||||
|
|
||||||
|
self.watchNumberLabel.text = @"";
|
||||||
|
|
||||||
|
self.watchNumberLabel.textAlignment = NSTextAlignmentLeft;
|
||||||
|
|
||||||
|
self.watchNumberLabel.textColor = UIColorHex(#14BEBE);
|
||||||
|
|
||||||
|
self.watchNumberLabel.font = MEDIUMFONT(13);
|
||||||
|
|
||||||
|
[heaedImg addSubview:self.watchNumberLabel];
|
||||||
|
|
||||||
|
[self.watchNumberLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.mas_equalTo(moreBtn.mas_left);
|
||||||
|
make.top.mas_offset(0);
|
||||||
|
make.height.mas_offset(40);
|
||||||
|
}];
|
||||||
|
MJWeakSelf
|
||||||
|
[self.watchNumberLabel setTextTapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {
|
||||||
|
|
||||||
|
if (weakSelf.bindDeviceBlock) {
|
||||||
|
weakSelf.bindDeviceBlock(weakSelf.watchModel.watchNo);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
//日期切换
|
||||||
|
// self.timeView = [[UIView alloc] init];
|
||||||
|
// self.timeView.backgroundColor = KWhiteColor;
|
||||||
|
// [self addSubview:self.timeView];
|
||||||
|
//
|
||||||
|
// [self.timeView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
// make.left.right.mas_offset(0);
|
||||||
|
// make.top.mas_equalTo(heaedImg.mas_bottom);
|
||||||
|
// make.height.mas_offset(52);
|
||||||
|
// }];
|
||||||
|
//
|
||||||
|
// UIButton *preBtn = [[UIButton alloc] init];
|
||||||
|
// [preBtn setTitle:@"上一天" forState:UIControlStateNormal];
|
||||||
|
// [preBtn setImage:[UIImage imageNamed:@"blackLeftAccow"] forState:UIControlStateNormal];
|
||||||
|
// [preBtn setTitleColor:UIColorHex(#333333) forState:UIControlStateNormal];
|
||||||
|
// preBtn.titleLabel.font = MEDIUMFONT(12);
|
||||||
|
// preBtn.titleEdgeInsets = UIEdgeInsetsMake(0, -8, 0, 8); // 左边多 4px 间距
|
||||||
|
// self.preBtn = preBtn;
|
||||||
|
// [preBtn addTarget:self action:@selector(previousWeekAction) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
// [self.timeView addSubview:preBtn];
|
||||||
|
//
|
||||||
|
// [preBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
// make.left.mas_equalTo(@46);
|
||||||
|
// make.width.mas_offset(60); // 注意宽度要能容纳文字+图片
|
||||||
|
// make.centerY.mas_equalTo(self.timeView);
|
||||||
|
// }];
|
||||||
|
// preBtn.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// UIButton *rightBtn = [[UIButton alloc] init];
|
||||||
|
// [rightBtn setImage:[UIImage imageNamed:@"blackRightAccow"] forState:UIControlStateNormal];
|
||||||
|
// [rightBtn setTitle:@"下一天" forState:UIControlStateNormal];
|
||||||
|
// [rightBtn setTitleColor:UIColorHex(#333333) forState:UIControlStateNormal];
|
||||||
|
// rightBtn.titleLabel.font = MEDIUMFONT(12);
|
||||||
|
// rightBtn.titleEdgeInsets = UIEdgeInsetsMake(0, 8, 0, 0); // 左边多 4px 间距
|
||||||
|
// self.nextBtn = rightBtn;
|
||||||
|
// [rightBtn addTarget:self action:@selector(nextWeekAction) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
// [self.timeView addSubview:rightBtn];
|
||||||
|
// [rightBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
// make.right.mas_equalTo(@-46);
|
||||||
|
// make.width.mas_offset(60); // 记得宽度要能容下文字+图片
|
||||||
|
// make.centerY.mas_equalTo(self.timeView);
|
||||||
|
// }];
|
||||||
|
//
|
||||||
|
// self.weekLabel = [[UILabel alloc] init];
|
||||||
|
// self.weekLabel.textAlignment = NSTextAlignmentCenter;
|
||||||
|
// self.weekLabel.textColor = UIColorHex(#333333);
|
||||||
|
// self.weekLabel.font = MEDIUMFONT(12);
|
||||||
|
// [self.timeView addSubview: self.weekLabel];
|
||||||
|
//
|
||||||
|
// [self.weekLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
// make.right.mas_equalTo(rightBtn.mas_left);
|
||||||
|
// make.left.mas_equalTo(preBtn.mas_right);
|
||||||
|
// make.centerY.mas_equalTo(self.timeView);
|
||||||
|
// make.top.mas_offset(0);
|
||||||
|
// }];
|
||||||
|
//
|
||||||
|
// [self updateWeekLabelWithType];
|
||||||
|
//
|
||||||
|
// ── Tab ScrollView ───────────────────────────────────
|
||||||
|
// _tabScrollView = [[UIScrollView alloc] init];
|
||||||
|
// _tabScrollView.showsHorizontalScrollIndicator = NO;
|
||||||
|
// _tabScrollView.showsVerticalScrollIndicator = NO;
|
||||||
|
// [self addSubview:_tabScrollView];
|
||||||
|
//
|
||||||
|
// [_tabScrollView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
// make.top.equalTo(heaedImg.mas_bottom);
|
||||||
|
// make.left.right.equalTo(self);
|
||||||
|
// make.height.mas_equalTo(kTabScrollH);
|
||||||
|
// }];
|
||||||
|
|
||||||
|
// scrollView 内的容器 view(Masonry 驱动 contentSize)
|
||||||
|
// _tabContentView = [[UIView alloc] init];
|
||||||
|
// [_tabScrollView addSubview:_tabContentView];
|
||||||
|
//
|
||||||
|
// [_tabContentView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
// make.edges.equalTo(_tabScrollView); // 四边贴 scrollView
|
||||||
|
// make.height.equalTo(_tabScrollView); // 固定高度 = scrollView,只横向滚动
|
||||||
|
// }];
|
||||||
|
|
||||||
|
// ── 底部 CollectionView ──────────────────────────────
|
||||||
|
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||||
|
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||||
|
layout.minimumLineSpacing = 0;
|
||||||
|
layout.minimumInteritemSpacing = 0;
|
||||||
|
|
||||||
|
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero
|
||||||
|
collectionViewLayout:layout];
|
||||||
|
_collectionView.backgroundColor = UIColor.clearColor;
|
||||||
|
_collectionView.showsHorizontalScrollIndicator = NO;
|
||||||
|
_collectionView.pagingEnabled = YES;
|
||||||
|
_collectionView.delegate = self;
|
||||||
|
_collectionView.dataSource = self;
|
||||||
|
[_collectionView registerClass:[XJHomeWatchCollectionViewCell class]
|
||||||
|
forCellWithReuseIdentifier:NSStringFromClass([XJHomeWatchCollectionViewCell class])];
|
||||||
|
[self addSubview:_collectionView];
|
||||||
|
|
||||||
|
[_collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.equalTo(@40);
|
||||||
|
make.left.right.bottom.equalTo(self);
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
// ── 未登录占位 Label ─────────────────────────────────────────
|
||||||
|
_emptyLabel = [[UILabel alloc] init];
|
||||||
|
_emptyLabel.text = @" 暂未登录 ";
|
||||||
|
_emptyLabel.textAlignment = NSTextAlignmentCenter;
|
||||||
|
_emptyLabel.textColor = [UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:1.0];
|
||||||
|
_emptyLabel.font = [UIFont systemFontOfSize:15.0];
|
||||||
|
_emptyLabel.hidden = YES;
|
||||||
|
[self.collectionView addSubview:_emptyLabel];
|
||||||
|
|
||||||
|
[_emptyLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.center.equalTo(self.collectionView);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// ── 无设备占位 View(已登录但未绑定设备时显示)────────────────
|
||||||
|
_emptyView = [[UIView alloc] init];
|
||||||
|
_emptyView.backgroundColor = KWhiteColor;
|
||||||
|
_emptyView.hidden = YES;
|
||||||
|
[self addSubview:_emptyView];
|
||||||
|
|
||||||
|
[_emptyView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.equalTo(@40);
|
||||||
|
make.left.right.bottom.equalTo(self);
|
||||||
|
}];
|
||||||
|
|
||||||
|
// // 空状态图标,宽高 59,居中,距 Tab 切换 View 底部 16
|
||||||
|
// UIImageView *emptyImageView = [[UIImageView alloc] init];
|
||||||
|
// emptyImageView.image = [UIImage imageNamed:@"ic_watch_empty"];
|
||||||
|
// emptyImageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||||
|
// [_emptyView addSubview:emptyImageView];
|
||||||
|
//
|
||||||
|
// [emptyImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
// make.top.mas_offset(16);
|
||||||
|
// make.centerX.equalTo(_emptyView);
|
||||||
|
// make.width.height.mas_offset(59);
|
||||||
|
// }];
|
||||||
|
//
|
||||||
|
// // 提示文字:~ 暂无数据 ~,字号 11 regular,颜色 #B6B6B6
|
||||||
|
// UILabel *emptyHintLabel = [[UILabel alloc] init];
|
||||||
|
// emptyHintLabel.text = @"~ 暂无数据 ~";
|
||||||
|
// emptyHintLabel.textAlignment = NSTextAlignmentCenter;
|
||||||
|
// emptyHintLabel.textColor = UIColorHex(#B6B6B6);
|
||||||
|
// emptyHintLabel.font = [UIFont systemFontOfSize:11];
|
||||||
|
// [_emptyView addSubview:emptyHintLabel];
|
||||||
|
//
|
||||||
|
// [emptyHintLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
// make.top.equalTo(emptyImageView.mas_bottom).offset(8);
|
||||||
|
// make.centerX.equalTo(_emptyView);
|
||||||
|
// }];
|
||||||
|
|
||||||
|
// 去绑定按钮:宽 80 高 24,medium 13,颜色 #21BEBD,圆角 12,白底边框 1
|
||||||
|
UIButton *bindBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
|
[bindBtn setTitle:@"去绑定" forState:UIControlStateNormal];
|
||||||
|
[bindBtn setTitleColor:UIColorHex(#21BEBD) forState:UIControlStateNormal];
|
||||||
|
bindBtn.titleLabel.font = MEDIUMFONT(13);
|
||||||
|
bindBtn.backgroundColor = KWhiteColor;
|
||||||
|
bindBtn.layer.cornerRadius = 12;
|
||||||
|
bindBtn.layer.borderWidth = 1;
|
||||||
|
bindBtn.layer.borderColor = UIColorHex(#21BEBD).CGColor;
|
||||||
|
bindBtn.layer.masksToBounds = YES;
|
||||||
|
[bindBtn addTarget:self action:@selector(bindButtonClick) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
[_emptyView addSubview:bindBtn];
|
||||||
|
|
||||||
|
[bindBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.mas_offset(20);
|
||||||
|
make.centerX.equalTo(_emptyView);
|
||||||
|
make.width.mas_offset(82);
|
||||||
|
make.height.mas_offset(24);
|
||||||
|
}];
|
||||||
|
|
||||||
|
if ([HQCommonUtils isLogin]) {
|
||||||
|
// 已登录,等待数据回调
|
||||||
|
} else {
|
||||||
|
// 未登录:显示"暂未登录"文字,emptyView 保持隐藏
|
||||||
|
_emptyLabel.hidden = NO;
|
||||||
|
_collectionView.hidden = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)bindButtonClick {
|
||||||
|
if (self.bindDeviceBlock) {
|
||||||
|
self.bindDeviceBlock(@"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)moreClick {
|
||||||
|
|
||||||
|
if (![HQCommonUtils isLogin]) {
|
||||||
|
|
||||||
|
KPostNotification(KNotificationLoginStateChange, @NO);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.watchModel.hasWatch == true) {
|
||||||
|
if (self.watchMoreBlock) {
|
||||||
|
self.watchMoreBlock();
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
|
||||||
|
if (self.bindDeviceBlock) {
|
||||||
|
self.bindDeviceBlock(@"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
- (void)setWatchModel:(XJHomeWatchModel *)watchModel {
|
||||||
|
|
||||||
|
_watchModel = watchModel;
|
||||||
|
|
||||||
|
if (_watchModel.hasWatch == true) {
|
||||||
|
//有手表
|
||||||
|
self.watchNumberLabel.text = [NSString stringWithFormat:@"监测工具编码:%@",_watchModel.watchNo];
|
||||||
|
self.watchNumberLabel.textColor = UIColorHex(#14BEBE);
|
||||||
|
|
||||||
|
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
self.watchNumberLabel.text = @"监测工具编码:暂无信息";
|
||||||
|
self.watchNumberLabel.textColor = UIColorHex(#808080);
|
||||||
|
self.dataList = @[];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Tab Titles Setter
|
||||||
|
|
||||||
|
- (void)setTabTitles:(NSArray<NSString *> *)tabTitles {
|
||||||
|
_tabTitles = [tabTitles copy];
|
||||||
|
_selectedIndex = 0;
|
||||||
|
|
||||||
|
// 清除旧按钮
|
||||||
|
for (UIButton *btn in _tabButtons) [btn removeFromSuperview];
|
||||||
|
[_tabButtons removeAllObjects];
|
||||||
|
|
||||||
|
UIFont *font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
|
||||||
|
UIButton *prevBtn = nil;
|
||||||
|
|
||||||
|
for (NSInteger i = 0; i < (NSInteger)tabTitles.count; i++) {
|
||||||
|
NSString *title = tabTitles[i];
|
||||||
|
BOOL isSelected = (i == 0);
|
||||||
|
|
||||||
|
// 计算文字宽度,得到按钮宽度
|
||||||
|
CGFloat textW = ceil([title boundingRectWithSize:CGSizeMake(MAXFLOAT, kButtonH)
|
||||||
|
options:NSStringDrawingUsesLineFragmentOrigin
|
||||||
|
attributes:@{NSFontAttributeName: font}
|
||||||
|
context:nil].size.width);
|
||||||
|
CGFloat btnW = textW + kRealValue(kButtonPadX) * 2;
|
||||||
|
|
||||||
|
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
|
btn.tag = i;
|
||||||
|
btn.titleLabel.font = font;
|
||||||
|
btn.layer.cornerRadius = kButtonH / 2.0;
|
||||||
|
btn.clipsToBounds = YES;
|
||||||
|
btn.backgroundColor = isSelected ? UIColorHex(#14BEBE) : UIColorHex(#F6F7FB);
|
||||||
|
[btn setTitle:title forState:UIControlStateNormal];
|
||||||
|
btn.titleLabel.font = isSelected ? BOLDSYSTEMFONT(15) : [UIFont systemFontOfSize:14 weight:UIFontWeightRegular];
|
||||||
|
[btn setTitleColor:isSelected ? KWhiteColor : UIColorHex(#808080)
|
||||||
|
forState:UIControlStateNormal];
|
||||||
|
[btn addTarget:self
|
||||||
|
action:@selector(p_tabButtonTapped:)
|
||||||
|
forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
|
||||||
|
[_tabContentView addSubview:btn];
|
||||||
|
|
||||||
|
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.centerY.equalTo(_tabContentView);
|
||||||
|
make.height.mas_equalTo(kButtonH);
|
||||||
|
make.width.mas_equalTo(btnW);
|
||||||
|
|
||||||
|
if (prevBtn) {
|
||||||
|
make.left.equalTo(prevBtn.mas_right).offset(kButtonGap);
|
||||||
|
} else {
|
||||||
|
make.left.equalTo(_tabContentView).offset(kButtonGap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最后一个按钮右边贴 contentView(撑开 scrollView contentSize)
|
||||||
|
if (i == (NSInteger)tabTitles.count - 1) {
|
||||||
|
make.right.equalTo(_tabContentView).offset(-kButtonGap);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
[_tabButtons addObject:btn];
|
||||||
|
prevBtn = btn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Button Tap
|
||||||
|
|
||||||
|
- (void)p_tabButtonTapped:(UIButton *)sender {
|
||||||
|
NSInteger index = sender.tag;
|
||||||
|
[self selectTabAtIndex:index];
|
||||||
|
// 用户主动点击,重置轮播计时器
|
||||||
|
[self p_restartAutoScroll];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Public: Select Tab
|
||||||
|
|
||||||
|
//- (void)selectTabAtIndex:(NSInteger)index {
|
||||||
|
// if (index < 0 || index >= (NSInteger)_tabButtons.count) return;
|
||||||
|
// if (![HQCommonUtils isLogin]) {
|
||||||
|
// KPostNotification(KNotificationLoginStateChange, @NO);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 恢复旧 Tab 样式
|
||||||
|
// UIButton *oldBtn = _tabButtons[_selectedIndex];
|
||||||
|
// oldBtn.backgroundColor = UIColorHex(#F6F7FB);
|
||||||
|
// oldBtn.titleLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightRegular];
|
||||||
|
// [oldBtn setTitleColor:UIColorHex(#808080) forState:UIControlStateNormal];
|
||||||
|
//
|
||||||
|
// // 设置新 Tab 样式
|
||||||
|
// _selectedIndex = index;
|
||||||
|
// UIButton *newBtn = _tabButtons[index];
|
||||||
|
// newBtn.backgroundColor = UIColorHex(#14BEBE);
|
||||||
|
// newBtn.titleLabel.font = BOLDSYSTEMFONT(14);
|
||||||
|
// [newBtn setTitleColor:KWhiteColor forState:UIControlStateNormal];
|
||||||
|
//
|
||||||
|
// [self p_scrollToButton:newBtn];
|
||||||
|
//
|
||||||
|
// // tab 0:显示 CollectionView 并恢复轮播;其他:显示"紧急开发中"并暂停轮播
|
||||||
|
// BOOL isFirst = (index == 0);
|
||||||
|
// _collectionView.hidden = !isFirst;
|
||||||
|
// _devView.hidden = isFirst;
|
||||||
|
//
|
||||||
|
// if (isFirst) {
|
||||||
|
// // 切换回第一个 Tab,重新根据数据状态显示 emptyView
|
||||||
|
// BOOL isEmpty = (_dataList.count == 0);
|
||||||
|
// _emptyView.hidden = !isEmpty;
|
||||||
|
// [self p_restartAutoScroll];
|
||||||
|
// } else {
|
||||||
|
// // 切换到其他 Tab,隐藏 emptyView
|
||||||
|
// _emptyView.hidden = YES;
|
||||||
|
// [self p_stopAutoScroll];
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 通知外部高度变化
|
||||||
|
// if (self.tabSelectBlock) {
|
||||||
|
// self.tabSelectBlock(index, _tabTitles[index]);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
///// 若按钮中心超过可视区一半,则滚动将其居中
|
||||||
|
//- (void)p_scrollToButton:(UIButton *)btn {
|
||||||
|
// // layoutIfNeeded 保证 frame 已计算
|
||||||
|
// [_tabScrollView layoutIfNeeded];
|
||||||
|
//
|
||||||
|
// CGFloat scrollW = _tabScrollView.bounds.size.width;
|
||||||
|
// CGFloat contentW = _tabScrollView.contentSize.width;
|
||||||
|
// CGFloat btnCenterX = CGRectGetMidX(btn.frame);
|
||||||
|
//
|
||||||
|
// CGFloat offsetX = 0;
|
||||||
|
// if (btnCenterX > scrollW / 2.0) {
|
||||||
|
// offsetX = btnCenterX - scrollW / 2.0;
|
||||||
|
// offsetX = MIN(offsetX, MAX(contentW - scrollW, 0));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// [_tabScrollView setContentOffset:CGPointMake(offsetX, 0) animated:YES];
|
||||||
|
//}
|
||||||
|
|
||||||
|
#pragma mark - DataList Setter
|
||||||
|
|
||||||
|
- (void)setDataList:(NSArray *)dataList {
|
||||||
|
_dataList = [dataList copy];
|
||||||
|
|
||||||
|
// 未登录:显示 emptyLabel,隐藏 emptyView 及内容区
|
||||||
|
if (![HQCommonUtils isLogin]) {
|
||||||
|
_emptyLabel.text = @" 暂未登录 ";
|
||||||
|
_emptyLabel.hidden = NO;
|
||||||
|
_emptyView.hidden = YES;
|
||||||
|
_collectionView.hidden = YES;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已登录:隐藏 emptyLabel,显示内容区
|
||||||
|
_emptyLabel.hidden = YES;
|
||||||
|
_collectionView.hidden = NO;
|
||||||
|
|
||||||
|
// 无设备数据:显示 emptyView(图标 + 提示 + 去绑定按钮)
|
||||||
|
BOOL isEmpty = (_dataList.count == 0);
|
||||||
|
_emptyView.hidden = !isEmpty;
|
||||||
|
|
||||||
|
[_collectionView reloadData];
|
||||||
|
|
||||||
|
// 有多条数据才启动轮播
|
||||||
|
if (_dataList.count > 1) {
|
||||||
|
[self p_startAutoScroll];
|
||||||
|
} else {
|
||||||
|
[self p_stopAutoScroll];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通知外部更新高度:无数据/未登录 104,有数据 205
|
||||||
|
BOOL needSmall = (isEmpty || ![HQCommonUtils isLogin]);
|
||||||
|
CGFloat newHeight = needSmall ? 104.0 : 200.0;
|
||||||
|
if (self.heightChangeBlock) {
|
||||||
|
self.heightChangeBlock(newHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UICollectionViewDataSource
|
||||||
|
|
||||||
|
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||||
|
return self.dataList.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
|
||||||
|
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
XJHomeWatchCollectionViewCell *cell =
|
||||||
|
[collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([XJHomeWatchCollectionViewCell class])
|
||||||
|
forIndexPath:indexPath];
|
||||||
|
// 用 dataList 里对应位置的 model 填充
|
||||||
|
if (indexPath.item < (NSInteger)_dataList.count) {
|
||||||
|
[cell configureWithData:_dataList[indexPath.item]];
|
||||||
|
}
|
||||||
|
// // item 下标即数据类型:0=心率 1=血氧 2=压力 3=体温
|
||||||
|
// [cell updateTabIndex:indexPath.item];
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UICollectionViewDelegateFlowLayout
|
||||||
|
|
||||||
|
- (CGSize)collectionView:(UICollectionView *)collectionView
|
||||||
|
layout:(UICollectionViewLayout *)collectionViewLayout
|
||||||
|
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
// cell 宽 = 整个 view 宽;cell 高 = collectionView 自身高度
|
||||||
|
return CGSizeMake(self.bounds.size.width, collectionView.bounds.size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UICollectionViewDelegate
|
||||||
|
|
||||||
|
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
// 预留:外部如需监听 cell 点击可在此通过 block 回调
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - UIScrollViewDelegate(手动滑动同步 Tab)
|
||||||
|
|
||||||
|
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
|
||||||
|
if (scrollView != _collectionView) return;
|
||||||
|
// 更新轮播页码(与 Tab selectedIndex 无关)
|
||||||
|
_carouselPage = (NSInteger)(scrollView.contentOffset.x / MAX(scrollView.bounds.size.width, 1));
|
||||||
|
[self p_restartAutoScroll];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
|
||||||
|
if (scrollView != _collectionView) return;
|
||||||
|
// 手指触碰时暂停自动轮播,避免与手势冲突
|
||||||
|
[self p_stopAutoScroll];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - 轮播
|
||||||
|
|
||||||
|
/// 启动自动轮播(3 秒一次)
|
||||||
|
- (void)p_startAutoScroll {
|
||||||
|
[self p_stopAutoScroll];
|
||||||
|
if (_dataList.count <= 1) return;
|
||||||
|
_autoScrollTimer = [NSTimer scheduledTimerWithTimeInterval:5.0
|
||||||
|
target:self
|
||||||
|
selector:@selector(p_autoScrollToNext)
|
||||||
|
userInfo:nil
|
||||||
|
repeats:YES];
|
||||||
|
// 加入 NSRunLoopCommonModes,防止父 ScrollView 滚动时定时器暂停
|
||||||
|
[[NSRunLoop mainRunLoop] addTimer:_autoScrollTimer forMode:NSRunLoopCommonModes];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 停止自动轮播
|
||||||
|
- (void)p_stopAutoScroll {
|
||||||
|
[_autoScrollTimer invalidate];
|
||||||
|
_autoScrollTimer = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 重置定时器(用户交互后调用)
|
||||||
|
- (void)p_restartAutoScroll {
|
||||||
|
if (_dataList.count > 1) [self p_startAutoScroll];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 滚到下一页,最后一页→第一页不用动画,避免明显跳动
|
||||||
|
- (void)p_autoScrollToNext {
|
||||||
|
if (_dataList.count == 0) return;
|
||||||
|
NSInteger next = (_carouselPage + 1) % _dataList.count;
|
||||||
|
BOOL animated = (next != 0);
|
||||||
|
[self p_scrollCollectionToIndex:next animated:animated];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 滚动 collectionView 到指定页,只更新 carouselPage,不影响 Tab
|
||||||
|
- (void)p_scrollCollectionToIndex:(NSInteger)index animated:(BOOL)animated {
|
||||||
|
if (index < 0 || index >= (NSInteger)_dataList.count) return;
|
||||||
|
_carouselPage = index;
|
||||||
|
NSIndexPath *ip = [NSIndexPath indexPathForItem:index inSection:0];
|
||||||
|
[_collectionView scrollToItemAtIndexPath:ip
|
||||||
|
atScrollPosition:UICollectionViewScrollPositionLeft
|
||||||
|
animated:animated];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 离开父视图时停止轮播,防止 timer 持有 self 造成内存泄漏
|
||||||
|
- (void)willMoveToSuperview:(UIView *)newSuperview {
|
||||||
|
[super willMoveToSuperview:newSuperview];
|
||||||
|
if (!newSuperview) [self p_stopAutoScroll];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - 上一日/上一周、下一日/下一周
|
||||||
|
|
||||||
|
// 上一日/上一周
|
||||||
|
- (void)previousWeekAction {
|
||||||
|
|
||||||
|
self.currentDayDate = [self dateByAddingDays:-1 toDate:self.currentDayDate];
|
||||||
|
[self updateWeekLabelWithType];
|
||||||
|
[self checkNextButtonState];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下一日/下一周
|
||||||
|
- (void)nextWeekAction {
|
||||||
|
self.currentDayDate = [self dateByAddingDays:1 toDate:self.currentDayDate];
|
||||||
|
[self updateWeekLabelWithType];
|
||||||
|
[self checkNextButtonState];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateWeekLabelWithType {
|
||||||
|
|
||||||
|
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||||||
|
formatter.dateFormat = @"yyyy-MM-dd";
|
||||||
|
self.weekLabel.text = [formatter stringFromDate:self.currentDayDate];
|
||||||
|
|
||||||
|
if (self.changeTimeClickBlock) {
|
||||||
|
NSString *dayYMD = [self formatDateToYMDString:self.currentDayDate];
|
||||||
|
self.changeTimeClickBlock(dayYMD); //
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 日期加减
|
||||||
|
- (NSDate *)dateByAddingDays:(NSInteger)days toDate:(NSDate *)date {
|
||||||
|
return [date dateByAddingTimeInterval:days*24*60*60];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)formatDateToYMDString:(NSDate *)date {
|
||||||
|
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||||||
|
[formatter setDateFormat:@"yyyy-MM-dd"];
|
||||||
|
return [formatter stringFromDate:date];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - 检查下一天/下一周按钮状态
|
||||||
|
|
||||||
|
- (void)checkNextButtonState {
|
||||||
|
NSCalendar *calendar = [NSCalendar currentCalendar];
|
||||||
|
[calendar setFirstWeekday:2]; // 周一为第一天
|
||||||
|
|
||||||
|
NSDate *today = [NSDate date];
|
||||||
|
|
||||||
|
NSDate *currentOnly = [self dateByRemovingTime:self.currentDayDate];
|
||||||
|
NSDate *todayOnly = [self dateByRemovingTime:today];
|
||||||
|
self.nextBtn.enabled = ([currentOnly compare:todayOnly] == NSOrderedAscending);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 去掉时分秒
|
||||||
|
- (NSDate *)dateByRemovingTime:(NSDate *)date {
|
||||||
|
NSCalendar *calendar = [NSCalendar currentCalendar];
|
||||||
|
NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay
|
||||||
|
fromDate:date];
|
||||||
|
return [calendar dateFromComponents:components];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// MessageListViewController.h
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/5.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "XJBaseViewController.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface MessageListViewController : XJBaseViewController
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// MessageListViewController.m
|
||||||
|
// XinjiangProject
|
||||||
|
//
|
||||||
|
// Created by Apple on 2026/2/5.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MessageListViewController.h"
|
||||||
|
|
||||||
|
@interface MessageListViewController ()
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MessageListViewController
|
||||||
|
|
||||||
|
- (void)viewDidLoad {
|
||||||
|
[super viewDidLoad];
|
||||||
|
// Do any additional setup after loading the view.
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#pragma mark - Navigation
|
||||||
|
|
||||||
|
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||||
|
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||||
|
// Get the new view controller using [segue destinationViewController].
|
||||||
|
// Pass the selected object to the new view controller.
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
@end
|
||||||
+40
-6
@@ -176,17 +176,21 @@
|
|||||||
|
|
||||||
//1月21日新需求
|
//1月21日新需求
|
||||||
|
|
||||||
self.topLoginTitleLab = [[UILabel alloc] initWithFrame:CGRectMake(0, kRealValue(40), kScreenWidth, 20)];;
|
self.topLoginTitleLab = [[UILabel alloc] init];;
|
||||||
self.topLoginTitleLab.text = @"平台统一认证";
|
self.topLoginTitleLab.text = @"平台统一认证";
|
||||||
self.topLoginTitleLab.font = [UIFont systemFontOfSize:20 weight:UIFontWeightBold];
|
self.topLoginTitleLab.font = [UIFont systemFontOfSize:20 weight:UIFontWeightBold];
|
||||||
self.topLoginTitleLab.textColor = UIColorHex(#2EB8B2);
|
self.topLoginTitleLab.textColor = UIColorHex(#2EB8B2);
|
||||||
self.topLoginTitleLab.textAlignment = NSTextAlignmentCenter;
|
self.topLoginTitleLab.textAlignment = NSTextAlignmentCenter;
|
||||||
[self.loginView addSubview:self.topLoginTitleLab];
|
[self.loginView addSubview:self.topLoginTitleLab];
|
||||||
|
|
||||||
|
[self.topLoginTitleLab mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.right.mas_offset(0);
|
||||||
|
make.top.mas_offset(40);
|
||||||
|
make.height.mas_offset(kRealValue(40));
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
UITextField *accountField = [[UITextField alloc]init];
|
UITextField *accountField = [[UITextField alloc]init];
|
||||||
accountField.frame = CGRectMake(kRealValue(25),self.topLoginTitleLab.bottom + kRealValue(24), loginView.width - kRealValue(50), 48);
|
|
||||||
accountField.placeholder = @"请输入员工编号或用户名";
|
accountField.placeholder = @"请输入员工编号或用户名";
|
||||||
accountField.font = BOLDSYSTEMFONT(14);
|
accountField.font = BOLDSYSTEMFONT(14);
|
||||||
accountField.textColor = CFontColor1;
|
accountField.textColor = CFontColor1;
|
||||||
@@ -203,9 +207,17 @@
|
|||||||
self.userNameField.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
self.userNameField.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||||
[loginView addSubview:accountField ];
|
[loginView addSubview:accountField ];
|
||||||
//
|
//
|
||||||
|
|
||||||
|
[self.userNameField mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(25);
|
||||||
|
make.right.mas_offset(-25);
|
||||||
|
make.height.mas_offset(48);
|
||||||
|
make.top.mas_equalTo(self.topLoginTitleLab.mas_bottom).offset(kRealValue(24));
|
||||||
|
}];
|
||||||
|
|
||||||
//
|
//
|
||||||
MQTextField * passwordField = [[MQTextField alloc]init];
|
MQTextField * passwordField = [[MQTextField alloc]init];
|
||||||
passwordField.frame = CGRectMake(kRealValue(25), accountField.bottom + kRealValue(19), accountField.width, accountField.height);
|
// passwordField.frame = CGRectMake(kRealValue(25), accountField.bottom + kRealValue(19), accountField.width, accountField.height);
|
||||||
passwordField.placeholder = @"请输入密码";
|
passwordField.placeholder = @"请输入密码";
|
||||||
passwordField.font = BOLDSYSTEMFONT(14);
|
passwordField.font = BOLDSYSTEMFONT(14);
|
||||||
passwordField.textColor = CFontColor1;
|
passwordField.textColor = CFontColor1;
|
||||||
@@ -239,10 +251,16 @@
|
|||||||
[loginView addSubview:passwordField];
|
[loginView addSubview:passwordField];
|
||||||
|
|
||||||
|
|
||||||
|
[self.passwordField mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(25);
|
||||||
|
make.right.mas_offset(-25);
|
||||||
|
make.height.mas_offset(48);
|
||||||
|
make.top.mas_equalTo(self.userNameField.mas_bottom).offset(kRealValue(19));
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
UIButton *loginBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
UIButton *loginBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
loginBtn.frame = CGRectMake(kRealValue(25), self.passwordField.bottom + kRealValue(20), WIDTH - kRealValue(50), 48);
|
// loginBtn.frame = CGRectMake(kRealValue(25), self.passwordField.bottom + kRealValue(20), WIDTH - kRealValue(50), 48);
|
||||||
[loginBtn setTitle:@"登录" forState:UIControlStateNormal];
|
[loginBtn setTitle:@"登录" forState:UIControlStateNormal];
|
||||||
[loginBtn.titleLabel setFont:BOLDSYSTEMFONT(16)];
|
[loginBtn.titleLabel setFont:BOLDSYSTEMFONT(16)];
|
||||||
loginBtn.backgroundColor = UIColorHex(#2EB8B2);
|
loginBtn.backgroundColor = UIColorHex(#2EB8B2);
|
||||||
@@ -252,8 +270,18 @@
|
|||||||
[loginBtn addTarget:self action:@selector(toClickFootBtn:) forControlEvents:UIControlEventTouchUpInside];
|
[loginBtn addTarget:self action:@selector(toClickFootBtn:) forControlEvents:UIControlEventTouchUpInside];
|
||||||
[loginView addSubview:loginBtn];
|
[loginView addSubview:loginBtn];
|
||||||
|
|
||||||
|
[loginBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.mas_offset(kRealValue(25));
|
||||||
|
make.right.mas_offset(-kRealValue(25));
|
||||||
|
make.height.mas_offset(48);
|
||||||
|
make.top.mas_equalTo(self.passwordField.mas_bottom).offset(kRealValue(20));
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
UIButton * foundPasswordBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
UIButton * foundPasswordBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
foundPasswordBtn.frame = CGRectMake(loginBtn.right - 52, loginBtn.bottom + kRealValue(22), 52, 12);
|
// foundPasswordBtn.frame = CGRectMake(loginBtn.right - 60, loginBtn.bottom + kRealValue(22), 60, 12);
|
||||||
[foundPasswordBtn setTitle:@"找回密码" forState:UIControlStateNormal];
|
[foundPasswordBtn setTitle:@"找回密码" forState:UIControlStateNormal];
|
||||||
foundPasswordBtn.titleLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightRegular];
|
foundPasswordBtn.titleLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightRegular];
|
||||||
[foundPasswordBtn setTitleColor:UIColorHex(#B6B6B6) forState:UIControlStateNormal];
|
[foundPasswordBtn setTitleColor:UIColorHex(#B6B6B6) forState:UIControlStateNormal];
|
||||||
@@ -262,6 +290,12 @@
|
|||||||
[loginView addSubview:foundPasswordBtn];
|
[loginView addSubview:foundPasswordBtn];
|
||||||
|
|
||||||
|
|
||||||
|
[foundPasswordBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.mas_equalTo(loginBtn.mas_right);
|
||||||
|
make.height.mas_offset(kRealValue(20));
|
||||||
|
make.top.mas_equalTo(loginBtn.mas_bottom).offset(18);
|
||||||
|
}];
|
||||||
|
|
||||||
[[NSUserDefaults standardUserDefaults] setObject:@"1" forKey:@"LOGINAgree"];
|
[[NSUserDefaults standardUserDefaults] setObject:@"1" forKey:@"LOGINAgree"];
|
||||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||||
|
|
||||||
@@ -283,7 +317,7 @@
|
|||||||
{
|
{
|
||||||
self.agreenBtn.selected = false;
|
self.agreenBtn.selected = false;
|
||||||
}
|
}
|
||||||
[self.view addSubview:self.agreenBtn];
|
[self.loginView addSubview:self.agreenBtn];
|
||||||
|
|
||||||
[self.agreenBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
[self.agreenBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
make.left.mas_offset(25);
|
make.left.mas_offset(25);
|
||||||
|
|||||||
+1
-1
@@ -189,7 +189,7 @@
|
|||||||
{
|
{
|
||||||
[EasyTextView showErrorText:message];
|
[EasyTextView showErrorText:message];
|
||||||
|
|
||||||
NSLog(@"apiError=%@",message);
|
DLog(@"apiError=%@",message);
|
||||||
// [self showMessage:message];
|
// [self showMessage:message];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user