RAOfflineHandler.m 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. //
  2. // RAOfflineHandler.m
  3. // Apex And Drivers
  4. //
  5. // Created by Jack on 2018/10/22.
  6. // Copyright © 2018年 USAI. All rights reserved.
  7. //
  8. #import "RAOfflineHandler.h"
  9. #import "NetworkUtils.h"
  10. #import "ZipArchive.h"
  11. #import "RADetailBaseModel.h"
  12. #import "RAHomeOrderModel.h"
  13. #import "RADetailActionModel.h"
  14. #import "AppDelegate.h"
  15. #import "RAEditImageBaseModel.h"
  16. #define Lock() dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER)
  17. #define Unlock() dispatch_semaphore_signal(_lock)
  18. static dispatch_semaphore_t _lock;
  19. @interface RAOfflineHandler () {
  20. NSString *_offlineDir;
  21. NSString *_offlineTmp;
  22. NSString *_offlineUploadDir;
  23. NSString *_zipPassword;
  24. }
  25. @property (nonatomic,strong) NSMutableDictionary *detailCache;///< 缓存查看过的Detai
  26. @property (nonatomic,strong,readonly) NSString *offlineDir; ///< 缓存文件夹
  27. @property (nonatomic,strong,readonly) NSString *offlineTmp; ///< 临时保存解压文件的文件夹
  28. @property (nonatomic,strong,readonly) NSString *offlineUploadDir; ///<上传文件目录
  29. @property (nonatomic,copy,readonly) NSString *zipPassword; ///<压缩/解压 密码
  30. @end
  31. @implementation RAOfflineHandler
  32. #pragma mark - Handler
  33. + (instancetype)defaultHandler {
  34. static RAOfflineHandler *handler;
  35. static dispatch_once_t token;
  36. dispatch_once(&token, ^{
  37. handler = [[RAOfflineHandler alloc] init];
  38. _lock = dispatch_semaphore_create(1);
  39. });
  40. return handler;
  41. }
  42. - (void)prepareParams:(NSMutableDictionary* )params {
  43. NSAssert(params != nil, @"params can't be nil");
  44. NSString *user = RASingleton.sharedInstance.encryptUser;
  45. NSString *password = RASingleton.sharedInstance.encryptPassword;
  46. if (user.length && password.length) {
  47. [params setObject:user forKey:@"name"];
  48. [params setObject:password forKey:@"password"];
  49. }
  50. [params setObject:@"iOS" forKey:@"platform"];
  51. NSDictionary* infoDict =[[NSBundle mainBundle] infoDictionary];
  52. NSString* short_version =[infoDict objectForKey:@"CFBundleShortVersionString"];
  53. [params setValue:short_version forKey:@"app_short_ver"];
  54. NSString *localeLanguageCode = [[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode];
  55. [params setValue:localeLanguageCode forKey:@"language"];
  56. NSString *time = [self currentDate];
  57. [params setObject:time forKey:@"date"];
  58. [params setObject:@(1) forKey:@"offline"];
  59. #if TARGET_IPHONE_SIMULATOR//模拟器
  60. [params setValue:@"simulator_uuid" forKey:@"deviceid"];
  61. #elif TARGET_OS_IPHONE//真机
  62. UIDevice * dev = [UIDevice currentDevice];
  63. NSUUID* uuid =dev.identifierForVendor;
  64. [params setValue:uuid.UUIDString forKey:@"deviceid"];
  65. #endif
  66. }
  67. - (NSString *)offlineDir {
  68. if (!_offlineDir) {
  69. NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
  70. _offlineDir = [cachePath stringByAppendingPathComponent:@"offline"];
  71. NSFileManager *fm = [NSFileManager defaultManager];
  72. BOOL isDir = YES;
  73. if ([fm fileExistsAtPath:_offlineDir isDirectory:&isDir] && isDir) {
  74. } else {
  75. [fm createDirectoryAtPath:_offlineDir withIntermediateDirectories:NO attributes:nil error:nil];
  76. }
  77. }
  78. return _offlineDir;
  79. }
  80. - (NSString *)offlineTmp {
  81. if (!_offlineTmp) {
  82. _offlineTmp = [self.offlineDir stringByAppendingPathComponent:@"tmp"];
  83. NSFileManager *fm = [NSFileManager defaultManager];
  84. BOOL isDir = YES;
  85. if ([fm fileExistsAtPath:_offlineTmp isDirectory:&isDir] && isDir) {
  86. } else {
  87. [fm createDirectoryAtPath:_offlineTmp withIntermediateDirectories:YES attributes:nil error:nil];
  88. }
  89. }
  90. return _offlineTmp;
  91. }
  92. - (NSString *)offlineUploadDir {
  93. if (!_offlineUploadDir) {
  94. _offlineUploadDir = [self.offlineDir stringByAppendingPathComponent:@"upload"];
  95. NSFileManager *fm = [NSFileManager defaultManager];
  96. BOOL isDir = YES;
  97. if ([fm fileExistsAtPath:_offlineUploadDir isDirectory:&isDir] && isDir) {
  98. } else {
  99. [fm createDirectoryAtPath:_offlineUploadDir withIntermediateDirectories:YES attributes:nil error:nil];
  100. }
  101. }
  102. return _offlineUploadDir;
  103. }
  104. - (NSString *)zipPassword {
  105. if (!_zipPassword) {
  106. _zipPassword = @"usai";
  107. }
  108. return _zipPassword;
  109. }
  110. #pragma mark - Download
  111. /**
  112. * @brief 向服务器请求离线数据
  113. */
  114. - (void)downloadOfflineData {
  115. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  116. NSMutableDictionary *params = [NSMutableDictionary dictionary];
  117. [self prepareParams:params];
  118. [NetworkUtils downloadFileOffset:0 Param:params from:@"" method:@"POST" toPath:self.offlineDir progressHandler:^(NSURLSessionTask *task, double progress) {
  119. } completionHandler:^(NSMutableDictionary *result) {
  120. int rs = [[result objectForKey:@"result"] intValue];
  121. NSString *path = [result objectForKey:@"path"];
  122. if (rs == RESULT_TRUE) {
  123. [self handleDownloadFile:path];
  124. }
  125. }];
  126. });
  127. }
  128. /**
  129. * @brief 加载沙盒中的数据
  130. * @param path 沙盒数据路径
  131. */
  132. - (NSDictionary *)_loadCacheData:(NSString *)path {
  133. if (path == nil || path.length == 0) {
  134. return nil;
  135. }
  136. NSData *data = [NSData dataWithContentsOfFile:path];
  137. if (data) {
  138. NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
  139. return dic;
  140. }
  141. return nil;
  142. }
  143. /**
  144. * @brief 处理下载的压缩文件
  145. * @param path 压缩文件路径
  146. */
  147. - (void)handleDownloadFile:(NSString *)path {
  148. Lock();
  149. // 解压
  150. BOOL zipRes = [self _unzipOfflineZip:path toDir:self.offlineTmp];
  151. if (zipRes) {
  152. NSFileManager *fm = [NSFileManager defaultManager];
  153. // 删除旧数据,除了tmp
  154. NSArray<NSString *> *items = [fm contentsOfDirectoryAtPath:self.offlineDir error:nil];
  155. [items enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  156. if (![obj isEqualToString:self.offlineTmp] || ![obj.lastPathComponent isEqualToString:@"finish"] || ![obj isEqualToString:self.offlineUploadDir]) {
  157. [fm removeItemAtPath:obj error:nil];
  158. }
  159. }];
  160. // 将tmp中解压数据移出来
  161. items = [fm contentsOfDirectoryAtPath:self.offlineTmp error:nil];
  162. [items enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  163. NSString *lastComponent = [obj lastPathComponent];
  164. NSString *to = [self.offlineDir stringByAppendingPathComponent:lastComponent];
  165. [fm moveItemAtPath:obj toPath:to error:nil];
  166. }];
  167. // 重置缓存的action
  168. [self _resetFinish];
  169. }
  170. Unlock();
  171. }
  172. /**
  173. * @brief 重置离线完成的Action,将finished order对应的action的剔除
  174. */
  175. - (void)_resetFinish {
  176. NSDictionary *homeJson = [self _requestOfflineHome];
  177. NSArray<NSDictionary *> *sections = [homeJson objectForKey:@"sections"];
  178. NSMutableDictionary *finishDic = [NSMutableDictionary dictionary];
  179. NSDictionary *finishDicTmp = [self _finishedActions];
  180. if (finishDicTmp.count > 0) {
  181. [sections enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  182. NSArray<NSDictionary *> *orders = [obj objectForKey:@"orders"];
  183. [orders enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull order, NSUInteger idx, BOOL * _Nonnull stop) {
  184. NSString *orderId = [order objectForKey:@"orderID"];
  185. NSNumber *finish = [finishDicTmp objectForKey:orderId];
  186. if (finish) {
  187. [finishDic setObject:finish forKey:orderId];
  188. }
  189. }];
  190. }];
  191. }
  192. NSString *finishPath = [self.offlineDir stringByAppendingPathComponent:@"finish"];
  193. [finishDic writeToFile:finishPath atomically:NO];
  194. }
  195. #pragma mark - Request Data
  196. /**
  197. * @brief 加载离线首页数据
  198. */
  199. - (NSDictionary *)_requestOfflineHome {
  200. NSString *homeJsonPath = [self.offlineDir stringByAppendingPathComponent:@"home.json"];
  201. NSDictionary *result = [self _loadCacheData:homeJsonPath];
  202. return result;
  203. }
  204. /**
  205. * @brief 加载离线首页数据
  206. */
  207. - (NSDictionary *)requestOfflineHome {
  208. Lock();
  209. NSDictionary *result = [self _requestOfflineHome];
  210. Unlock();
  211. return result;
  212. }
  213. /**
  214. * @brief 加载离线Detail
  215. * @param orderId 订单号
  216. * @param type 订单类型,包括 new order 和 processing order
  217. */
  218. - (NSDictionary *)requestOfflineDetailForOrder:(NSString *)orderId withOrderType:(NSInteger)type {
  219. Lock();
  220. NSString *detailJsonPath = [self.offlineDir stringByAppendingPathComponent:[NSString stringWithFormat:@"detail/%@_%ld",orderId,(long)type]];
  221. NSMutableDictionary *detailJson = [[self _loadCacheData:detailJsonPath] mutableCopy];
  222. NSNumber *finish = [self _lastActionIndexForOrder:orderId];
  223. detailJson = [self filtrateActionFromDetail:detailJson withFinishActions:finish];
  224. Unlock();
  225. return detailJson;
  226. }
  227. /**
  228. * @brief 记载离线Edit Order
  229. * @param orderId 订单号
  230. * @param actionIndex 操作标记
  231. */
  232. - (NSDictionary *)requestOfflineEditOrder:(NSString *)orderId withAction:(NSInteger)actionIndex {
  233. Lock();
  234. NSString *editJsonPath = [self.offlineDir stringByAppendingPathComponent:[NSString stringWithFormat:@"edit/%@_%ld",orderId,(long)actionIndex]];
  235. NSDictionary *editJson = [self _loadCacheData:editJsonPath];
  236. Unlock();
  237. return editJson;
  238. }
  239. #pragma mark - Utils
  240. /**
  241. * @brief 解压离线下载的压缩包
  242. * @return 解压是否成功
  243. */
  244. - (BOOL)_unzipOfflineZip:(NSString *)path toDir:(NSString *)to {
  245. ZipArchive *zip = [[ZipArchive alloc] init];
  246. BOOL zipRes = [zip UnzipOpenFile:path Password:self.zipPassword];
  247. if (zipRes) {
  248. zipRes = [zip UnzipFileTo:to overWrite:YES];
  249. }
  250. [zip UnzipCloseFile];
  251. return zipRes;
  252. }
  253. /**
  254. * @brief 压缩文件夹
  255. * @param dir 被压缩文件夹
  256. * @return 压缩文件路径
  257. */
  258. - (NSString *)_zipDir:(NSString *)dir {
  259. NSString *name = [[dir lastPathComponent] stringByAppendingString:@".zip"];
  260. NSString *zipFile = [[dir stringByDeletingLastPathComponent] stringByAppendingPathComponent:name];
  261. ZipArchive *zip = [[ZipArchive alloc] init];
  262. [zip CreateZipFile2:zipFile Password:self.zipPassword];
  263. NSFileManager *fm = [NSFileManager defaultManager];
  264. NSArray *list = [fm contentsOfDirectoryAtPath:dir error:nil];
  265. for (NSString *imgPath in list) {
  266. [zip addFileToZip:imgPath newname:imgPath.lastPathComponent];
  267. }
  268. [zip CloseZipFile2];
  269. return zipFile;
  270. }
  271. /**
  272. * @brief 在detail中过滤订单已经做过的操作
  273. * @param detail order detail界面数据
  274. * @param finish order最后完成的一个action索引
  275. */
  276. - (NSMutableDictionary *)filtrateActionFromDetail:(NSMutableDictionary *)detail withFinishActions:(NSNumber *)finish {
  277. if (finish == nil) {
  278. return detail;
  279. }
  280. int result = [[detail objectForKey:@"result"] intValue];
  281. if (result != RESULT_TRUE) {
  282. return detail;
  283. }
  284. // 一层层解开,获取到目标值后作出修改,然后反向一层层的套回去
  285. NSMutableArray<NSDictionary *> *sections = [[detail objectForKey:@"sections"] mutableCopy];
  286. [sections enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  287. NSMutableDictionary *section = [obj mutableCopy];
  288. NSMutableArray<NSDictionary *> *values = [[section objectForKey:@"values"] mutableCopy];
  289. [values enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  290. int type = [[obj objectForKey:@"type"] intValue];
  291. if (type == RAOrderDetailValueTypeAction) {
  292. NSMutableDictionary *mObj = [obj mutableCopy];
  293. NSMutableArray<NSDictionary *> *actions = [[mObj objectForKey:@"actions"] mutableCopy];
  294. NSMutableArray *rmArr = [NSMutableArray array];
  295. [actions enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  296. NSInteger index = [[obj objectForKey:@"index"] integerValue];
  297. if ([finish integerValue] >= index) {
  298. [rmArr addObject:obj];
  299. }
  300. }];
  301. [actions removeObjectsInArray:rmArr];
  302. [mObj setObject:actions forKey:@"actions"];
  303. [values replaceObjectAtIndex:idx withObject:mObj];
  304. }
  305. }];
  306. [section setObject:values forKey:@"values"];
  307. [sections replaceObjectAtIndex:idx withObject:section];
  308. }];
  309. [detail setObject:sections forKey:@"sections"];
  310. return detail;
  311. }
  312. /**
  313. * @brief 判断Order Action是否是最后一步
  314. * @param orderId 订单号
  315. * @return YES/NO
  316. */
  317. - (BOOL)isLastActionForOrder:(NSString *)orderId {
  318. if (!orderId) {
  319. return NO;
  320. }
  321. NSDictionary *detail = [self requestOfflineDetailForOrder:orderId withOrderType:RAOrderStatusProcessing];
  322. int result = [[detail objectForKey:@"result"] intValue];
  323. if (result != RESULT_TRUE) {
  324. return NO;
  325. }
  326. __block BOOL isLast = NO;
  327. NSMutableArray<NSDictionary *> *sections = [[detail objectForKey:@"sections"] mutableCopy];
  328. [sections enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  329. NSMutableDictionary *section = [obj mutableCopy];
  330. NSMutableArray<NSDictionary *> *values = [[section objectForKey:@"values"] mutableCopy];
  331. __block BOOL findAction = NO;
  332. [values enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  333. int type = [[obj objectForKey:@"type"] intValue];
  334. if (type == RAOrderDetailValueTypeAction) {
  335. findAction = YES;
  336. NSMutableDictionary *mObj = [obj mutableCopy];
  337. NSMutableArray<NSDictionary *> *actions = [[mObj objectForKey:@"actions"] mutableCopy];
  338. if (actions.count == 1) {
  339. isLast = YES;
  340. }
  341. *stop = YES;
  342. }
  343. }];
  344. if (findAction) {
  345. *stop = YES;
  346. }
  347. }];
  348. return isLast;
  349. }
  350. /**
  351. * @brief 加载所有完成的订单Action
  352. */
  353. - (NSDictionary<NSString *, NSNumber *> *)_finishedActions {
  354. NSString *path = [self.offlineDir stringByAppendingPathComponent:@"finish"];
  355. NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:path];
  356. if (dic == nil) {
  357. dic = [NSDictionary dictionary];
  358. }
  359. return dic;
  360. }
  361. /**
  362. * @brief 最后一次修改Order的 Action 索引
  363. * @param orderId 订单号
  364. */
  365. - (NSNumber *)_lastActionIndexForOrder:(NSString *)orderId {
  366. NSDictionary *finishDic = [self _finishedActions];
  367. NSNumber *finish = [finishDic objectForKey:orderId];
  368. return finish;
  369. }
  370. /**
  371. * @brief 最后一次修改Order的 Action 索引
  372. * @param orderId 订单号
  373. */
  374. - (NSNumber *)lastActionIndexForOrder:(NSString *)orderId {
  375. Lock();
  376. NSDictionary *finishDic = [self _finishedActions];
  377. NSNumber *finish = [finishDic objectForKey:orderId];
  378. Unlock();
  379. return finish;
  380. }
  381. /**
  382. * @brief 删除文件
  383. * @param path 待删除文件路径
  384. */
  385. - (void)deleteFileAtPath:(NSString *)path {
  386. Lock();
  387. NSFileManager *fm = [NSFileManager defaultManager];
  388. if([fm fileExistsAtPath:path]) {
  389. [fm removeItemAtPath:path error:nil];
  390. }
  391. Unlock();
  392. }
  393. /**
  394. * @brief 将字典以Json格式写入文件
  395. * @param json 待写入字典数据
  396. * @param path 写入文件路径
  397. */
  398. - (void)_writeJson:(NSDictionary *)json toPath:(NSString *)path {
  399. NSData *data = [NSJSONSerialization dataWithJSONObject:json options:NSJSONWritingPrettyPrinted error:nil];
  400. [data writeToFile:path atomically:NO];
  401. }
  402. /**
  403. * @brief 将字典以Json格式写入文件
  404. * @param json 待写入字典数据
  405. * @param path 写入文件路径
  406. */
  407. - (void)writeJson:(NSDictionary *)json toPath:(NSString *)path {
  408. Lock();
  409. [self _writeJson:json toPath:path];
  410. Unlock();
  411. }
  412. /**
  413. * @brief 当前时间字符串,格式 MM/DD/YYYY HH:mm
  414. */
  415. - (NSString *)currentDate {
  416. NSDate *date = [NSDate date];
  417. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  418. formatter.dateFormat = @"MM/DD/YYYY HH:mm";
  419. return [formatter stringFromDate:date];
  420. }
  421. #pragma mark - Update Data
  422. /**
  423. * @brief 更新离线缓存Home数据
  424. * @param homeJson 新的Home数据
  425. */
  426. - (void)updateHome:(NSDictionary *)homeJson {
  427. NSString *homeJsonPath = [self.offlineDir stringByAppendingPathComponent:@"home.json"];
  428. [self writeJson:homeJson toPath:homeJsonPath];
  429. }
  430. /**
  431. * @brief 更新order最后一次操作标记
  432. * @param actionIdx 操作索引
  433. * @param orderId 订单号
  434. */
  435. - (void)updateLastAction:(NSInteger)actionIdx forOrder:(NSString *)orderId {
  436. if (!orderId) {
  437. return;
  438. }
  439. Lock();
  440. NSMutableDictionary<NSString *, NSNumber *> *finishDic = [[self _finishedActions] mutableCopy];
  441. Unlock();
  442. [finishDic setObject:@(actionIdx) forKey:orderId];
  443. NSString *path = [self.offlineDir stringByAppendingPathComponent:@"finish"];
  444. [self writeJson:finishDic toPath:path];
  445. }
  446. /**
  447. * @brief 删除order操作对应的json文件
  448. * @param orderId 订单号
  449. * @param actionIdx 操作索引
  450. */
  451. - (void)deleteEditJsonFileForOrder:(NSString *)orderId withActionIndex:(NSInteger)actionIdx {
  452. NSString *editJsonPath = [self.offlineDir stringByAppendingPathComponent:[NSString stringWithFormat:@"edit/%@_%ld",orderId,(long)actionIdx]];
  453. [self deleteFileAtPath:editJsonPath];
  454. }
  455. /**
  456. * @brief 离线提交Detail Remote Action
  457. * @param orderId 订单号
  458. * @param type 订单类型 RAOrderStatus, New Order / Processing Order
  459. * @param action 操作类型 RADetailActionSubType, Reject / Accept
  460. * @param actionIdx 操作索引
  461. * @param actionName 操作名称
  462. * @param url 操作提交目标地址
  463. * @param params 操作提交的参数
  464. * @return 成功/失败
  465. */
  466. - (NSDictionary *)reportOrder:(NSString *)orderId type:(NSInteger)type actionType:(NSInteger)action actionIndex:(NSInteger)actionIdx actionName:(NSString *)actionName withURL:(NSString *)url params:(NSDictionary *)params {
  467. // 组织参数
  468. NSString *time = [self currentDate];
  469. NSMutableDictionary *mParams = [params mutableCopy];
  470. [self prepareParams:mParams];
  471. NSMutableDictionary *task = [@{
  472. @"order" : orderId,
  473. @"action" : actionName,
  474. @"name" : actionName,
  475. @"time" : time,
  476. @"url" : url,
  477. @"noFile" : @YES,
  478. @"params" : params
  479. } mutableCopy];
  480. // @"file" : photoPath,
  481. // 提交参数给UploadManager
  482. AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
  483. [appDelegate.uploadManager addTask:task];
  484. // New Order
  485. if (type == RAOrderStatusNew) {
  486. // 加载Home
  487. NSMutableDictionary *home = [[self requestOfflineHome] mutableCopy];
  488. if (home != nil) {
  489. // 遍历order,查找当前order,并修改状态/移除
  490. // Accept 移动order到processing
  491. // Reject 删除Order及对应的detail、edit
  492. NSMutableArray<NSDictionary *> *sections = [[home objectForKey:@"sections"] mutableCopy];
  493. __block NSDictionary *curOrder = nil; // 当前order
  494. __block NSDictionary *rmSection = nil; // 若section下没有order,则移除section
  495. if (sections) {
  496. // 查找New Order
  497. for (int i = 0; i < sections.count; i++) {
  498. NSDictionary *section = [sections objectAtIndex:i];
  499. RAOrderStatus type = [[section objectForKey:@"type"] intValue];
  500. if (type == RAOrderStatusNew) {
  501. // 查找当前order
  502. NSMutableArray<NSDictionary *> *orders = [[section objectForKey:@"orders"] mutableCopy];
  503. [orders enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  504. NSString *orderID = [obj objectForKey:@"orderID"];
  505. if ([orderId isEqualToString:orderID]) {
  506. curOrder = obj;
  507. *stop = YES;
  508. }
  509. }];
  510. // 找到order并移除
  511. if (curOrder) {
  512. [orders removeObject:curOrder];
  513. // 移除过后如果orders为空,则移除section
  514. if (orders.count == 0) {
  515. rmSection = section;
  516. }
  517. else {
  518. // orders不为空,重新修改
  519. rmSection = nil;
  520. NSMutableDictionary *mSec = [section mutableCopy];
  521. [mSec setObject:orders forKey:@"orders"];
  522. [sections replaceObjectAtIndex:i withObject:mSec];
  523. }
  524. }
  525. // 删除Order 操作对应Edit文件
  526. [self deleteEditJsonFileForOrder:orderId withActionIndex:actionIdx];
  527. break;
  528. }
  529. }
  530. if (rmSection) {
  531. [sections removeObject:rmSection];
  532. }
  533. // 如果是Accept则将order添加到Processing Order
  534. if (action == RADetailActionSubTypeAccept) {
  535. for (int i = 0; i < sections.count; i++) {
  536. NSMutableDictionary *section = [[sections objectAtIndex:i] mutableCopy];
  537. RAOrderStatus type = [[section objectForKey:@"type"] intValue];
  538. if (type == RAOrderStatusProcessing) {
  539. NSMutableArray<NSDictionary *> *orders = [[section objectForKey:@"orders"] mutableCopy];
  540. // 修改order状态为Processing
  541. [curOrder setValue:@(RAOrderStatusProcessing) forKey:@"status"];
  542. // 将当前order插入第一个位置
  543. [orders insertObject:curOrder atIndex:0];
  544. [section setObject:orders forKey:@"orders"];
  545. // 重新生成section
  546. [sections replaceObjectAtIndex:i withObject:section];
  547. break;
  548. }
  549. }
  550. }
  551. // 重新生成sections
  552. [home setObject:sections forKey:@"sections"];
  553. }
  554. // 更新Home文件
  555. [self updateHome:home];
  556. }
  557. }
  558. // 更新Action
  559. [self updateLastAction:actionIdx forOrder:orderId];
  560. return @{
  561. @"result" : @(RESULT_TRUE)
  562. };
  563. }
  564. /**
  565. * @brief 离线提交订单
  566. * @param orderId 订单号
  567. * @param actionId 操作ID,RADetailActionSubType
  568. * @param title 操作名称
  569. * @param idx 操作索引
  570. * @param params 订单填写的信息
  571. * @param photos 待上传的图片模型数组
  572. * @param dir 待上传的图片存储目录
  573. */
  574. - (NSDictionary *)updateOrder:(NSString *)orderId action:(NSInteger)actionId title:(NSString *)title index:(NSInteger)idx withParams:(NSDictionary *)params photos:(NSArray<RAEditImageBaseModel *> *)photos cacheDir:(NSString *)dir {
  575. Lock();
  576. NSFileManager *fm = [NSFileManager defaultManager];
  577. // 生成上传目录
  578. NSString *upDir = [self.offlineUploadDir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_%ld",orderId,(long)idx]];
  579. [fm createDirectoryAtPath:upDir withIntermediateDirectories:NO attributes:nil error:nil];
  580. // 修改Params
  581. NSString *time = [self currentDate];
  582. NSMutableDictionary *mParams = [params mutableCopy];
  583. [self prepareParams:mParams];
  584. // // 将params写入目录
  585. // NSString *paramPath = [upDir stringByAppendingPathComponent:@"params.json"];
  586. // [self _writeJson:mParams toPath:paramPath];
  587. if (photos.count > 0) {
  588. // 生成图片目录
  589. NSString *imageDir = [upDir stringByAppendingPathComponent:@"images"];
  590. [fm createDirectoryAtPath:imageDir withIntermediateDirectories:NO attributes:nil error:nil];
  591. // 将图片移动到图片目录
  592. for (RAEditImageBaseModel *model in photos) {
  593. NSString *path = [dir stringByAppendingPathComponent:model.imageName];
  594. NSString *toPath = [imageDir stringByAppendingString:model.imageName];
  595. if ([fm fileExistsAtPath:path]) {
  596. NSError *err;
  597. BOOL move = [fm moveItemAtPath:path toPath:toPath error:&err];
  598. if (!move) {
  599. NSString *msg = @"Sorry,there is something error";
  600. if (err) {
  601. msg = err.localizedDescription;
  602. }
  603. Unlock();
  604. return @{
  605. @"result" : @(RESULT_FALSE),
  606. @"err_msg" : msg
  607. };
  608. }
  609. }
  610. }
  611. }
  612. // 压缩目录
  613. NSString *zip = [self _zipDir:upDir];
  614. // 删除目录
  615. [fm removeItemAtPath:upDir error:nil];
  616. Unlock();
  617. // 创建Task
  618. NSMutableDictionary *task = [@{
  619. @"order" : orderId,
  620. @"action" : title,
  621. @"name" : title,
  622. @"time" : time,
  623. @"url" : URL_UPLOAD,
  624. @"file" : zip,
  625. @"params" : mParams
  626. } mutableCopy];
  627. // 提交Task
  628. AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
  629. [appDelegate.uploadManager addTask:task];
  630. // 判断是否完成order 所有操作
  631. BOOL finish = [self isLastActionForOrder:orderId];
  632. if (finish) {
  633. // 将order从Processing中删除
  634. // 加载Home
  635. NSMutableDictionary *home = [[self requestOfflineHome] mutableCopy];
  636. if (home) {
  637. NSMutableArray<NSDictionary *> *sections = [[home objectForKey:@"sections"] mutableCopy];
  638. if (sections) {
  639. __block NSDictionary *rmSection = nil; // 若section下没有order,则移除section
  640. for (int i = 0; i < sections.count; i++) {
  641. NSMutableDictionary *section = [[sections objectAtIndex:i] mutableCopy];
  642. RAOrderStatus type = [[section objectForKey:@"type"] intValue];
  643. if (type == RAOrderStatusProcessing) {
  644. NSMutableArray<NSDictionary *> *orders = [[section objectForKey:@"orders"] mutableCopy];
  645. __block NSDictionary *curOrder = nil; // 当前order
  646. [orders enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  647. NSString *orderID = [obj objectForKey:@"orderID"];
  648. if ([orderId isEqualToString:orderID]) {
  649. curOrder = obj;
  650. *stop = YES;
  651. }
  652. }];
  653. [orders removeObject:curOrder];
  654. if (orders.count > 0) {
  655. [section setObject:orders forKey:@"orders"];
  656. // 重新生成section
  657. [sections replaceObjectAtIndex:i withObject:section];
  658. } else {
  659. rmSection = [sections objectAtIndex:i];
  660. }
  661. break;
  662. }
  663. }
  664. if (rmSection) {
  665. [sections removeObject:rmSection];
  666. }
  667. // 重新生成sections
  668. [home setObject:sections forKey:@"sections"];
  669. }
  670. // 更新Home文件
  671. [self updateHome:home];
  672. }
  673. }
  674. return @{
  675. @"result" : @(RESULT_TRUE),
  676. @"err_msg" : [NSString stringWithFormat:@"%@ %@ is submitted,you will find it in upload list.",title,orderId]
  677. };
  678. }
  679. @end