itsm-widget 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ANGULAR-INSTALLATION.md +372 -0
- package/API-SERVICE.md +334 -0
- package/INSTALLATION.md +467 -0
- package/README.md +361 -0
- package/dist/assets/icons/add-ticket-icon.png +0 -0
- package/dist/itsm-widget.min.css +1 -0
- package/dist/itsm-widget.min.js +2 -0
- package/dist/itsm-widget.min.js.LICENSE.txt +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
# Hướng dẫn cài đặt ITSM Widget vào Angular Project
|
|
2
|
+
|
|
3
|
+
## 📋 Các bước cài đặt
|
|
4
|
+
|
|
5
|
+
### Cách 1: Cài đặt qua npm (Khuyến nghị)
|
|
6
|
+
|
|
7
|
+
**Bước 1: Install package**
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install itsm-widget
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**Bước 2: Cập nhật `angular.json`**
|
|
14
|
+
|
|
15
|
+
Thêm vào `scripts` và `styles`:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"projects": {
|
|
20
|
+
"your-project-name": {
|
|
21
|
+
"architect": {
|
|
22
|
+
"build": {
|
|
23
|
+
"options": {
|
|
24
|
+
"scripts": [
|
|
25
|
+
"node_modules/itsm-widget/dist/itsm-widget.min.js"
|
|
26
|
+
],
|
|
27
|
+
"styles": [
|
|
28
|
+
"src/styles.css",
|
|
29
|
+
"node_modules/itsm-widget/dist/itsm-widget.min.css"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Bước 3:** Xem tiếp phần "Khởi tạo widget" bên dưới.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
### Cách 2: Copy files thủ công
|
|
44
|
+
|
|
45
|
+
**Bước 1: Copy files vào project**
|
|
46
|
+
|
|
47
|
+
Copy 2 files sau từ `dist/` của widget vào Angular project:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
src/assets/
|
|
51
|
+
├── itsm-widget.min.js
|
|
52
|
+
└── itsm-widget.min.css
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Cách copy:**
|
|
56
|
+
- Copy `dist/itsm-widget.min.js` → `src/assets/itsm-widget.min.js`
|
|
57
|
+
- Copy `dist/itsm-widget.min.css` → `src/assets/itsm-widget.min.css`
|
|
58
|
+
|
|
59
|
+
**Bước 2: Cập nhật `angular.json`**
|
|
60
|
+
|
|
61
|
+
Thêm scripts và styles vào `angular.json`:
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"projects": {
|
|
66
|
+
"your-project-name": {
|
|
67
|
+
"architect": {
|
|
68
|
+
"build": {
|
|
69
|
+
"options": {
|
|
70
|
+
"scripts": [
|
|
71
|
+
"src/assets/itsm-widget.min.js"
|
|
72
|
+
],
|
|
73
|
+
"styles": [
|
|
74
|
+
"src/styles.css",
|
|
75
|
+
"src/assets/itsm-widget.min.css"
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Lưu ý:** Thay `your-project-name` bằng tên project của bạn.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## ⚙️ Cấu hình (Áp dụng cho cả 2 cách)
|
|
90
|
+
|
|
91
|
+
### Bước 3: Cấu hình environment (Khuyến nghị)
|
|
92
|
+
|
|
93
|
+
Thêm config vào `src/environments/environment.ts`:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
export const environment = {
|
|
97
|
+
production: false,
|
|
98
|
+
// ... other config
|
|
99
|
+
itsm: {
|
|
100
|
+
apiBaseUrl: 'https://your-api-domain.com',
|
|
101
|
+
apiKey: 'your-api-key',
|
|
102
|
+
tenant: 'your-tenant-name',
|
|
103
|
+
site: 'Your Site Name'
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Và `src/environments/environment.prod.ts`:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
export const environment = {
|
|
112
|
+
production: true,
|
|
113
|
+
// ... other config
|
|
114
|
+
itsm: {
|
|
115
|
+
apiBaseUrl: 'https://your-api-domain.com',
|
|
116
|
+
apiKey: 'your-production-api-key',
|
|
117
|
+
tenant: 'your-tenant-name',
|
|
118
|
+
site: 'Your Site Name'
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## 🚀 Khởi tạo widget
|
|
124
|
+
|
|
125
|
+
Có 2 cách để khởi tạo widget:
|
|
126
|
+
|
|
127
|
+
#### Cách 1: Khởi tạo trong `app.component.ts` (Đơn giản)
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import { Component, OnInit, OnDestroy } from '@angular/core';
|
|
131
|
+
import { environment } from '../environments/environment';
|
|
132
|
+
|
|
133
|
+
declare var ITSMWidget: any;
|
|
134
|
+
|
|
135
|
+
@Component({
|
|
136
|
+
selector: 'app-root',
|
|
137
|
+
templateUrl: './app.component.html',
|
|
138
|
+
styleUrls: ['./app.component.css']
|
|
139
|
+
})
|
|
140
|
+
export class AppComponent implements OnInit, OnDestroy {
|
|
141
|
+
title = 'your-app';
|
|
142
|
+
private itsmWidgetInstance: any;
|
|
143
|
+
|
|
144
|
+
ngOnInit() {
|
|
145
|
+
// Khởi tạo ITSM Widget
|
|
146
|
+
if (typeof ITSMWidget !== 'undefined') {
|
|
147
|
+
this.itsmWidgetInstance = new ITSMWidget({
|
|
148
|
+
apiBaseUrl: environment.itsm.apiBaseUrl,
|
|
149
|
+
apiKey: environment.itsm.apiKey,
|
|
150
|
+
tenant: environment.itsm.tenant,
|
|
151
|
+
position: 'bottom-right',
|
|
152
|
+
iconText: '📝',
|
|
153
|
+
iconColor: '#007bff',
|
|
154
|
+
title: 'Tạo phiếu yêu cầu ITSM',
|
|
155
|
+
requesterName: '', // Optional - có thể lấy từ service
|
|
156
|
+
site: environment.itsm.site,
|
|
157
|
+
onSuccess: (response: any) => {
|
|
158
|
+
console.log('ITSM Request submitted:', response);
|
|
159
|
+
// Hiển thị thông báo thành công
|
|
160
|
+
alert('Phiếu yêu cầu đã được gửi thành công!');
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Lưu instance vào window để có thể access từ nơi khác
|
|
165
|
+
(window as any).itsmWidgetInstance = this.itsmWidgetInstance;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
ngOnDestroy() {
|
|
170
|
+
// Cleanup widget khi component bị destroy
|
|
171
|
+
if (this.itsmWidgetInstance) {
|
|
172
|
+
this.itsmWidgetInstance.destroy();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
#### Cách 2: Tạo Service riêng (Khuyến nghị cho project lớn)
|
|
179
|
+
|
|
180
|
+
**1. Tạo service:** `src/app/services/itsm-widget.service.ts`
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import { Injectable, OnDestroy } from '@angular/core';
|
|
184
|
+
import { environment } from '../../environments/environment';
|
|
185
|
+
|
|
186
|
+
declare var ITSMWidget: any;
|
|
187
|
+
|
|
188
|
+
@Injectable({
|
|
189
|
+
providedIn: 'root'
|
|
190
|
+
})
|
|
191
|
+
export class ItsmWidgetService implements OnDestroy {
|
|
192
|
+
private widgetInstance: any;
|
|
193
|
+
|
|
194
|
+
constructor() {
|
|
195
|
+
this.init();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private init(): void {
|
|
199
|
+
if (typeof ITSMWidget !== 'undefined' && !this.widgetInstance) {
|
|
200
|
+
this.widgetInstance = new ITSMWidget({
|
|
201
|
+
apiBaseUrl: environment.itsm.apiBaseUrl,
|
|
202
|
+
apiKey: environment.itsm.apiKey,
|
|
203
|
+
tenant: environment.itsm.tenant,
|
|
204
|
+
position: 'bottom-right',
|
|
205
|
+
iconText: '📝',
|
|
206
|
+
iconColor: '#007bff',
|
|
207
|
+
title: 'Tạo phiếu yêu cầu ITSM',
|
|
208
|
+
requesterName: this.getCurrentUser(), // Lấy từ auth service
|
|
209
|
+
site: environment.itsm.site,
|
|
210
|
+
onSuccess: (response: any) => {
|
|
211
|
+
console.log('ITSM Request submitted:', response);
|
|
212
|
+
// Có thể emit event hoặc hiển thị notification ở đây
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
(window as any).itsmWidgetInstance = this.widgetInstance;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private getCurrentUser(): string {
|
|
221
|
+
// Lấy tên user từ auth service, localStorage, hoặc sessionStorage
|
|
222
|
+
// Ví dụ:
|
|
223
|
+
// return this.authService.getCurrentUser()?.name || '';
|
|
224
|
+
// return localStorage.getItem('userName') || '';
|
|
225
|
+
return '';
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
ngOnDestroy(): void {
|
|
229
|
+
if (this.widgetInstance) {
|
|
230
|
+
this.widgetInstance.destroy();
|
|
231
|
+
this.widgetInstance = null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**2. Inject service vào `app.component.ts`:**
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
import { Component, OnInit } from '@angular/core';
|
|
241
|
+
import { ItsmWidgetService } from './services/itsm-widget.service';
|
|
242
|
+
|
|
243
|
+
@Component({
|
|
244
|
+
selector: 'app-root',
|
|
245
|
+
templateUrl: './app.component.html',
|
|
246
|
+
styleUrls: ['./app.component.css']
|
|
247
|
+
})
|
|
248
|
+
export class AppComponent implements OnInit {
|
|
249
|
+
title = 'your-app';
|
|
250
|
+
|
|
251
|
+
constructor(private itsmWidgetService: ItsmWidgetService) {}
|
|
252
|
+
|
|
253
|
+
ngOnInit() {
|
|
254
|
+
// Service sẽ tự động khởi tạo widget
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Bước 5: Build và test
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
# Development
|
|
263
|
+
ng serve
|
|
264
|
+
|
|
265
|
+
# Production build
|
|
266
|
+
ng build --prod
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## ⚙️ Cấu hình nâng cao
|
|
270
|
+
|
|
271
|
+
### Lấy thông tin user từ Auth Service
|
|
272
|
+
|
|
273
|
+
Nếu bạn có Auth Service, có thể lấy thông tin user:
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
import { AuthService } from './services/auth.service';
|
|
277
|
+
|
|
278
|
+
constructor(
|
|
279
|
+
private itsmWidgetService: ItsmWidgetService,
|
|
280
|
+
private authService: AuthService
|
|
281
|
+
) {}
|
|
282
|
+
|
|
283
|
+
ngOnInit() {
|
|
284
|
+
const user = this.authService.getCurrentUser();
|
|
285
|
+
|
|
286
|
+
// Update widget với thông tin user
|
|
287
|
+
if ((window as any).itsmWidgetInstance && user) {
|
|
288
|
+
(window as any).itsmWidgetInstance.config.requesterName = user.name;
|
|
289
|
+
(window as any).itsmWidgetInstance.config.site = user.site || '';
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Tích hợp với Notification Service
|
|
295
|
+
|
|
296
|
+
Có thể tích hợp với notification service của Angular:
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
import { NotificationService } from './services/notification.service';
|
|
300
|
+
|
|
301
|
+
constructor(private notificationService: NotificationService) {}
|
|
302
|
+
|
|
303
|
+
// Trong widget config:
|
|
304
|
+
onSuccess: (response: any) => {
|
|
305
|
+
this.notificationService.showSuccess('Phiếu yêu cầu đã được gửi thành công!');
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Custom UDF Fields
|
|
310
|
+
|
|
311
|
+
Có thể thêm custom UDF fields:
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
new ITSMWidget({
|
|
315
|
+
// ... other config
|
|
316
|
+
udf_fields: {
|
|
317
|
+
udf_pick_301: 'Value 1',
|
|
318
|
+
udf_pick_302: 'Value 2',
|
|
319
|
+
// ... other fields
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## 🐛 Troubleshooting
|
|
325
|
+
|
|
326
|
+
### Widget không hiển thị
|
|
327
|
+
|
|
328
|
+
1. Kiểm tra `angular.json` đã add scripts và styles chưa
|
|
329
|
+
2. Kiểm tra files đã copy đúng vào `src/assets/` chưa
|
|
330
|
+
3. Kiểm tra console có lỗi JavaScript không
|
|
331
|
+
4. Đảm bảo đã build lại project: `ng serve` hoặc `ng build`
|
|
332
|
+
|
|
333
|
+
### Lỗi TypeScript: Cannot find name 'ITSMWidget'
|
|
334
|
+
|
|
335
|
+
Thêm declare vào đầu file:
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
declare var ITSMWidget: any;
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
Hoặc tạo file `src/typings.d.ts`:
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
declare var ITSMWidget: any;
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Widget không hoạt động sau khi build production
|
|
348
|
+
|
|
349
|
+
Đảm bảo files đã được include trong `angular.json`:
|
|
350
|
+
|
|
351
|
+
```json
|
|
352
|
+
"assets": [
|
|
353
|
+
"src/favicon.ico",
|
|
354
|
+
"src/assets",
|
|
355
|
+
{
|
|
356
|
+
"glob": "**/*",
|
|
357
|
+
"input": "src/assets",
|
|
358
|
+
"output": "/assets"
|
|
359
|
+
}
|
|
360
|
+
]
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## 📝 Ví dụ hoàn chỉnh
|
|
364
|
+
|
|
365
|
+
Xem file [example.html](../example.html) để tham khảo cách sử dụng cơ bản.
|
|
366
|
+
|
|
367
|
+
## 📚 Tài liệu thêm
|
|
368
|
+
|
|
369
|
+
- [README.md](../README.md) - Tài liệu tổng quan
|
|
370
|
+
- [INSTALLATION.md](../INSTALLATION.md) - Hướng dẫn cho các platform khác
|
|
371
|
+
- [API-SERVICE.md](../API-SERVICE.md) - Tài liệu API Service
|
|
372
|
+
|
package/API-SERVICE.md
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
# ITSM API Service
|
|
2
|
+
|
|
3
|
+
Service JavaScript để gọi các API của SDP ITSM theo tài liệu API v2 SDP ITSM SPC.
|
|
4
|
+
|
|
5
|
+
## Tổng quan
|
|
6
|
+
|
|
7
|
+
`ITSMAPIService` cung cấp các method để tương tác với ITSM API:
|
|
8
|
+
- Tạo yêu cầu mới (ticket)
|
|
9
|
+
- Upload file đính kèm
|
|
10
|
+
- Lấy thông tin request
|
|
11
|
+
- Helper methods để map và build data
|
|
12
|
+
|
|
13
|
+
## Cài đặt
|
|
14
|
+
|
|
15
|
+
### Import trong module:
|
|
16
|
+
```javascript
|
|
17
|
+
import ITSMAPIService from './itsm-api.service.js';
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Hoặc sử dụng global (sau khi load script):
|
|
21
|
+
```javascript
|
|
22
|
+
const ITSMAPIService = window.ITSMAPIService;
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Khởi tạo
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
const apiService = new ITSMAPIService({
|
|
29
|
+
baseUrl: 'https://your-api-domain.com',
|
|
30
|
+
apiKey: 'your-api-key',
|
|
31
|
+
tenant: 'your-tenant-name'
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Options
|
|
36
|
+
|
|
37
|
+
| Option | Type | Default | Mô tả |
|
|
38
|
+
|--------|------|---------|-------|
|
|
39
|
+
| `baseUrl` | string | `''` | Base URL của API ITSM (bắt buộc) |
|
|
40
|
+
| `apiKey` | string | `''` | API Key để xác thực (bắt buộc) |
|
|
41
|
+
| `tenant` | string | `''` | Tenant name (pn header) (bắt buộc) |
|
|
42
|
+
|
|
43
|
+
## Methods
|
|
44
|
+
|
|
45
|
+
### 1. createRequest(requestData)
|
|
46
|
+
|
|
47
|
+
Tạo yêu cầu mới (ticket).
|
|
48
|
+
|
|
49
|
+
**Parameters:**
|
|
50
|
+
- `requestData` (Object): Dữ liệu yêu cầu theo format API
|
|
51
|
+
|
|
52
|
+
**Returns:** `Promise<Object>`
|
|
53
|
+
|
|
54
|
+
**Ví dụ:**
|
|
55
|
+
```javascript
|
|
56
|
+
const requestData = {
|
|
57
|
+
requester: {
|
|
58
|
+
name: 'Lê Trường Tình'
|
|
59
|
+
},
|
|
60
|
+
category: {
|
|
61
|
+
name: 'A01A00 - Quản lý an toàn thông tin'
|
|
62
|
+
},
|
|
63
|
+
subcategory: {
|
|
64
|
+
name: 'A01A01 - Hệ thống'
|
|
65
|
+
},
|
|
66
|
+
priority: {
|
|
67
|
+
name: 'Trung bình'
|
|
68
|
+
},
|
|
69
|
+
subject: 'Test ITSM',
|
|
70
|
+
description: '<div>Test description</div>',
|
|
71
|
+
site: {
|
|
72
|
+
name: 'Your Site Name'
|
|
73
|
+
},
|
|
74
|
+
item: {
|
|
75
|
+
name: 'Danh sách chức năng'
|
|
76
|
+
},
|
|
77
|
+
template: {
|
|
78
|
+
name: 'A01A00 - Quản lý an toàn thông tin'
|
|
79
|
+
},
|
|
80
|
+
udf_fields: {
|
|
81
|
+
udf_pick_301: 'Value 1',
|
|
82
|
+
udf_pick_302: 'Value 2',
|
|
83
|
+
udf_pick_303: 'Value 3',
|
|
84
|
+
udf_pick_304: 'Value 4',
|
|
85
|
+
udf_pick_305: 'Value 5',
|
|
86
|
+
udf_pick_306: 'Value 6'
|
|
87
|
+
},
|
|
88
|
+
attachments: [],
|
|
89
|
+
assets: []
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const response = await apiService.createRequest(requestData);
|
|
93
|
+
console.log('Request ID:', response.request.id);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Response:**
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"response_status": {
|
|
100
|
+
"status_code": 2000,
|
|
101
|
+
"status": "success"
|
|
102
|
+
},
|
|
103
|
+
"request": {
|
|
104
|
+
"id": "18391",
|
|
105
|
+
"ola_due_by_time": null,
|
|
106
|
+
"resolution": {
|
|
107
|
+
"resolution_attachments": [],
|
|
108
|
+
"content": null
|
|
109
|
+
},
|
|
110
|
+
"onhold_time": null,
|
|
111
|
+
"is_trashed": false
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 2. uploadAttachment(requestId, files)
|
|
117
|
+
|
|
118
|
+
Upload file đính kèm vào ticket đã tạo.
|
|
119
|
+
|
|
120
|
+
**Parameters:**
|
|
121
|
+
- `requestId` (string): ID của ticket
|
|
122
|
+
- `files` (File | File[]): File hoặc mảng các file cần upload
|
|
123
|
+
|
|
124
|
+
**Returns:** `Promise<Object>`
|
|
125
|
+
|
|
126
|
+
**Ví dụ:**
|
|
127
|
+
```javascript
|
|
128
|
+
// Upload 1 file
|
|
129
|
+
const fileInput = document.getElementById('file-input');
|
|
130
|
+
const file = fileInput.files[0];
|
|
131
|
+
const response = await apiService.uploadAttachment('18391', file);
|
|
132
|
+
|
|
133
|
+
// Upload nhiều file
|
|
134
|
+
const files = Array.from(fileInput.files);
|
|
135
|
+
const response = await apiService.uploadAttachment('18391', files);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 3. createRequestWithAttachments(requestData, files)
|
|
139
|
+
|
|
140
|
+
Tạo request và upload file cùng lúc (all-in-one method).
|
|
141
|
+
|
|
142
|
+
**Parameters:**
|
|
143
|
+
- `requestData` (Object): Dữ liệu yêu cầu
|
|
144
|
+
- `files` (File | File[]): File đính kèm (optional)
|
|
145
|
+
|
|
146
|
+
**Returns:** `Promise<Object>`
|
|
147
|
+
|
|
148
|
+
**Ví dụ:**
|
|
149
|
+
```javascript
|
|
150
|
+
const requestData = {
|
|
151
|
+
requester: { name: 'Nguyễn Văn A' },
|
|
152
|
+
category: { name: 'A01A00 - Quản lý an toàn thông tin' },
|
|
153
|
+
priority: { name: 'Trung bình' },
|
|
154
|
+
subject: 'Test with attachment',
|
|
155
|
+
description: 'Test description'
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const files = Array.from(document.getElementById('file-input').files);
|
|
159
|
+
const response = await apiService.createRequestWithAttachments(requestData, files);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### 4. getRequest(requestId)
|
|
163
|
+
|
|
164
|
+
Lấy thông tin request theo ID.
|
|
165
|
+
|
|
166
|
+
**Parameters:**
|
|
167
|
+
- `requestId` (string): ID của request
|
|
168
|
+
|
|
169
|
+
**Returns:** `Promise<Object>`
|
|
170
|
+
|
|
171
|
+
**Ví dụ:**
|
|
172
|
+
```javascript
|
|
173
|
+
const requestInfo = await apiService.getRequest('18391');
|
|
174
|
+
console.log(requestInfo);
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 5. mapPriority(priority)
|
|
178
|
+
|
|
179
|
+
Helper method để map priority từ form widget sang format API.
|
|
180
|
+
|
|
181
|
+
**Parameters:**
|
|
182
|
+
- `priority` (string): 'low', 'medium', 'high', 'none'
|
|
183
|
+
|
|
184
|
+
**Returns:** `string`
|
|
185
|
+
|
|
186
|
+
**Ví dụ:**
|
|
187
|
+
```javascript
|
|
188
|
+
const priority = apiService.mapPriority('high'); // Trả về: 'Cao'
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 6. mapCategory(category)
|
|
192
|
+
|
|
193
|
+
Helper method để map category từ form widget sang format API.
|
|
194
|
+
|
|
195
|
+
**Parameters:**
|
|
196
|
+
- `category` (string): Category từ form
|
|
197
|
+
|
|
198
|
+
**Returns:** `string | null`
|
|
199
|
+
|
|
200
|
+
**Ví dụ:**
|
|
201
|
+
```javascript
|
|
202
|
+
const category = apiService.mapCategory('hardware');
|
|
203
|
+
// Trả về: 'A01A00 - Quản lý an toàn thông tin'
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### 7. buildRequestData(formData, options)
|
|
207
|
+
|
|
208
|
+
Build request data từ form data của widget sang format API.
|
|
209
|
+
|
|
210
|
+
**Parameters:**
|
|
211
|
+
- `formData` (Object): Dữ liệu từ form widget
|
|
212
|
+
- `title`: string
|
|
213
|
+
- `description`: string
|
|
214
|
+
- `category`: string
|
|
215
|
+
- `priority`: string
|
|
216
|
+
- `contact`: string
|
|
217
|
+
- `options` (Object): Options bổ sung
|
|
218
|
+
- `requesterName`: string
|
|
219
|
+
- `site`: string
|
|
220
|
+
- `udf_fields`: object
|
|
221
|
+
- `zia_properties`: object
|
|
222
|
+
- `template`: string
|
|
223
|
+
- `item`: string
|
|
224
|
+
- `subcategory`: string
|
|
225
|
+
|
|
226
|
+
**Returns:** `Object`
|
|
227
|
+
|
|
228
|
+
**Ví dụ:**
|
|
229
|
+
```javascript
|
|
230
|
+
const formData = {
|
|
231
|
+
title: 'Test Request',
|
|
232
|
+
description: 'Test description',
|
|
233
|
+
category: 'hardware',
|
|
234
|
+
priority: 'none',
|
|
235
|
+
contact: 'test@example.com'
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const requestData = apiService.buildRequestData(formData, {
|
|
239
|
+
requesterName: 'Người dùng',
|
|
240
|
+
site: 'Your Site Name',
|
|
241
|
+
udf_fields: {
|
|
242
|
+
udf_pick_301: 'Value 1'
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Cấu trúc Request Data
|
|
248
|
+
|
|
249
|
+
### Đầy đủ các trường:
|
|
250
|
+
|
|
251
|
+
```javascript
|
|
252
|
+
{
|
|
253
|
+
requester: {
|
|
254
|
+
name: string
|
|
255
|
+
},
|
|
256
|
+
assets: [],
|
|
257
|
+
category: {
|
|
258
|
+
name: string
|
|
259
|
+
} | null,
|
|
260
|
+
group: string | null,
|
|
261
|
+
subcategory: {
|
|
262
|
+
name: string
|
|
263
|
+
} | null,
|
|
264
|
+
technician: string | null,
|
|
265
|
+
item: {
|
|
266
|
+
name: string
|
|
267
|
+
} | null,
|
|
268
|
+
priority: {
|
|
269
|
+
name: string // 'Thấp', 'Trung bình', 'Cao', 'Khẩn cấp'
|
|
270
|
+
},
|
|
271
|
+
subject: string,
|
|
272
|
+
description: string, // HTML string
|
|
273
|
+
site: {
|
|
274
|
+
name: string
|
|
275
|
+
} | null,
|
|
276
|
+
attachments: [],
|
|
277
|
+
udf_fields: {
|
|
278
|
+
udf_pick_301: string,
|
|
279
|
+
udf_pick_302: string,
|
|
280
|
+
// ... các custom fields khác
|
|
281
|
+
},
|
|
282
|
+
template: {
|
|
283
|
+
name: string
|
|
284
|
+
} | null,
|
|
285
|
+
zia_properties: {}
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Error Handling
|
|
290
|
+
|
|
291
|
+
Tất cả các methods đều throw Error nếu có lỗi:
|
|
292
|
+
|
|
293
|
+
```javascript
|
|
294
|
+
try {
|
|
295
|
+
const response = await apiService.createRequest(requestData);
|
|
296
|
+
} catch (error) {
|
|
297
|
+
console.error('Error:', error.message);
|
|
298
|
+
// error.message có thể là:
|
|
299
|
+
// - "API Key không hợp lệ."
|
|
300
|
+
// - "HTTP error! status: 400"
|
|
301
|
+
// - hoặc các thông báo lỗi khác
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## API Endpoints
|
|
306
|
+
|
|
307
|
+
### 1. Tạo Request
|
|
308
|
+
- **URL:** `POST {baseUrl}/{tenant}/send`
|
|
309
|
+
- **Headers:**
|
|
310
|
+
- `authtoken`: API key
|
|
311
|
+
- `pn`: Tenant name
|
|
312
|
+
- `Content-Type`: `multipart/form-data` (auto)
|
|
313
|
+
- **Body:** FormData với key `input_data` chứa JSON string
|
|
314
|
+
|
|
315
|
+
### 2. Upload Attachment
|
|
316
|
+
- **URL:** `PUT {baseUrl}/{tenant}/{id}/upload`
|
|
317
|
+
- **Headers:**
|
|
318
|
+
- `authtoken`: API key
|
|
319
|
+
- `pn`: Tenant name
|
|
320
|
+
- `Content-Type`: `multipart/form-data` (auto)
|
|
321
|
+
- **Body:** FormData với các file
|
|
322
|
+
|
|
323
|
+
### 3. Get Request
|
|
324
|
+
- **URL:** `GET {baseUrl}/{tenant}/{id}`
|
|
325
|
+
- **Headers:**
|
|
326
|
+
- `authtoken`: API key
|
|
327
|
+
- `pn`: Tenant name
|
|
328
|
+
- `Accept`: `application/json`
|
|
329
|
+
|
|
330
|
+
## Xem thêm
|
|
331
|
+
|
|
332
|
+
- Xem tài liệu API đầy đủ tại: `src/assets/13082025 API v2 SDP ITSM SPC.doc`
|
|
333
|
+
- Xem ví dụ sử dụng widget tại: [example.html](./example.html)
|
|
334
|
+
|