Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
weihan-plugin
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Wei Han
weihan-plugin
Commits
5ac78689
Commit
5ac78689
authored
Nov 04, 2025
by
Wei Han
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
code update
parent
e71683b7
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
501 additions
and
135 deletions
+501
-135
Info.plist
...PluginFramework/QmsPluginFramework.xcframework/Info.plist
+5
-5
QmsPluginFramework
...ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
QmsPluginFramework
...simulator/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
AddIssueAPIClient.h
...Framework/QmsPluginFramework/AddIssue/AddIssueAPIClient.h
+17
-7
AddIssueAPIClient.mm
...ramework/QmsPluginFramework/AddIssue/AddIssueAPIClient.mm
+112
-0
DetailsViewController.h
...ework/QmsPluginFramework/AddIssue/DetailsViewController.h
+4
-4
DetailsViewController.mm
...work/QmsPluginFramework/AddIssue/DetailsViewController.mm
+263
-79
PlanViewController.mm
...amework/QmsPluginFramework/AddIssue/PlanViewController.mm
+42
-28
IssueDetailViewController.mm
...ork/QmsPluginFramework/Issue/IssueDetailViewController.mm
+1
-1
WithdrawSingleIssueViewController.mm
...luginFramework/Issue/WithdrawSingleIssueViewController.mm
+52
-6
Info.plist
ios/QmsPluginFramework.xcframework/Info.plist
+5
-5
QmsPluginFramework
...ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
QmsPluginFramework
...simulator/QmsPluginFramework.framework/QmsPluginFramework
+0
-0
No files found.
framework/QmsPluginFramework/QmsPluginFramework.xcframework/Info.plist
View file @
5ac78689
...
...
@@ -8,32 +8,32 @@
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
string
>
ios-arm64
_x86_64-simulator
<
/string
>
<
string
>
ios-arm64
<
/string
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
d
i
c
t
>
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
string
>
ios-arm64
<
/string
>
<
string
>
ios-arm64
_x86_64-simulator
<
/string
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
/
a
rr
a
y
>
<
k
e
y
>
CFBundlePackageType
<
/k
e
y
>
...
...
framework/QmsPluginFramework/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
View file @
5ac78689
No preview for this file type
framework/QmsPluginFramework/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework
View file @
5ac78689
No preview for this file type
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/AddIssueAPIClient.h
View file @
5ac78689
...
...
@@ -2,14 +2,24 @@
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface
AddIssueAPIClient
:
NSObject
+
(
void
)
fetchGetUnitPlan
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
+
(
void
)
fetchSettingsByLocation
:(
NSString
*
)
locationID
projectID
:(
NSString
*
)
projectID
completion
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
+
(
void
)
submitAddIssue
:(
NSDictionary
*
)
params
images
:(
NSArray
<
UIImage
*>
*
)
images
completion
:(
void
(
^
)(
NSDictionary
*
data
,
NSError
*
error
))
completion
;
+
(
void
)
fetchGetUnitPlan
:(
void
(
^
)(
NSDictionary
*
_Nullable
data
,
NSError
*
_Nullable
error
))
completion
;
+
(
void
)
fetchSettingsByLocation
:(
NSString
*
_Nonnull
)
locationID
projectID
:(
NSString
*
_Nonnull
)
projectID
completion
:(
void
(
^
)(
NSDictionary
*
_Nullable
data
,
NSError
*
_Nullable
error
))
completion
;
+
(
void
)
submitAddIssue
:(
NSDictionary
*
_Nonnull
)
params
images
:(
NSArray
<
UIImage
*>
*
_Nullable
)
images
completion
:(
void
(
^
)(
NSDictionary
*
_Nullable
data
,
NSError
*
_Nullable
error
))
completion
;
+
(
void
)
submitUpdateIssue
:(
NSDictionary
*
_Nonnull
)
updateData
images
:(
NSArray
<
UIImage
*>
*
_Nullable
)
images
completion
:(
void
(
^
)(
NSDictionary
*
_Nullable
response
,
NSError
*
_Nullable
error
))
completion
;
@end
NS_ASSUME_NONNULL_END
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/AddIssueAPIClient.mm
View file @
5ac78689
...
...
@@ -271,4 +271,116 @@
}
+ (void)submitUpdateIssue:(NSDictionary *)updateData
images:(NSArray<UIImage *> * _Nullable)images
completion:(void (^)(NSDictionary * _Nullable response, NSError * _Nullable error))completion {
NSString *urlString = @"https://kitadev.commudesk.com/api/owner/issue/addIssue?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImF0aGlyYWh6YWlkaUBjb252ZXAuY29tIiwicGFzc3dvcmQiOiIkMnkkMTAkNU9xYklqMnZ6UHJwckJrcVd5c3I2LmJCc1hVYS9Hd014eUhnL3RhUUhPUkNQcGdmTG8yakciLCJzdWIiOjIxNzAsImlzcyI6Imh0dHBzOi8va2l0YWRldi5jb21tdWRlc2suY29tL2FwaS9vd25lci9hdXRoL3Bhc3N3b3JkbGVzc19sb2dpbiIsImlhdCI6MTc2MDMxNTM1MiwiZXhwIjoyMDc1ODg0ODcyLCJuYmYiOjE3NjAzMTUzNTIsImp0aSI6IktoQmNyQnJEdDVNdDZlWmMifQ.JnxGbZ7hTeoOr6oibIzZMphgyKtTo2Aq9Efx6mrGfFA"; NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
// 🧱 Multipart body setup
NSString *boundary = [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]];
[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]
forHTTPHeaderField:@"Content-Type"];
NSMutableData *body = [NSMutableData data];
// Helper for form fields
void (^appendFormField)(NSString *, NSString *) = ^(NSString *key, NSString *value) {
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:
@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@\r\n", value]
dataUsingEncoding:NSUTF8StringEncoding]];
};
// 🔹 Append update fields (all under data[])
for (NSString *key in updateData.allKeys) {
id value = updateData[key];
if ([value isKindOfClass:[NSNumber class]]) value = [(NSNumber *)value stringValue];
if ([value isKindOfClass:[NSString class]]) {
appendFormField([NSString stringWithFormat:@"data[%@]", key], value);
}
}
// 🔹 Always include OS
appendFormField(@"data[os]", @"AND");
// 🔹 Add `information` field (as JSON string)
NSDictionary *info = @{
@"os": @"AND",
@"drawing_plan_id": updateData[@"plan_id"] ?: @"",
@"information": @{
@"OS": @"AND",
@"IMEI": @"AND:2a2f13ff17b1cbb5",
@"OS_VERSION": @"35",
@"MODEL": @"2306EPN60G",
@"APP_VERSION": @"1.22.26"
}
};
NSError *jsonError;
NSData *infoData = [NSJSONSerialization dataWithJSONObject:info options:0 error:&jsonError];
if (!jsonError) {
NSString *infoString = [[NSString alloc] initWithData:infoData encoding:NSUTF8StringEncoding];
appendFormField(@"data[information]", infoString);
}
// 🔹 Append image files
for (int i = 0; i < images.count; i++) {
UIImage *image = images[i];
NSData *imageData = UIImageJPEGRepresentation(image, 0.8);
if (!imageData) continue;
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:
@"Content-Disposition: form-data; name=\"data[image][%d]\"; filename=\"image%d.jpg\"\r\n", i, i]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Type: image/jpeg\r\n\r\n"
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:imageData];
[body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
}
[body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
request.HTTPBody = body;
NSLog(@"📦 [UpdateIssue] Uploading %lu image(s)", (unsigned long)images.count);
// 🔹 Execute request
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"❌ [UpdateIssue] Network error: %@", error);
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) completion(nil, error);
});
return;
}
NSError *jsonErr;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonErr];
if (jsonErr) {
NSString *raw = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"⚠️ [UpdateIssue] JSON parse error: %@\nRaw: %@", jsonErr, raw);
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) completion(nil, jsonErr);
});
return;
}
NSLog(@"✅ [UpdateIssue] Response: %@", json);
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) completion(json, nil);
});
}];
[task resume];
}
@end
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/DetailsViewController.h
View file @
5ac78689
...
...
@@ -6,20 +6,20 @@
@interface
AddIssueDetailsViewController
:
UIViewController
@property
(
nonatomic
,
strong
)
NSString
*
selectedLocationName
;
@property
(
nonatomic
,
strong
)
NSMutableArray
<
UIImage
*>
*
uploadedImages
;
@property
(
nonatomic
,
strong
)
NSString
*
planID
;
@property
(
nonatomic
,
strong
)
NSString
*
locationID
;
@property
(
nonatomic
,
strong
)
NSDictionary
*
locationData
;
@property
(
nonatomic
,
strong
)
NSString
*
defectMatrix
;
@property
(
nonatomic
,
strong
)
NSString
*
projectCode
;
@property
(
nonatomic
,
strong
)
NSString
*
projectName
;
@property
(
nonatomic
,
assign
)
CGFloat
planX
;
@property
(
nonatomic
,
assign
)
CGFloat
planY
;
@property
(
nonatomic
,
strong
)
NSString
*
action
;
@property
(
nonatomic
,
strong
)
NSDictionary
*
issueContent
;
@property
(
nonatomic
,
strong
)
NSDictionary
*
issueFullData
;
@property
(
nonatomic
,
strong
)
NSString
*
locationName
;
-
(
void
)
dismissSelf
;
-
(
void
)
handleSubmit
;
-
(
void
)
handleReset
;
@end
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/DetailsViewController.mm
View file @
5ac78689
...
...
@@ -17,16 +17,18 @@
@property (nonatomic, weak) UIButton *issueButton;
@property (nonatomic, copy) NSString *selectedTypeName;
@property (nonatomic, copy) NSString * selectedIssueID;
@property (nonatomic, assign) BOOL isEditMode;
@end
@implementation AddIssueDetailsViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
[super viewDidLoad];
self.isEditMode = [self.action isEqualToString:@"edit_issue"];
self.view.backgroundColor = UIColor.whiteColor;
NSLog(@"📦 Data being brought over:\n planID: %@\n locationID: %@\n selectedLocationName: %@\n defectMatrix: %@\n projectName: %@\n projectCode: %@\n XCoordinates: %f\n YCoordinates: %f\n locationData: %@",
NSLog(@"📦 Data being brought over:\n planID: %@\n locationID: %@\n selectedLocationName: %@\n defectMatrix: %@\n projectName: %@\n projectCode: %@\n XCoordinates: %f\n YCoordinates: %f\n
action: %@\n issueFullData: %@\n issueContent: %@\n
locationData: %@",
self.planID,
self.locationID,
self.selectedLocationName,
...
...
@@ -35,38 +37,146 @@
self.projectCode,
self.planX,
self.planY,
self.action,
self.issueFullData,
self.issueContent,
self.locationData);
NSString *text = [NSString stringWithFormat:@"%@", self.locationData];
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [docsPath stringByAppendingPathComponent:@"locationData.txt"];
// Convert issueData to a readable string
NSString *plainText = [NSString stringWithFormat:@"%@", self.locationData];
// Write as plain UTF-8 text
[plainText writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
// Log the path so you can find it
NSLog(@"📁 issueData saved as plain text to: %@", filePath);
NSDictionary *locData = self.locationData;
if ([locData isKindOfClass:[NSDictionary class]]) {
self.categories = locData[@"category"];
// Extract all types under all categories (for now, assuming one category)
if (self.categories.count > 0) {
NSDictionary *firstCat = self.categories.firstObject;
self.types = firstCat[@"type"];
}
NSLog(@"✅ Parsed %lu categories, %lu types", (unsigned long)self.categories.count, (unsigned long)self.types.count);
self.categories = locData[@"category"];
// Extract all types under all categories (for now, assuming one category)
if (self.categories.count > 0) {
NSDictionary *firstCat = self.categories.firstObject;
self.types = firstCat[@"type"];
}
NSLog(@"✅ Parsed %lu categories, %lu types", (unsigned long)self.categories.count, (unsigned long)self.types.count);
}
if (self.categories.count > 0) {
NSDictionary *firstCat = self.categories.firstObject;
NSString *catName = firstCat[@"cat_name"];
UIButton *catBtn = [self.view viewWithTag:2000];
if ([catBtn isKindOfClass:[UIButton class]] && catName) {
[catBtn setTitle:catName forState:UIControlStateNormal];
[catBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
}
NSDictionary *firstCat = self.categories.firstObject;
NSString *catName = firstCat[@"cat_name"];
UIButton *catBtn = [self.view viewWithTag:2000];
if ([catBtn isKindOfClass:[UIButton class]] && catName) {
[catBtn setTitle:catName forState:UIControlStateNormal];
[catBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
}
}
// Create all views (don’t position them yet)
[self createHeader];
[self createForm];
// Set location if passed from previous screen
if (self.selectedLocationName && self.selectedLocationName.length > 0) {
self.locationField.text = self.selectedLocationName;
self.locationField.text = self.selectedLocationName;
}
self.uploadedImages = [NSMutableArray arrayWithObjects:[NSNull null], [NSNull null], [NSNull null], nil];
if (self.isEditMode) {
UILabel *title = [self.headerView viewWithTag:101];
title.text = @"Edit Issue Details";
[self.submitButton setTitle:@"Save Changes" forState:UIControlStateNormal];
}
if (self.isEditMode && [self.issueFullData isKindOfClass:[NSDictionary class]]) {
NSDictionary *issue = self.issueFullData;
NSLog(@"🧠 Prefilling edit fields with issueFullData: %@", issue);
// 🗒 Prefill comment field (use 'remarks' key)
NSString *remarks = issue[@"remarks"];
if ([remarks isKindOfClass:[NSString class]]) {
self.commentField.text = remarks;
}
// 🏷 Prefill dropdown titles
NSString *catName = issue[@"category"];
NSString *typeName = issue[@"type"];
NSString *issueName = issue[@"issue"];
UIButton *catBtn = [self.view viewWithTag:2000]; // Category
UIButton *typeBtn = [self.view viewWithTag:2001]; // Type
UIButton *issueBtn = [self.view viewWithTag:2002]; // Issue
if ([catBtn isKindOfClass:[UIButton class]] && catName.length > 0) {
[catBtn setTitle:catName forState:UIControlStateNormal];
[catBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
}
if ([typeBtn isKindOfClass:[UIButton class]] && typeName.length > 0) {
[typeBtn setTitle:typeName forState:UIControlStateNormal];
[typeBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
self.selectedTypeName = typeName;
}
if ([issueBtn isKindOfClass:[UIButton class]] && issueName.length > 0) {
[issueBtn setTitle:issueName forState:UIControlStateNormal];
[issueBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
self.selectedIssueID = [NSString stringWithFormat:@"%@", issue[@"issue_id"] ?: @""];
}
// 📍 Prefill position
if (issue[@"pos_x"]) self.planX = [issue[@"pos_x"] floatValue];
if (issue[@"pos_y"]) self.planY = [issue[@"pos_y"] floatValue];
// 🧭 Prefill location name
NSString *locName = issue[@"location_name"];
if ([locName isKindOfClass:[NSString class]]) {
self.locationField.text = locName;
}
// 🖼 Prefill images under "first"
NSArray *firstImages = self.issueFullData[@"first"];
if ([firstImages isKindOfClass:[NSArray class]] && firstImages.count > 0) {
for (int i = 0; i < MIN(firstImages.count, 3); i++) {
NSDictionary *imgDict = firstImages[i];
NSString *urlStr = imgDict[@"thumb_image"] ?: imgDict[@"image"];
if (![urlStr isKindOfClass:[NSString class]]) continue;
NSURL *url = [NSURL URLWithString:urlStr];
if (!url) continue;
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error || !data) return;
UIImage *img = [UIImage imageWithData:data];
if (!img) return;
dispatch_async(dispatch_get_main_queue(), ^{
if (i < self.uploadedImages.count)
self.uploadedImages[i] = img;
else
[self.uploadedImages addObject:img];
UIButton *btn = [self.view viewWithTag:1000 + i];
if ([btn isKindOfClass:[UIButton class]]) {
[btn setImage:img forState:UIControlStateNormal];
btn.imageView.contentMode = UIViewContentModeScaleAspectFill;
btn.clipsToBounds = YES;
[self addRemoveButtonToUpload:btn atIndex:i];
}
});
}];
[task resume];
}
}
NSLog(@"✅ Prefilled Edit Mode UI successfully");
}
}
- (void)viewDidLayoutSubviews {
...
...
@@ -123,6 +233,9 @@
// ✅ Reset button (refresh icon)
self.resetButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.resetButton.translatesAutoresizingMaskIntoConstraints = NO;
if (self.isEditMode){
self.resetButton.hidden = YES;
}
UIImage *refreshImage = [UIImage systemImageNamed:@"arrow.clockwise"];
refreshImage = [refreshImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
...
...
@@ -770,66 +883,137 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *
}
- (void)performSubmit {
NSLog(@"Calling addIssue API:\n planID: %@\n locationID: %@\n selectedIssueID: %@\n XCoordinates: %f\n YCoordinates: %f\n commentField: %@",
self.planID,
self.locationID,
self.selectedIssueID,
self.planX,
self.planY,
self.commentField.text);
NSDictionary *issueData = @{
@"plan_id": self.planID ?: @"0",
@"location_id": self.locationID ?: @"0",
@"issue_setting_id": self.selectedIssueID ?: @"",
@"position_x": [NSString stringWithFormat:@"%f", self.planX ?: 0.0],
@"position_y": [NSString stringWithFormat:@"%f", self.planY ?: 0.0],
@"comment": self.commentField.text ?: @"",
@"os": @"AND"
};
[AddIssueAPIClient submitAddIssue:issueData
images:self.uploadedImages
completion:^(NSDictionary *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{ // ensure UI updates happen on main thread
if (error) {
NSLog(@"❌ Submission failed: %@", error.localizedDescription);
[self showAlertWithTitle:@"Submission Failed"
message:error.localizedDescription ?: @"An unknown error occurred."];
return;
}
NSDictionary *appData = response[@"AppData"];
if ([appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"✅ Issue submitted successfully!");
// ✅ Success alert
UIAlertController *successAlert = [UIAlertController alertControllerWithTitle:@"Issue Submitted"
message:@"Your issue has been successfully added."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
// Optionally go back or refresh dashboard
UIViewController *presenter = self.presentingViewController;
if (presenter.presentingViewController) {
[presenter.presentingViewController dismissViewControllerAnimated:YES completion:nil];
} else {
[self dismissViewControllerAnimated:YES completion:nil];
}}];
[successAlert addAction:ok];
[self presentViewController:successAlert animated:YES completion:nil];
if (self.isEditMode) {
NSLog(@"📝 Updating existing issue instead of adding new one");
if (self.isEditMode && !self.issueFullData) {
NSLog(@"⚠️ Edit mode is ON, but no issueFullData passed!");
}
// Prefer issue_id first, fallback to id
NSString *issueID = nil;
if ([self.issueFullData[@"issue_id"] isKindOfClass:[NSString class]]) {
issueID = self.issueFullData[@"issue_id"];
} else if ([self.issueFullData[@"id"] isKindOfClass:[NSString class]]) {
issueID = self.issueFullData[@"id"];
} else {
issueID = [NSString stringWithFormat:@"%@", self.issueFullData[@"issue_id"] ?: self.issueFullData[@"id"] ?: @"0"];
}
// ✅ Build update payload
NSDictionary *updateData = @{
@"issue_id": issueID ?: @"0",
@"issue_setting_id": self.selectedIssueID ?: @"",
@"position_x": @(self.planX).stringValue ?: @"",
@"position_y": @(self.planY).stringValue ?: @"",
@"comment": self.commentField.text ?: @"",
@"os": @"AND"
};
NSLog(@"📦 Sending UpdateIssue with data: %@", updateData);
[AddIssueAPIClient submitUpdateIssue:updateData
images:self.uploadedImages
completion:^(NSDictionary * _Nullable response, NSError * _Nullable error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
[self showAlertWithTitle:@"Update Failed" message:error.localizedDescription];
return;
}
NSDictionary *appData = response[@"AppData"];
if ([appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"✅ Issue updated successfully!");
UIAlertController *successAlert =
[UIAlertController alertControllerWithTitle:@"Issue Updated"
message:@"Your changes have been successfully saved."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
// ✅ Same navigation logic as Add Issue
UIViewController *presenter = self.presentingViewController;
if (presenter.presentingViewController) {
[presenter.presentingViewController dismissViewControllerAnimated:YES completion:nil];
} else {
[self dismissViewControllerAnimated:YES completion:nil];
}
}];
[successAlert addAction:ok];
[self presentViewController:successAlert animated:YES completion:nil];
} else {
NSString *msg = appData[@"message"] ?: @"Unknown error occurred";
NSLog(@"⚠️ Update API Error: %@", msg);
[self showAlertWithTitle:@"Update Error" message:msg];
}
});
}];
} else {
NSLog(@"Calling addIssue API:\n planID: %@\n locationID: %@\n selectedIssueID: %@\n XCoordinates: %f\n YCoordinates: %f\n commentField: %@",
self.planID,
self.locationID,
self.selectedIssueID,
self.planX,
self.planY,
self.commentField.text);
NSDictionary *issueData = @{
@"plan_id": self.planID ?: @"0",
@"location_id": self.locationID ?: @"0",
@"issue_setting_id": self.selectedIssueID ?: @"",
@"position_x": [NSString stringWithFormat:@"%f", self.planX ?: 0.0],
@"position_y": [NSString stringWithFormat:@"%f", self.planY ?: 0.0],
@"comment": self.commentField.text ?: @"",
@"os": @"AND"
};
[AddIssueAPIClient submitAddIssue:issueData
images:self.uploadedImages
completion:^(NSDictionary *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
NSLog(@"❌ Submission failed: %@", error.localizedDescription);
[self showAlertWithTitle:@"Submission Failed"
message:error.localizedDescription ?: @"An unknown error occurred."];
return;
}
} else {
NSString *msg = appData[@"message"] ?: @"Unexpected response from server.";
NSLog(@"⚠️ API Error: %@", msg);
[self showAlertWithTitle:@"Submission Error" message:msg];
}
});
}];
NSDictionary *appData = response[@"AppData"];
if ([appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"✅ Issue submitted successfully!");
UIAlertController *successAlert =
[UIAlertController alertControllerWithTitle:@"Issue Submitted"
message:@"Your issue has been successfully added."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
UIViewController *presenter = self.presentingViewController;
if (presenter.presentingViewController) {
[presenter.presentingViewController dismissViewControllerAnimated:YES completion:nil];
} else {
[self dismissViewControllerAnimated:YES completion:nil];
}
}];
[successAlert addAction:ok];
[self presentViewController:successAlert animated:YES completion:nil];
} else {
NSString *msg = appData[@"message"] ?: @"Unexpected response from server.";
NSLog(@"⚠️ API Error: %@", msg);
[self showAlertWithTitle:@"Submission Error" message:msg];
}
});
}];
}
}
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title
message:message
...
...
framework/QmsPluginFramework/QmsPluginFramework/AddIssue/PlanViewController.mm
View file @
5ac78689
...
...
@@ -43,8 +43,8 @@
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
NSLog(@"PlanViewController loaded");
NSLog(@"🧭 Navigated to PlanScreen with:\n type=%@\n unitID=%@\n unitName=%@\n location= %@ & %@\n
issue_id=%@\n
",
self.type, self.unitID, self.unitName, self.locationName, self.locationId, self.issueContent[@"issue_id"]);
NSLog(@"🧭 Navigated to PlanScreen with:\n type=%@\n unitID=%@\n unitName=%@\n location= %@ & %@\n
issue_id=%@\n action=%@
",
self.type, self.unitID, self.unitName, self.locationName, self.locationId, self.issueContent[@"issue_id"]
, self.action
);
// Create UI elements (but don’t assign final frames yet)
[self createHeader];
[self createScrollView];
...
...
@@ -77,7 +77,7 @@
NSLog(@"✅ Raw Unit Plan response received");
// Save response to Documents for
inspection
// Save response to Documents for
debugging
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:nil];
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [docsPath stringByAppendingPathComponent:@"getUnitPlan.txt"];
...
...
@@ -100,8 +100,6 @@
return;
}
self.unitPlanLocations = mainData.firstObject[@"location"];
// Store main plan object
self.unitPlanData = mainData.firstObject;
self.locations = self.unitPlanData[@"location"];
...
...
@@ -136,31 +134,38 @@
dispatch_async(dispatch_get_main_queue(), ^{
[self displayPlanImage];
[self debugPrintAllIssues];
// 🧭 Auto-lock logic for edit mode
NSString *action = self.passedData[@"action"];
if ([action isEqualToString:@"edit_issue"]) {
NSLog(@"✏️ Edit mode detected — auto-selecting issue location");
// Option 1️⃣ — If you have coordinates
NSString *posX = [NSString stringWithFormat:@"%@", self.passedData[@"issue_content"][@"pos_x"] ?: @""];
NSString *posY = [NSString stringWithFormat:@"%@", self.passedData[@"issue_content"][@"pos_y"] ?: @""];
if (posX.length > 0 && posY.length > 0) {
self.tappedPlanX = [posX floatValue];
self.tappedPlanY = [posY floatValue];
[self highlightExistingIssueAtCoordinates:self.tappedPlanX Y:self.tappedPlanY];
}
// Option 2️⃣ — If you prefer locking by location name
NSString *locationName = self.passedData[@"location_name"];
if (locationName.length > 0) {
self.selectedLocation = locationName;
[self showAddIssuePopup]; // show popup immediately
}
if ([self.action isEqualToString:@"edit_issue"]) {
NSLog(@"✏️ Edit mode detected — will auto-select issue location after image loads");
NSString *posX = [NSString stringWithFormat:@"%@", self.issueContent[@"pos_x"] ?: @""];
NSString *posY = [NSString stringWithFormat:@"%@", self.issueContent[@"pos_y"] ?: @""];
self.tappedPlanX = [posX floatValue];
self.tappedPlanY = [posY floatValue];
NSString *locationName = self.locationName;
self.selectedLocation = locationName;
// Wait until planImageView has a valid image
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (self.planImageView.image) {
[self highlightExistingIssueAtCoordinates:self.tappedPlanX Y:self.tappedPlanY];
[self showAddIssuePopup];
} else {
NSLog(@"⚠️ Plan image not ready, retrying highlight...");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self highlightExistingIssueAtCoordinates:self.tappedPlanX Y:self.tappedPlanY];
[self showAddIssuePopup];
});
}
});
}
});
}];
}
- (void)highlightExistingIssueAtCoordinates:(CGFloat)x Y:(CGFloat)y {
NSLog(@"📍 Highlighting existing issue at (%.2f, %.2f)", x, y);
...
...
@@ -764,12 +769,18 @@
nextVC.selectedLocationName = self.selectedLocation;
nextVC.locationData = mainData;
nextVC.defectMatrix = defectMatrix;
nextVC.projectCode = self.projectCode;
nextVC.projectName = self.
projec
tName;
nextVC.projectCode = self.projectCode
?: @""
;
nextVC.projectName = self.
uni
tName;
nextVC.planX = self.tappedPlanX;
nextVC.planY = self.tappedPlanY;
//edit info
nextVC.action = self.action;
nextVC.issueFullData = self.issueFullData;
nextVC.issueContent = self.issueContent;
nextVC.locationName = self.locationName;
NSLog(@"📦 Data being brought over:\n planID: %@\n locationID: %@\n selectedLocationName: %@\n defectMatrix: %@\n projectName: %@\n projectCode: %@\n XCoordinates: %f\n YCoordinates: %f\n locationData: %@",
NSLog(@"📦 Data being brought over:\n planID: %@\n locationID: %@\n selectedLocationName: %@\n defectMatrix: %@\n projectName: %@\n projectCode: %@\n XCoordinates: %f\n YCoordinates: %f\n locationData: %@
\n action: %@\n issueFullData: %@\n issueContent: %@
",
nextVC.planID,
nextVC.locationID,
nextVC.selectedLocationName,
...
...
@@ -778,7 +789,10 @@
nextVC.projectCode,
nextVC.planX,
nextVC.planY,
nextVC.locationData);
nextVC.locationData,
nextVC.action,
nextVC.issueFullData,
nextVC.issueContent);
[self presentViewController:nextVC animated:YES completion:nil];
}
...
...
framework/QmsPluginFramework/QmsPluginFramework/Issue/IssueDetailViewController.mm
View file @
5ac78689
...
...
@@ -414,7 +414,7 @@
HistoryViewController *nextVC = [[HistoryViewController alloc] init];
nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
nextVC.issueID = self.issueData[@"issue_reference_id"];
nextVC.issueID = self.issueData[@"issue_reference_id"]
?: self.issueData[@"id"] ?: @""
;
nextVC.planID = self.issueData[@"plan_id"];
nextVC.status = self.issueData[@"status_external"];
nextVC.unitName = self.issueData[@"plan_unit"];
...
...
framework/QmsPluginFramework/QmsPluginFramework/Issue/WithdrawSingleIssueViewController.mm
View file @
5ac78689
...
...
@@ -170,10 +170,28 @@
NSDictionary *appData = data[@"AppData"];
if ([appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"Issue deleted successfully");
NSLog(@"✅ Issue deleted successfully!");
UIAlertController *successAlert = [UIAlertController alertControllerWithTitle:@"Success"
message:@"Issue deleted successfully."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
// 🏠 Mimic AddIssue success dismissal logic
UIViewController *presenter = self.presentingViewController;
if (presenter.presentingViewController) {
[presenter.presentingViewController dismissViewControllerAnimated:YES completion:nil];
} else {
[self dismissViewControllerAnimated:YES completion:nil];
}
}];
[successAlert addAction:ok];
[self presentViewController:successAlert animated:YES completion:nil];
} else {
NSString *message = appData[@"message"] ?: @"Unknown error";
NSLog(@"Error Message %@", message);
NSString *message = appData[@"message"] ?: @"Unknown error";
NSLog(@"⚠️ Error Message %@", message);
[self showAlertWithTitle:@"Delete Failed" message:message];
}
}];
}
...
...
@@ -190,12 +208,40 @@
NSDictionary *appData = data[@"AppData"];
if ([appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"Issue withdrawn successfully");
NSLog(@"✅ Issue deleted successfully!");
UIAlertController *successAlert = [UIAlertController alertControllerWithTitle:@"Success"
message:@"Issue deleted successfully."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
// 🏠 Mimic AddIssue success dismissal logic
UIViewController *presenter = self.presentingViewController;
if (presenter.presentingViewController) {
[presenter.presentingViewController dismissViewControllerAnimated:YES completion:nil];
} else {
[self dismissViewControllerAnimated:YES completion:nil];
}
}];
[successAlert addAction:ok];
[self presentViewController:successAlert animated:YES completion:nil];
} else {
NSString *message = appData[@"message"] ?: @"Unknown error";
NSLog(@"Error Message %@", message);
NSString *message = appData[@"message"] ?: @"Unknown error";
NSLog(@"⚠️ Error Message %@", message);
[self showAlertWithTitle:@"Delete Failed" message:message];
}
}];
}
# pragma mark - helper
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:ok];
[self presentViewController:alert animated:YES completion:nil];
}
@end
ios/QmsPluginFramework.xcframework/Info.plist
View file @
5ac78689
...
...
@@ -8,32 +8,32 @@
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
string
>
ios-arm64
_x86_64-simulator
<
/string
>
<
string
>
ios-arm64
<
/string
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
d
i
c
t
>
<
k
e
y
>
BinaryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework/QmsPluginFramework
<
/string
>
<
k
e
y
>
LibraryIdentifier
<
/k
e
y
>
<
string
>
ios-arm64
<
/string
>
<
string
>
ios-arm64
_x86_64-simulator
<
/string
>
<
k
e
y
>
LibraryPath
<
/k
e
y
>
<
string
>
QmsPluginFramework.framework
<
/string
>
<
k
e
y
>
SupportedArchitectures
<
/k
e
y
>
<
a
rr
a
y
>
<
string
>
arm64
<
/string
>
<
string
>
x86_64
<
/string
>
<
/
a
rr
a
y
>
<
k
e
y
>
SupportedPlatform
<
/k
e
y
>
<
string
>
ios
<
/string
>
<
k
e
y
>
SupportedPlatformVariant
<
/k
e
y
>
<
string
>
simulator
<
/string
>
<
/
d
i
c
t
>
<
/
a
rr
a
y
>
<
k
e
y
>
CFBundlePackageType
<
/k
e
y
>
...
...
ios/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework
View file @
5ac78689
No preview for this file type
ios/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework
View file @
5ac78689
No preview for this file type
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment