# Vue Plugins & Tiện ích mở rộng

Tài liệu chi tiết về tất cả Vue plugins, global components, filters, mixins được sử dụng trong AutoShopee Kit.

## Thứ tự đăng ký Plugin (Popup Entry)

Trong `src/popup/main.js`, các plugin được đăng ký theo thứ tự:

```
1. VueCompositionAPI   — Polyfill Composition API cho Vue 2
2. VTooltip            — Tooltip directive
3. mixin               — Global mixins + filters (src/app/mixin/)
4. pluginLoader         — Global components + third-party plugins (src/app/plugins/loader.js)
5. store (Vuex)        — State management
6. VueRouter           — Routing
7. VueLazyload         — Lazy load ảnh
8. i18n (VueI18n)      — Đa ngôn ngữ
9. Pinia               — State management bổ sung
```

---

## Vue Plugins (`src/app/plugins/`)

### Plugin Loader (`src/app/plugins/loader.js`)

| Thuộc tính | Chi tiết |
|------------|----------|
| File | `src/app/plugins/loader.js` |
| Đăng ký | `Vue.use(pluginLoader)` trong `src/popup/main.js` |
| Chức năng | Plugin tổng hợp: đăng ký global components, cài đặt third-party plugins |

**Cách hoạt động:**
- Export object có method `install(Vue)` (Vue plugin pattern chuẩn)
- Bên trong `install()` thực hiện:
  - Đăng ký 14 global components qua `Vue.component()`
  - Cài đặt VueClipboard, ViewUI, VueI18n, VueMeta qua `Vue.use()`
  - Import CSS: Font Awesome 4, View Design (iView), app styles

**Global Components được đăng ký:**

| Component | Source | Mục đích |
|-----------|--------|----------|
| `WrapProfileActive` | `@/components/Plugin/WrapProfileActive.vue` | Wrapper kiểm tra profile đang active |
| `WrapRequireAuth` | `@/components/Plugin/WrapRequireAuth.vue` | Wrapper yêu cầu đăng nhập |
| `WrapRequirePaid` | `@/components/Plugin/WrapRequirePaid.vue` | Wrapper yêu cầu gói trả phí |
| `BoxLayout` | `@/components/Layout/Box.vue` | Layout dạng box |
| `LayoutSingle` | `@/components/Layout/Single.vue` | Layout đơn (single page) |
| `LoadingApp` | `@/components/Plugin/LoadingApp.vue` | Loading toàn app |
| `LoadingBox` | `@/components/Plugin/LoadingBox.vue` | Loading trong box/section |
| `AlertVip` | `@/components/Plugin/AlertVip.vue` | Thông báo yêu cầu VIP |
| `AlertPlus` | `@/components/Plugin/AlertVip.vue` | Thông báo yêu cầu Plus (cùng component với AlertVip) |
| `InputTag` | `vue-input-tag` | Input dạng tags (third-party) |
| `InputSwitch` | `vue-switches` | Toggle switch (third-party) |
| `CheckAll` | `@/components/Plugin/CheckAll.vue` | Checkbox chọn tất cả |
| `NotifyApp` | `@/components/Plugin/NotifyApp.vue` | Hiển thị thông báo ứng dụng |
| `ShopeeSellerConnect` | `@/components/Plugin/ShopeeSellerConnect.vue` | Kết nối shop Shopee Seller |

**Third-party plugins được cài trong loader:**

| Plugin | Cấu hình |
|--------|----------|
| `vue-clipboard2` | Mặc định (không cấu hình) |
| `view-design` | `transfer: true`, `size: 'default'`, `capture: false`, locale: `vi-VN` |
| `vue-i18n` | Mặc định |
| `vue-meta` | Mặc định |

**Phụ thuộc:** `view-design`, `vue-i18n`, `vue-clipboard2`, `vue-input-tag`, `vue-meta`, `vue-switches`

---

### i18n Plugin (`src/app/plugins/i18n/`)

| Thuộc tính | Chi tiết |
|------------|----------|
| File chính | `src/app/plugins/i18n/vue.js` (Vue), `src/app/plugins/i18n/index.js` (standalone) |
| Đăng ký | Tạo instance `VueI18n` rồi truyền vào `new Vue({ i18n })` |
| Chức năng | Hỗ trợ đa ngôn ngữ (hiện tại chỉ tiếng Việt) |

**Cấu trúc thư mục:**
```
src/app/plugins/i18n/
  index.js    — Instance i18n-js (standalone, dùng ngoài Vue context)
  vue.js      — Factory tạo VueI18n instance
  config.js   — Cấu hình dateTimeFormats
  lang/
    index.js  — Export ngôn ngữ mặc định và source
    vi.json   — Bản dịch tiếng Việt
```

**Hai instance i18n:**

1. **VueI18n** (`vue.js`): Dùng trong Vue components qua `this.$t()`, `this.$d()`
   - `locale`: `'vi'`
   - `fallbackLocale`: `'vi'`
   - `dateTimeFormats`: Định dạng ngày cho locale `vi` (short, onlyDate, long)

2. **i18n-js** (`index.js`): Dùng ngoài Vue context (background, services, models)
   - Instance của class `I18n` từ thư viện `i18n-js`
   - Cùng source ngôn ngữ với VueI18n

**Cấu hình dateTimeFormats** (`config.js`):

| Format | Hiển thị |
|--------|----------|
| `short` | Ngày, tháng (short), năm |
| `onlyDate` | Ngày/tháng/năm (2-digit) |
| `long` | Ngày, tháng, năm, giờ, phút |

**Phụ thuộc:** `vue-i18n@8.26.5`, `i18n-js`

---

### Logger Plugin (`src/app/plugins/logger.js`)

| Thuộc tính | Chi tiết |
|------------|----------|
| File | `src/app/plugins/logger.js` |
| Đăng ký | Không đăng ký qua `Vue.use()` — import trực tiếp khi cần |
| Chức năng | Hệ thống logging có phân loại, màu sắc, ID tracking |

**Cách hoạt động:**
- Dựa trên thư viện `loglevel`, mở rộng thêm:
  - Log ID tự động (format `LOG-{timestamp}-{counter}`)
  - Màu sắc theo category (shopee: cam, worker: xanh lá, api: xanh dương, vue: xanh nhạt, content: vàng)
  - Lưu trữ log trong `Map` để truy vấn sau
  - Tắt/bật log dựa trên biến `isShowLogger` từ env config
- Mỗi logger tạo bằng factory `createLogger(name, prefix)`

**Các logger instances được export:**

| Logger | Category | Sử dụng cho |
|--------|----------|-------------|
| `loggerShopee` | shopee | Logic Shopee |
| `loggerTiktok` | tiktok | Logic TikTok |
| `loggerLazada` | lazada | Logic Lazada |
| `loggerApi` | api | HTTP API calls |
| `loggerVue` | vue | Vue components & lifecycle |
| `loggerContent` | content | Content scripts |
| `loggerPlugin` | plugin | Plugins (KV, setting, etc.) |
| `loggerModel` | model | Data models |
| `loggerWorker` | worker | Background workers |
| `loggerBackground` | background | Background script |

**API mở rộng trên mỗi logger:**

| Method | Mô tả |
|--------|-------|
| `logger.withId(logId)` | Tạo child logger gắn log ID cố định |
| `logger.getLogById(logId)` | Lấy log entry theo ID |
| `logger.filterByCategory(category)` | Lọc tất cả log theo category |
| `logger.getAllLogs()` | Lấy toàn bộ log đã lưu |
| `logger.clearLogs()` | Xóa tất cả log đã lưu |

**Phụ thuộc:** `loglevel@1.9.2`

---

### KV Store Plugin (`src/app/plugins/kv/`)

| Thuộc tính | Chi tiết |
|------------|----------|
| File chính | `src/app/plugins/kv/index.js` |
| Đăng ký | Không đăng ký qua `Vue.use()` — import trực tiếp |
| Chức năng | Key-Value store từ xa (remote), hỗ trợ TTL, mã hóa, lock/unlock |

**Cấu trúc thư mục:**
```
src/app/plugins/kv/
  index.js    — Export các KV store instances
  adapter.js  — HTTP adapter gọi API KV server
  api.js      — Factory tạo KV store class
  config.js   — Cấu hình các KV store
```

**KvApiAdapter** (`adapter.js`):
- HTTP client gọi API KV server (endpoint từ env `KV_API`)
- Sử dụng `axios` với `@vespaiach/axios-fetch-adapter` (tương thích Service Worker)
- Các method: `set`, `get`, `del`, `exists`, `info`, `setTtl`, `lock`, `unlock`, `getLockState`

**initKvStore** (`api.js`):
- Factory function nhận `KvConfig`, trả về class `KvStoreApi`
- Mỗi instance `KvStoreApi` đại diện cho 1 key cụ thể
- Key được hash bằng SHA-256, format: `kv:autoshopee-kit:{rootKey}:{userId|global}:{sha256(key)}`
- Hỗ trợ mã hóa key (crypt) và validation bằng AJV schema

**Các KV Store instances** (`index.js`):

| Instance | Root Key | TTL | Scope | Mục đích |
|----------|----------|-----|-------|----------|
| `KVStoreCache` | `cache-global` | 60s | Per-user | Cache chung |
| `KVCheckLock` | `check-lock` | 30s | Per-user | Kiểm tra lock trạng thái |
| `KVShopeeProductStock` | `shopee-product-stock` | 1 giờ | Global | Cache tồn kho sản phẩm Shopee |
| `KVShopeeMarketingSenderCustomer` | `shopee-marketing-sender-customer` | 30 ngày | Global | Theo dõi khách hàng đã gửi tin nhắn marketing |

**Phụ thuộc:** `axios`, `@vespaiach/axios-fetch-adapter`, `sha256`, `ajv`

---

### Setting Plugin (`src/app/plugins/setting/`)

| Thuộc tính | Chi tiết |
|------------|----------|
| File chính | `src/app/plugins/setting/index.js` |
| Đăng ký | Không đăng ký qua `Vue.use()` — import trực tiếp |
| Chức năng | Quản lý cài đặt ứng dụng qua localStorage + browser extension storage |

**Cấu trúc thư mục:**
```
src/app/plugins/setting/
  index.js    — Export các setting groups
  setting.js  — Định nghĩa key, type, default value cho từng setting
  api.js      — Factory apiLocalSetting() và clearAllSetting()
```

**apiLocalSetting** (`api.js`):
- Factory nhận config `{key, type, defaultVal}`
- Hỗ trợ các type: `string`, `bool`, `number`, `json`
- Ưu tiên localStorage (nếu có), fallback sang browser extension storage
- Parse/serialize tự động theo type
- Trả về object API:

| Method | Mô tả |
|--------|-------|
| `get()` | Đọc giá trị (sync từ localStorage) |
| `set(value)` | Ghi giá trị vào cả localStorage và extension storage |
| `remove()` | Xóa giá trị |
| `reset()` | Reset về giá trị mặc định |
| `getSync()` | Đọc giá trị bất đồng bộ (từ extension storage) |
| `useStorage()` | Reactive ref qua `@vueuse/core` `useStorage()` |

**Các nhóm setting** (`index.js`):

| Nhóm | Các key | Mô tả |
|------|---------|-------|
| `appSetting` | `usePopup`, `useShopManager`, `readNotifyId`, `extensionInfo`, `platformShopConfig`, `betaMode`, `workerFetchService`, `toggleMenu`, `badWord` | Cài đặt chung ứng dụng |
| `userSetting` | `userId`, `userToken`, `userExtensionPlan`, `userName`, `userPassword`, `userData` | Thông tin người dùng |
| `indentifySetting` | `databaseId`, `appUuid`, `profileId`, `fingerprintId`, `browserIp`, `browserAgent`, `browserName`, `browserPlatform` | Định danh thiết bị/trình duyệt |
| `shopeeSetting` | Affiliate (`shopeeAffId`, `shopeeAffToken`, ...), Shop (`shopeeShopId`, `shopeeShopName`, ...), Product, Flashsale | Cài đặt Shopee |
| `tiktokSetting` | `tiktokShopId`, `tiktokShopName` | Cài đặt TikTok |
| `lazadaSetting` | `lazadaShopId`, `lazadaShopName` | Cài đặt Lazada |
| `tracerAfSetting` | `affTrackingShopeeTime`, `affTrackingLazadaTime`, `affTrackingTikiTime` | Tracking thời gian affiliate |
| `platformSetting` | `saveHistoryPrint` | Cài đặt nền tảng |

**Phụ thuộc:** `@vueuse/core`, `parse-js`, browser storage API

---

### Store Cache Plugin (`src/app/plugins/store/`)

| Thuộc tính | Chi tiết |
|------------|----------|
| File chính | `src/app/plugins/store/cache.js` |
| Đăng ký | Không đăng ký qua `Vue.use()` — import trực tiếp |
| Chức năng | Cache cục bộ (local) sử dụng IndexedDB qua localForage, hỗ trợ TTL và mã hóa AES |

**setupCache** (`api.js`):
- Factory nhận `(cacheKey, ttlDefault, cryptKey)`
- Tạo `localForage` instance riêng cho mỗi cache
- Key được hash bằng SHA-256
- Hỗ trợ mã hóa AES nếu cung cấp `cryptKey`
- Trả về class `CacheStore` với các method: `get`, `set`, `remove`, `destroy` (static)

**Các Cache instances** (`cache.js`):

| Instance | TTL | Mã hóa | Mục đích |
|----------|-----|--------|----------|
| `CacheFetchUrl` | 10 phút | Không | Cache URL fetch |
| `CacheCmsContent` | 5 phút | Không | Cache nội dung CMS |
| `CacheCouchDbConnect` | 6 giờ | AES (`couchdb-auth-session`) | Cache phiên CouchDB |
| `CacheShopeeSellerProductTime` | 10 phút | Không | Thời gian cập nhật sản phẩm seller |
| `CacheShopeeSellerProductList` | 5 phút | Không | Danh sách sản phẩm seller |
| `CacheShopeeSellerProductId` | 2 phút | Không | Sản phẩm theo ID |
| `CacheShopeeAtrribute` | 5 phút | Không | Thuộc tính sản phẩm Shopee |
| `CacheShopeeProduct` | 10 phút | Không | Sản phẩm Shopee |
| `CacheShopeeStock` | 1 giờ | Không | Tồn kho Shopee |
| `CacheShopeeShop` | 1 giờ | Không | Thông tin shop |
| `CacheShopeeShopSearch` | 5 giờ | Không | Kết quả tìm shop |
| `CacheShopeeProductSearch` | 5 giờ | Không | Kết quả tìm sản phẩm |
| `CacheShopeeReview` | 1 giờ | Không | Đánh giá sản phẩm |
| `CacheShopeeAny` | 60 giây | Không | Cache tạm Shopee |
| `CacheShopeeSellerConfig` | 10 phút | Không | Cấu hình seller |
| `CacheTiktokProductId` | 10 phút | Không | Sản phẩm TikTok theo ID |
| `CacheTiktokProductSearch` | 10 phút | Không | Tìm sản phẩm TikTok |
| `CacheTiktokImageShopee` | 24 giờ | Không | Ảnh TikTok chuyển sang Shopee |
| `CacheOrderPdfBuffer` | 1 giờ | Không | Buffer PDF đơn hàng |

**Phụ thuộc:** `localforage`, `crypto-js`

---

### Validator Plugin (`src/app/plugins/validator/`)

| Thuộc tính | Chi tiết |
|------------|----------|
| File chính | `src/app/plugins/validator/ajv.js`, `src/app/plugins/validator/joi.js` |
| Đăng ký | Không đăng ký qua `Vue.use()` — import trực tiếp |
| Chức năng | Validation dữ liệu bằng AJV (JSON Schema) và Joi |

**AJV Validator** (`ajv.js`):
- Instance `Ajv` với `coerceTypes: true`
- Đã cài `ajv-formats` (hỗ trợ format: email, uri, date, etc.)
- Dùng chủ yếu trong KV Store để validate schema

**Joi Validator** (`joi.js`):
- Instance Joi với config mặc định từ `config.js`
- Toàn bộ error messages được dịch sang tiếng Việt
- Hỗ trợ messages cho: `number`, `string`, `object`, `array`, `boolean`, `date`, `function`, `alternatives`, `any`, `binary`, `symbol`

**API export** (`api.js`): Re-export `joiValidator` từ thư viện `joi` (không có logic bổ sung)

**Phụ thuộc:** `ajv@8.17.1`, `ajv-formats`, `joi@17.13.3`

---

### Image Plugin (`src/app/plugins/image.js`)

| Thuộc tính | Chi tiết |
|------------|----------|
| File | `src/app/plugins/image.js` |
| Đăng ký | Không đăng ký qua `Vue.use()` — import trực tiếp |
| Chức năng | Xử lý ảnh: watermark, thay đổi MD5, chuyển đổi format |

**Các hàm được export:**

| Hàm | Mô tả |
|-----|-------|
| `extractBas64Image(base64)` | Loại bỏ prefix `data:image/jpeg;base64,` |
| `appendBase64Image(base64)` | Thêm prefix base64 cho JPEG |
| `base64ImageToBlob(base64)` | Chuyển base64 image sang Blob |
| `changeImageMd5(imageUrl)` | Thay đổi MD5 của ảnh bằng cách sửa pixel ngẫu nhiên + watermark ẩn |
| `getImageSize(imageUrl)` | Lấy kích thước ảnh (width, height) |
| `watermarkImageFrame(source, layer, size)` | Ghép ảnh watermark frame lên ảnh gốc |

**Config:**
- `wartermarkConfig.productImage`: URL khung ảnh sản phẩm (CDN)
- `wartermarkConfig.noImage`: URL ảnh placeholder upload (CDN)

**Phụ thuộc:** `jimp`, `random`

---

### Dev Plugin (`src/app/plugins/dev.js`)

| Thuộc tính | Chi tiết |
|------------|----------|
| File | `src/app/plugins/dev.js` |
| Đăng ký | Gọi `devLoader()` trong `src/popup/main.js` khi `isDevMode === true` |
| Chức năng | Expose model API ra `window._devModelApi` để debug trong console |

**Chỉ hoạt động ở chế độ development.** Hiện tại expose:
- `ShopeeSpyList` — Model danh sách spy Shopee

**Phụ thuộc:** `@/models/shopee/spy`

---

## Custom Directives (`src/app/directives/`)

Dự án **không có** thư mục `src/app/directives/` và không đăng ký custom directive nào qua `Vue.directive()`.

Các directive được sử dụng đều đến từ third-party plugins:
- `v-tooltip` — từ `v-tooltip` package
- `v-lazy` — từ `vue-lazyload` package
- View Design directives (v-transfer-dom, etc.)

---

## Custom Filters (`src/app/filters/`)

Dự án **không có** thư mục `src/app/filters/` riêng. Filters được đăng ký trong mixin loader (`src/app/mixin/index.js`) qua `Vue.filter()`.

**Source:** `src/app/mixin/filter.js`

| Filter | Mô tả | Ví dụ |
|--------|-------|-------|
| `maxString(str, max)` | Cắt chuỗi nếu vượt quá `max` ký tự, thêm `...` | `{{ text \| maxString(50) }}` |
| `formatDate(dateStr)` | Format ngày theo locale `vi-VN` | `{{ date \| formatDate }}` |
| `addCommas(number)` | Thêm dấu phẩy phân cách hàng nghìn | `{{ price \| addCommas }}` |

---

## Global Mixins (`src/app/mixin/`)

Mixin được đăng ký dưới dạng Vue plugin tại `src/app/mixin/index.js`, cài đặt qua `Vue.use(mixin)`.

### Mixin Index (`src/app/mixin/index.js`)

Plugin entry point, trong `install(Vue)` thực hiện:
1. `Vue.mixin(global)` — Đăng ký global mixin
2. `Vue.mixin(store)` — Đăng ký store mixin
3. `Vue.filter(...)` — Đăng ký tất cả filters từ `filter.js`

---

### Global Mixin (`src/app/mixin/global.js`)

| Thuộc tính | Chi tiết |
|------------|----------|
| File | `src/app/mixin/global.js` |
| Phạm vi | Tất cả Vue components |

**Data properties (có sẵn trong mọi component):**

| Property | Type | Mô tả |
|----------|------|-------|
| `isUsePopup` | `boolean` | Extension đang chạy ở chế độ popup hay không |
| `configApp` | `object` | Cấu hình ứng dụng |
| `configAppApi` | `object` | Cấu hình API |
| `isDevMode` | `boolean` | Đang ở chế độ development |
| `loggerVue` | `Logger` | Logger instance cho Vue |
| `loggerApi` | `Logger` | Logger instance cho API (alias của loggerVue) |
| `shopeeSpyEnabled` | `boolean` | Tính năng spy Shopee có bật không |

**Methods (có sẵn trong mọi component):**

| Method | Mô tả |
|--------|-------|
| `openPopupUrl(url)` | Mở URL trong popup extension |
| `createPopupUrl(path)` | Tạo URL popup từ path |
| `getTabCurrent()` | Lấy tab hiện tại |
| `reloadTabCurrent()` | Reload tab hiện tại |
| `openExternalUrl(url)` | Mở URL ngoài (tab mới) |

**Computed (có sẵn trong mọi component):**

| Computed | Mô tả |
|----------|-------|
| `layoutBox` | Style object cho box layout (height + overflow) |
| `layoutFooter` | Style object cho layout có footer |

---

### Store Mixin (`src/app/mixin/store.js`)

| Thuộc tính | Chi tiết |
|------------|----------|
| File | `src/app/mixin/store.js` |
| Phạm vi | Tất cả Vue components |

Map toàn bộ Vuex actions và getters vào mọi component.

**Actions (methods) được map:**

| Action | Mô tả |
|--------|-------|
| `UseScoreClone` | Sử dụng điểm clone |
| `UserFetch` | Lấy thông tin user |
| `UserLogin` | Đăng nhập |
| `UserLogout` | Đăng xuất |
| `AppInitUrl` | Khởi tạo URL ứng dụng |
| `SetAppTitle` | Đặt tiêu đề ứng dụng |
| `SetTabActive` | Đặt tab active |
| `SetUseShopManager` | Bật/tắt Shop Manager |
| `ShopeeSellerInit` | Khởi tạo Shopee Seller |
| `ShopeeGetProduct` | Lấy sản phẩm Shopee |
| `ShopeeKeywordAdd` | Thêm từ khóa Shopee |
| `ShopeeKeywordFetch` | Lấy danh sách từ khóa |
| `SetAppLoading` | Bật/tắt loading |
| `SetMenuActive` | Đặt menu active |
| `SetRouterCurrent` | Đặt router hiện tại |
| `SetRouterHistory` | Đặt lịch sử router |
| `RouterBack` | Quay lại |
| `RouterTo` | Điều hướng đến |
| `Router404` | Điều hướng 404 |
| `RouterLogin` | Điều hướng login |
| `RouterPath` | Điều hướng theo path |

**Getters (computed) được map:** `getListPlatform`, `getUseShopManager`, `getProfileId`, `getUserProfileId`, `getUserProfileActive`, `getBrowserIp`, `getShopeeShopRef`, `getShopeeShopImage`, `getShopeeShopId`, `getShopeeShopName`, `getShopeeKeywordCollection`, `getShopeeSellerAuthed`, `getUrlCurrent`, `getRouterCurrent`, `getRouterHistory`, `getNotifyApp`, `getNotifyBanner`, `getAppInfo`, `getUserId`, `getToken`, `getIsVipPlus`, `getUsageGptWriter`, `getRouterUrl`, `getIsPaidVip`, `getIsPaidPlan`, `getIsAuthed`, `getUserPlan`, `getScoreClone`, `getTimeExpried`, `getUsername`, `getAppTitle`, `getPassword`, `getUserData`, `getTabActive`, `getProductShopeeLoaded`, `getProductShopee`, `getAppLoading`, `getMenuActive`, `getBetaMode`

---

### Menu Mixin (`src/app/mixin/menu.js`)

| Thuộc tính | Chi tiết |
|------------|----------|
| File | `src/app/mixin/menu.js` |
| Phạm vi | Không phải global — import thủ công khi cần |

**Methods:**
- `openMenu({ to, external, key, isNewTab })` — Xử lý điều hướng menu: mở URL ngoài, mở popup, hoặc router push

**Computed:**
- `labelMenu` — Label hiển thị cho dropdown menu (có gắn trạng thái login)
- `listMenu` — Danh sách menu items của ứng dụng (Shopee, TikTok, Setting, Printer, etc.)

---

## Third-party Vue Plugins

### View Design (iView) 4.2.0

| Thuộc tính | Chi tiết |
|------------|----------|
| Import | `view-design` |
| Đăng ký | `Vue.use(ViewUI, config)` trong `loader.js` và `src/content/service/vue.js` |
| Locale | `view-design/dist/locale/vi-VN` (tiếng Việt) |

**Cấu hình:**
```js
{
  transfer: true,        // Render dropdown/modal vào body
  size: 'default',       // Kích thước component mặc định
  capture: false,        // Không capture event
  select: {
    arrow: 'md-arrow-dropdown',
    arrowSize: 20,
  },
  locale: vi-VN,         // Tiếng Việt
}
```

Cung cấp toàn bộ UI components: Button, Table, Modal, Form, Menu, Select, DatePicker, etc.

---

### vue-i18n 8.26.5

| Thuộc tính | Chi tiết |
|------------|----------|
| Import | `vue-i18n` |
| Đăng ký | `Vue.use(VueI18n)` trong `loader.js`, instance truyền vào Vue root |
| Locale mặc định | `vi` |

Cung cấp:
- `this.$t(key)` — Dịch chuỗi
- `this.$d(date, format)` — Format ngày theo locale
- `this.$i18n` — Truy cập instance i18n

---

### VueRouter 3.5.1

| Thuộc tính | Chi tiết |
|------------|----------|
| Import | `vue-router` |
| Đăng ký | `Vue.use(VueRouter)` trong `src/popup/main.js` |
| Cấu hình | `src/app/router/index.js` |

Middleware (`src/app/router/middleware.js`):
- NProgress cho progress bar khi chuyển trang
- Khởi tạo store, kiểm tra auth Shopee, chạy task flashsale tự động
- Service Worker keep-alive

---

### Vuex 3.6.2

| Thuộc tính | Chi tiết |
|------------|----------|
| Import | `vuex` |
| Đăng ký | `Vue.use(Vuex)` trong `src/app/store/index.js`, instance qua `Vue.use(store)` |
| Persist | `vuex-persistedstate` |

---

### Pinia 2.1.7

| Thuộc tính | Chi tiết |
|------------|----------|
| Import | `pinia` |
| Đăng ký | `Vue.use(PiniaVuePlugin)` trong `src/app/pinia/setup.js` |
| Persist | `pinia-plugin-persistedstate` |
| Setup | Truyền `pinia: usePinia` vào Vue root instance |

---

### @vue/composition-api

| Thuộc tính | Chi tiết |
|------------|----------|
| Import | `@vue/composition-api` |
| Đăng ký | `Vue.use(VueCompositionAPI)` trong `src/popup/main.js` |
| Chức năng | Polyfill Composition API cho Vue 2 (dùng cho `defineComponent`, `@vueuse/core`) |

---

### v-tooltip

| Thuộc tính | Chi tiết |
|------------|----------|
| Import | `v-tooltip` |
| Đăng ký | `Vue.use(VTooltip)` trong `src/popup/main.js` |
| Chức năng | Directive `v-tooltip` cho tooltip trên elements |

---

### vue-lazyload

| Thuộc tính | Chi tiết |
|------------|----------|
| Import | `vue-lazyload` |
| Đăng ký | `Vue.use(VueLazyload, config)` trong `src/popup/main.js` |

**Cấu hình:**
```js
{
  preLoad: 1.3,           // Tải trước khi element vào viewport
  error: errorimage,      // Ảnh hiển thị khi lỗi (error.gif)
  loading: loadimage,     // Ảnh hiển thị khi đang tải (loading.gif)
  attempt: 1,             // Số lần thử tải lại
}
```

---

### vue-clipboard2

| Thuộc tính | Chi tiết |
|------------|----------|
| Import | `vue-clipboard2` |
| Đăng ký | `Vue.use(VueClipboard)` trong `loader.js` |
| Chức năng | Directive `v-clipboard` và method `this.$copyText()` để copy text vào clipboard |

---

### vue-meta 2.4.0

| Thuộc tính | Chi tiết |
|------------|----------|
| Import | `vue-meta` |
| Đăng ký | `Vue.use(VueMeta)` trong `loader.js` |
| Chức năng | Quản lý document head (title, meta tags) qua `metaInfo()` trong component |

---

## Đăng ký Plugin trong Content Scripts

Content scripts (`src/content/service/vue.js`) đăng ký plugin riêng, nhẹ hơn popup:

| Plugin | Có đăng ký |
|--------|-----------|
| View Design (iView) | Co (cùng cấu hình với popup) |
| VueI18n | Co |
| VueRouter | Khong |
| Vuex | Khong |
| Pinia | Khong |
| VueLazyload | Khong |
| VTooltip | Khong |
| VueMeta | Khong |

Content scripts cũng load CSS từ CDN (iView CSS, Font Awesome 4) thay vì bundle.
