# Base Components > Base Vue 3 components built on Element Plus. --- ## Overview The `packages/base/` directory provides foundational Vue 3 components that wrap Element Plus components with theme integration, i18n support, and consistent prop patterns. ### Architecture ``` packages/base/ ├── index.ts # Exports all base components ├── item/ # Basic UI elements │ ├── tag.vue │ ├── button.vue │ ├── select.vue │ ├── input.vue │ ├── datetime.vue │ ├── light-box.vue │ ├── buttonWithTooltip.vue │ ├── confirmCancel.vue │ ├── tzDatePicker.vue │ ├── tzDateTime.vue │ └── ws-monitor-toggle.vue └── data/ # Data-driven components ├── search-row.vue ├── list-table.vue ├── listTableDialog.vue ├── infomation.vue ├── modify-form.vue ├── descriptions.vue └── table-action.vue ``` --- ## Item Components ### NoobTag Wraps `el-tag` with theme integration. **File**: `packages/base/item/tag.vue` **Props**: | Prop | Type | Default | Description | |------|------|---------|-------------| | `type` | `string` | `null` | Element Plus tag type | | `color` | `string` | `null` | Custom color | | `closable` | `boolean` | `false` | Show close button | | `round` | `boolean` | `false` | Round style | | `effect` | `string` | `'light'` | Tag effect (light/dark/plain) | **Usage**: ```vue Active Custom Removable ``` --- ### NoobButton Wraps `el-button` with theme integration and slot content detection. **File**: `packages/base/item/button.vue` **Props**: | Prop | Type | Default | Description | |------|------|---------|-------------| | `type` | `string` | `null` | Button type (primary/success/warning/danger/info) | | `icon` | `string` | `null` | Icon name | | `disabled` | `boolean` | `false` | Disabled state | | `plain` | `boolean` | `false` | Plain style | | `round` | `boolean` | `false` | Round style | | `circle` | `boolean` | `false` | Circle style (icon-only) | | `loading` | `boolean` | `false` | Loading state | | `text` | `boolean` | `false` | Text button | | `link` | `boolean` | `false` | Link button | **Usage**: ```vue Add Saving... ``` **Note**: Automatically detects if slot content exists before rendering, handling empty slots in circle buttons. --- ### NoobSelect Wraps `el-select` with Vuex dict integration and width management. **File**: `packages/base/item/select.vue` **Props**: | Prop | Type | Default | Description | |------|------|---------|-------------| | `modelValue` | `any` | `-` | v-model value | | `placeholder` | `string` | `i18n: rule.pleaseSelect` | Placeholder text | | `disabled` | `boolean` | `false` | Disabled state | | `clearable` | `boolean` | `true` | Show clear button | | `filterable` | `boolean` | `true` | Enable search | | `full` | `boolean` | `false` | 100% width | | `width` | `number` | `-` | Fixed width in px | | `dict` | `string` | `-` | Vuex dict key for options | | `stateProp` | `string` | `-` | Vuex state property for options | | `maxValue` | `number` | `-` | Generate 1-N options | | `valueKey` | `string` | `'key'` | Option value key | | `labelKey` | `string` | `'value'` | Option label key | | `remote` | `boolean` | `false` | Enable remote search | | `remoteMethod` | `function` | `null` | Remote search function | **Usage**: ```vue ``` --- ### NoobInput Wraps `el-input` with width management and label prepend support. **File**: `packages/base/item/input.vue` **Props**: | Prop | Type | Default | Description | |------|------|---------|-------------| | `modelValue` | `any` | `-` | v-model value | | `label` | `string` | `null` | Prepend label | | `placeholder` | `string` | `i18n: rule.pleaseEnter` | Placeholder text | | `type` | `string` | `null` | Input type | | `disabled` | `boolean` | `false` | Disabled state | | `clearable` | `boolean` | `true` | Show clear button | | `full` | `boolean` | `false` | 100% width | | `width` | `number` | `-` | Fixed width in px | **Usage**: ```vue ``` --- ### ConfirmCancel Confirmation button pair with i18n text. **File**: `packages/base/item/confirmCancel.vue` **Events**: | Event | Payload | Description | |-------|---------|-------------| | `confirm` | `void` | Confirm button clicked | | `cancel` | `void` | Cancel button clicked | **Usage**: ```vue ``` --- ### ButtonWithTooltip Wraps `NoobButton` with tooltip disabled state handling. **File**: `packages/base/item/buttonWithTooltip.vue` **Props**: | Prop | Type | Default | Description | |------|------|---------|-------------| | `tooltip` | `string` | `-` | Tooltip content | | `disabled` | `boolean` | `-` | Button disabled state | **Usage**: ```vue Delete ``` --- ### WsMonitorToggle WebSocket subscription monitor with automatic retry logic. **File**: `packages/base/item/ws-monitor-toggle.vue` **Props**: | Prop | Type | Default | Description | |------|------|---------|-------------| | `topics` | `string[]` | **required** | Topics to monitor | | `statusEndpoint` | `string` | `'/public/ws/topics'` | Status check endpoint | | `interval` | `number` | `3000` | Retry interval (ms) | | `maxRetries` | `number` | `10` | Max connection attempts | | `connect` | `object/function` | `-` | Subscribe command or function | | `disconnect` | `object/function` | `-` | Unsubscribe command or function | | `disabled` | `boolean` | `false` | Disable toggle | | `labelConnected` | `string` | `'ws.autorefresh.enabled'` | Connected label i18n key | | `labelConnecting` | `string` | `'ws.autorefresh.enabling'` | Connecting label i18n key | | `labelDisconnected` | `string` | `'ws.autorefresh.disabled'` | Disconnected label i18n key | | `labelError` | `string` | `'ws.autorefresh.error'` | Error label i18n key | **Events**: | Event | Payload | Description | |-------|---------|-------------| | `status-change` | `boolean` | Connection status changed | | `error` | `Error` | Error occurred | **States**: `disconnected` | `connecting` | `connected` | `error` **Usage**: ```vue ``` --- ## Data Components ### SearchRow Search form row with standard action buttons. **File**: `packages/base/data/search-row.vue` **Props**: | Prop | Type | Default | Description | |------|------|---------|-------------| | `title` | `string` | `null` | Row title | | `fresh` | `boolean` | `true` | Show refresh button | | `add` | `boolean` | `true` | Show add button | | `del` | `boolean` | `true` | Show delete button | | `query` | `boolean` | `true` | Show query button | **Slots**: | Slot | Description | |------|-------------| | `left` | Extra buttons on left side | | `default` | Search form fields | **Events**: | Event | Description | |-------|-------------| | `query` | Query button clicked | | `add` | Add button clicked | | `delete` | Delete button clicked | **Usage**: ```vue ``` --- ### ListTable Data table with pagination and formatting support. **File**: `packages/base/data/list-table.vue` **Props**: | Prop | Type | Default | Description | |------|------|---------|-------------| | `data` | `any[]/PageResponse` | `[]` | Table data or paginated response | | `props` | `TableColumn[]` | `[]` | Column definitions | | `page` | `boolean` | `false` | Enable pagination | | `height` | `number/string` | `-` | Table height | | `maxHeight` | `number/string` | `-` | Table max height | | `example` | `object` | `{}` | Pagination state ({ page, size }) | | `rowKey` | `string` | `-` | Row key for tree/lazy | | `selectKey` | `string` | `-` | Key for auto-selection | | `treeProps` | `object` | `-` | Tree table configuration | | `lazy` | `boolean` | `false` | Lazy loading | | `border` | `boolean` | `false` | Show border | **TableColumn Interface**: ```typescript interface TableColumn { code: string; // Property name name?: string; // Column label (used if i18n not set) i18n?: string; // i18n key for label type?: string; // 'selection' | 'index' | 'expand' width?: number; // Column width fixed?: string; // 'left' | 'right' align?: string; // 'left' | 'center' | 'right' slot?: boolean; // Enable slot rendering dict?: string; // Dict key for value mapping timestamp?: boolean; // Format as timestamp filesize?: boolean; // Format as file size } ``` **Events**: | Event | Payload | Description | |-------|---------|-------------| | `query` | `void` | Refresh data | | `selection-change` | `selection[]` | Selection changed | | `row-click` | `row` | Row clicked | | `cell-click` | `row, column, cell, event` | Cell clicked | **Usage**: ```vue ``` --- ### ListTableDialog List table with multi-select in a dialog. **File**: `packages/base/data/listTableDialog.vue` **Props** (from `ListTableProps`): | Prop | Type | Default | Description | |------|------|---------|-------------| | `props` | `TableColumn[]` | `-` | Column definitions | | `rowKey` | `string` | `-` | Row key for selection | | `useDicts` | `string[]` | `-` | Dict keys to load | | `initialPage` | `number` | `1` | Initial page | | `initialPageSize` | `number` | `-` | Initial page size | | `initExample` | `object` | `-` | Initial query params | **Events**: | Event | Payload | Description | |-------|---------|-------------| | `query` | `(handler, example)` | Query handler (async) | | `confirm` | `(handler, rows)` | Confirm handler (async) | | `close` | `(handler)` | Close handler (async) | **Usage**: ```vue ``` --- ### ModifyForm Dynamic form for create/edit operations. **File**: `packages/base/data/modify-form.vue` **Props**: | Prop | Type | Default | Description | |------|------|---------|-------------| | `width` | `number` | `80` | Label width | | `param` | `object` | `{}` | Form data | | `rules` | `object` | `{}` | Validation rules | | `class` | `string` | `''` | Form class | | `type` | `string` | `null` | Form type | | `modify` | `boolean` | `false` | Edit mode (hides noModify fields) | | `items` | `FormItem[]` | `[]` | Form field definitions | | `confirm` | `string/boolean` | `undefined` | Confirm button config | | `cancel` | `string/boolean` | `undefined` | Cancel button config | **FormItem Interface**: ```typescript interface FormItem { code: string; // Field key name?: string; // Label (used if i18n not set) i18n?: string; // i18n key for label dict?: string; // Dict for select maxValue?: number; // Max value for number select date?: boolean; // Render as date picker formater?: string; // Date format string slot?: boolean; // Enable slot rendering type?: string; // Input type (textarea, etc.) rows?: number; // Textarea rows disabled?: boolean; // Disabled state noModify?: boolean; // Hidden in edit mode readonly?: boolean; // Readonly state } ``` **Events**: | Event | Description | |-------|-------------| | `confirm` | Form validated and submitted | | `cancel` | Cancel clicked | **Exposed Methods**: | Method | Description | |--------|-------------| | `clearValidate` | Clear validation state | **Usage**: ```vue ``` --- ### Descriptions Key-value display component based on `el-descriptions`. **File**: `packages/base/data/descriptions.vue` **Props**: | Prop | Type | Default | Description | |------|------|---------|-------------| | `data` | `object/array/string` | `0` | Display data | | `title` | `string` | `null` | Descriptions title | | `border` | `boolean` | `true` | Show border | **Usage**: ```vue ``` --- ### TableAction Row action buttons (edit/delete/add) with tooltips. **File**: `packages/base/data/table-action.vue` **Props**: | Prop | Type | Default | Description | |------|------|---------|-------------| | `add` | `boolean` | `false` | Show add button | | `modify` | `boolean` | `true` | Show edit button | | `del` | `boolean` | `true` | Show delete button | **Slots**: | Slot | Description | |------|-------------| | `left` | Extra content before actions | | `default` | Extra buttons after actions | **Events**: | Event | Description | |-------|-------------| | `modify` | Edit button clicked | | `del` | Delete button clicked | | `add` | Add button clicked | **Usage**: ```vue ``` --- ### Infomation Card component for displaying single metrics/stats. **File**: `packages/base/data/infomation.vue` **Props**: | Prop | Type | Default | Description | |------|------|---------|-------------| | `num` | `number` | `0` | Numeric value | | `icon` | `string` | `''` | Element Plus icon name | | `title` | `string` | `''` | Card title | | `center` | `boolean` | `false` | Center alignment | **Usage**: ```vue ``` --- ## Common Patterns ### Theme Integration All components use Vuex store for theme values: ```typescript const { state } = useStore(); // state.style - colors, backgrounds // state.size - sizes, paddings, fonts ``` Example in SCSS: ```scss color: v-bind('state.style.color'); background-color: v-bind('state.style.primaryBg'); ``` ### i18n Integration Components use `vue3-i18n` for translations: ```typescript const { t } = useI18n(); // t('key') for translation ``` Common i18n keys: - `base.add` - Add button - `base.delete` - Delete button - `base.select` - Select/Search button - `base.confirm` - Confirm button - `base.cancel` - Cancel button - `rule.pleaseEnter` - Enter placeholder - `rule.pleaseSelect` - Select placeholder ### v-model Pattern Components use Vue 3 `defineProps` with `defineEmits`: ```typescript const prop = defineProps({ modelValue: null, }); const emit = defineEmits(["update:modelValue"]); // Sync internal value to prop watch(myValue, (n) => emit('update:modelValue', n)); ``` ### Width Management Item components support multiple width modes: ```typescript // Fixed width from prop width.value = prop.width + 'px'; // Or from Vuex store width.value = state.size.searchWidth; // Full width &.full { width: 100%; } ``` ### Props Definition Pattern ```typescript // With defaults const prop = defineProps({ modelValue: null, disabled: { type: Boolean, default: false, }, }); // TypeScript interface (preferred for new components) interface Props { title: string; items: TableColumn[]; } withDefaults(defineProps(), { items: () => [], }); ``` --- ## Anti-Patterns 1. **Do not access Vuex store directly in templates** - Use computed properties ```vue
{{ state.style.color }}
text
``` 2. **Do not use `any` for typed props** - Define proper interfaces ```typescript // Bad prop: any; // Good interface TableColumn { code: string; name?: string; } ``` 3. **Do not mix Element Plus imports** - Use the component registry ```typescript // Avoid import { ElButton } from 'element-plus'; // Prefer (through noob-mengyxu) import { NoobButton } from 'noob-mengyxu'; ``` 4. **Avoid prop drilling** - Use provide/inject or Vuex for deep component trees 5. **Do not forget to emit `update:modelValue`** - For v-model to work properly