Enhance form column settings and table display
- Add "Show all" and "Hide all" buttons in column settings modal - Improve column width handling and default width management - Update OpenSelect and OpenText components to support more flexible prop types - Add z-index to table header for better visual hierarchy - Refactor column width property from `cell_width` to `width`
This commit is contained in:
parent
0d6bd1bfde
commit
55b0f57741
|
|
@ -0,0 +1,53 @@
|
||||||
|
---
|
||||||
|
description: Laravel Back-end
|
||||||
|
globs: api/**.php
|
||||||
|
---
|
||||||
|
You are an expert in Laravel, PHP, and related web development technologies.
|
||||||
|
|
||||||
|
Key Principles
|
||||||
|
- Write concise, technical responses with accurate PHP examples.
|
||||||
|
- Adhere to Laravel 11+ best practices and conventions.
|
||||||
|
- Use object-oriented programming with a focus on SOLID principles.
|
||||||
|
- Prefer iteration and modularization over duplication.
|
||||||
|
- Use descriptive variable and method names.
|
||||||
|
- Use lowercase with dashes for directories (e.g., app/Http/Controllers).
|
||||||
|
- Favor dependency injection and service containers.
|
||||||
|
|
||||||
|
PHP/Laravel
|
||||||
|
- Use PHP 8.2+ features when appropriate (e.g., typed properties, match expressions).
|
||||||
|
- Follow PSR-12 coding standards.
|
||||||
|
- Utilize Laravel's built-in features and helpers when possible.
|
||||||
|
- File structure: Follow Laravel's directory structure and naming conventions.
|
||||||
|
- Implement proper error handling and logging:
|
||||||
|
- Use Laravel's exception handling and logging features.
|
||||||
|
- Create custom exceptions when necessary.
|
||||||
|
- Use try-catch blocks for expected exceptions.
|
||||||
|
- Use Laravel's validation features for form and request validation.
|
||||||
|
- Implement middleware for request filtering and modification.
|
||||||
|
- Utilize Laravel's Eloquent ORM for database interactions.
|
||||||
|
- Use Laravel's query builder for complex database queries.
|
||||||
|
- Implement proper database migrations and seeders.
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
- Laravel (latest stable version)
|
||||||
|
- Composer for dependency management
|
||||||
|
|
||||||
|
Laravel Best Practices
|
||||||
|
- Use Eloquent ORM instead of raw SQL queries when possible.
|
||||||
|
- Use Laravel's built-in authentication and authorization features.
|
||||||
|
- Utilize Laravel's caching mechanisms for improved performance.
|
||||||
|
- Implement job queues for long-running tasks.
|
||||||
|
- Use Pest for unit and feature tests.
|
||||||
|
- Use Laravel's localization features for multi-language support.
|
||||||
|
- Implement proper database indexing for improved query performance.
|
||||||
|
- Use Laravel's built-in pagination features.
|
||||||
|
- Implement proper error logging and monitoring.
|
||||||
|
|
||||||
|
Key Conventions
|
||||||
|
1. Follow Laravel's MVC architecture.
|
||||||
|
2. Use Laravel's routing system for defining application endpoints.
|
||||||
|
3. Implement proper request validation using Form Requests.
|
||||||
|
4. Implement proper database relationships using Eloquent.
|
||||||
|
5. Use Laravel's event and listener system for decoupled code.
|
||||||
|
6. Implement proper database transactions for data integrity.
|
||||||
|
7. Use Laravel's built-in scheduling features for recurring tasks.
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
---
|
||||||
|
description: Vue and Nuxt guidelines
|
||||||
|
globs: client/**.*
|
||||||
|
---
|
||||||
|
You are an expert in Nuxt, Vue.js, Vue Router, Pinia, VueUse, NuxtUI library and Tailwind, with a deep understanding of best practices and performance optimization techniques in these technologies.
|
||||||
|
|
||||||
|
Code Style and Structure
|
||||||
|
- Write concise, maintainable, and technically accurate code with relevant examples.
|
||||||
|
- Use functional and declarative programming patterns; avoid classes.
|
||||||
|
- Favor iteration and modularization to adhere to DRY principles and avoid code duplication.
|
||||||
|
- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
|
||||||
|
- Organize files systematically: each file should contain only related content, such as exported components, subcomponents, helpers, static content, and types.
|
||||||
|
|
||||||
|
Naming Conventions
|
||||||
|
- Use lowercase with dashes for directories (e.g., components/auth-wizard).
|
||||||
|
- Favor named exports for functions.
|
||||||
|
|
||||||
|
We don't use typescript, javascript only (except when really required for config file for instance).
|
||||||
|
|
||||||
|
Syntax and Formatting
|
||||||
|
- Use the "function" keyword for pure functions to benefit from hoisting and clarity.
|
||||||
|
- Always use the Vue Composition API script setup style. If a legacy file still used
|
||||||
|
|
||||||
|
UI and Styling
|
||||||
|
- Use Nuxt UI components (https://ui.nuxt.com/components) and Tailwind for components and styling.
|
||||||
|
- Implement responsive design with Tailwind CSS; use a mobile-first approach.
|
||||||
|
- Build UI components using atomic design principles, organizing them from smallest to largest (e.g., atoms, molecules, organisms, pages).
|
||||||
|
|
||||||
|
Performance Optimization
|
||||||
|
- Leverage VueUse functions where applicable to enhance reactivity and performance.
|
||||||
|
- Wrap asynchronous components in Suspense with a fallback UI made with <USkeleton/> components.
|
||||||
|
- Use dynamic loading for non-critical components.
|
||||||
|
|
||||||
|
Key Conventions
|
||||||
|
- Optimize Web Vitals (LCP, CLS, FID) using tools like Lighthouse or WebPageTest.
|
||||||
|
- Implement proper error boundaries or try-catch mechanisms to handle errors gracefully, especially in asynchronous operations.
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<UButtonGroup size="xs" orientation="horizontal">
|
<UButtonGroup
|
||||||
|
size="xs"
|
||||||
|
orientation="horizontal"
|
||||||
|
>
|
||||||
<UButton
|
<UButton
|
||||||
v-track.delete_record_click
|
v-track.delete_record_click
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,14 @@
|
||||||
<modal
|
<modal
|
||||||
compact-header
|
compact-header
|
||||||
:show="show"
|
:show="show"
|
||||||
|
v-bind="$attrs"
|
||||||
@close="$emit('close')"
|
@close="$emit('close')"
|
||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<Icon name="heroicons:adjustments-horizontal" class="w-8 h-8" />
|
<Icon
|
||||||
|
name="heroicons:adjustments-horizontal"
|
||||||
|
class="w-8 h-8"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #title>
|
<template #title>
|
||||||
Manage Columns
|
Manage Columns
|
||||||
|
|
@ -21,7 +25,24 @@
|
||||||
class="font-semibold mb-2"
|
class="font-semibold mb-2"
|
||||||
:class="{ 'mt-4': sectionIndex > 0 }"
|
:class="{ 'mt-4': sectionIndex > 0 }"
|
||||||
>
|
>
|
||||||
{{ section.title }}
|
<div class="flex items-center justify-between">
|
||||||
|
<span>{{ section.title }}</span>
|
||||||
|
<div class="flex items-center gap-2 text-xs text-gray-500">
|
||||||
|
<button
|
||||||
|
class="hover:text-gray-700"
|
||||||
|
@click="toggleAllColumns(section.fields, true)"
|
||||||
|
>
|
||||||
|
Show all
|
||||||
|
</button>
|
||||||
|
<span class="text-gray-300">|</span>
|
||||||
|
<button
|
||||||
|
class="hover:text-gray-700"
|
||||||
|
@click="toggleAllColumns(section.fields, false)"
|
||||||
|
>
|
||||||
|
Hide all
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</h4>
|
</h4>
|
||||||
<div class="border border-gray-300">
|
<div class="border border-gray-300">
|
||||||
<div class="grid grid-cols-[1fr,auto,auto] gap-4 px-4 py-2 bg-gray-50 border-b border-gray-300">
|
<div class="grid grid-cols-[1fr,auto,auto] gap-4 px-4 py-2 bg-gray-50 border-b border-gray-300">
|
||||||
|
|
@ -46,8 +67,8 @@
|
||||||
</p>
|
</p>
|
||||||
<div class="flex justify-center w-20">
|
<div class="flex justify-center w-20">
|
||||||
<ToggleSwitchInput
|
<ToggleSwitchInput
|
||||||
v-model="displayColumns[field.id]"
|
v-model="computedDisplayColumns[field.id]"
|
||||||
wrapper-class="mb-0"
|
wrapper-class="my-0"
|
||||||
label=""
|
label=""
|
||||||
:name="`display-${field.id}`"
|
:name="`display-${field.id}`"
|
||||||
@update:model-value="onChangeDisplayColumns"
|
@update:model-value="onChangeDisplayColumns"
|
||||||
|
|
@ -55,8 +76,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-center w-20">
|
<div class="flex justify-center w-20">
|
||||||
<ToggleSwitchInput
|
<ToggleSwitchInput
|
||||||
v-model="wrapColumns[field.id]"
|
v-model="computedWrapColumns[field.id]"
|
||||||
wrapper-class="mb-0"
|
wrapper-class="my-0"
|
||||||
label=""
|
label=""
|
||||||
:name="`wrap-${field.id}`"
|
:name="`wrap-${field.id}`"
|
||||||
/>
|
/>
|
||||||
|
|
@ -85,6 +106,14 @@ const props = defineProps({
|
||||||
columns: {
|
columns: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => []
|
||||||
|
},
|
||||||
|
displayColumns: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
wrapColumns: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -122,16 +151,24 @@ const sections = computed(() => [
|
||||||
])
|
])
|
||||||
|
|
||||||
// Column preferences storage
|
// Column preferences storage
|
||||||
|
const storageKey = computed(() => `column-preferences-formid-${props.form.id}`)
|
||||||
|
|
||||||
const columnPreferences = useStorage(
|
const columnPreferences = useStorage(
|
||||||
computed(() => props.form ? `column-preferences-formid-${props.form.id}` : null),
|
storageKey.value,
|
||||||
{
|
{
|
||||||
display: {},
|
display: {},
|
||||||
wrap: {},
|
wrap: {},
|
||||||
widths: {}
|
widths: {}
|
||||||
|
},
|
||||||
|
localStorage,
|
||||||
|
{
|
||||||
|
onError: (error) => {
|
||||||
|
console.error('Storage error:', error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const displayColumns = computed({
|
const computedDisplayColumns = computed({
|
||||||
get: () => columnPreferences.value.display,
|
get: () => columnPreferences.value.display,
|
||||||
set: (val) => {
|
set: (val) => {
|
||||||
columnPreferences.value.display = val
|
columnPreferences.value.display = val
|
||||||
|
|
@ -139,7 +176,7 @@ const displayColumns = computed({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const wrapColumns = computed({
|
const computedWrapColumns = computed({
|
||||||
get: () => columnPreferences.value.wrap,
|
get: () => columnPreferences.value.wrap,
|
||||||
set: (val) => {
|
set: (val) => {
|
||||||
columnPreferences.value.wrap = val
|
columnPreferences.value.wrap = val
|
||||||
|
|
@ -164,12 +201,18 @@ function preserveColumnWidths(newColumns, existingColumns = []) {
|
||||||
// Then fallback to form properties
|
// Then fallback to form properties
|
||||||
const existing = existingColumns?.find(e => e.id === col.id)
|
const existing = existingColumns?.find(e => e.id === col.id)
|
||||||
|
|
||||||
const width = storedWidth || currentCol?.cell_width || currentCol?.width || existing?.cell_width || existing?.width || col.width || 150
|
// Convert any non-numeric width to default
|
||||||
|
const defaultWidth = 250
|
||||||
|
let width = storedWidth || currentCol?.width || existing?.width || defaultWidth
|
||||||
|
|
||||||
|
// If width is not a number or is 'full', use default width
|
||||||
|
if (typeof width !== 'number' || isNaN(width)) {
|
||||||
|
width = defaultWidth
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...col,
|
...col,
|
||||||
width,
|
width
|
||||||
cell_width: width
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -187,8 +230,8 @@ watch(() => props.columns, (newColumns) => {
|
||||||
|
|
||||||
const widths = {}
|
const widths = {}
|
||||||
newColumns.forEach(col => {
|
newColumns.forEach(col => {
|
||||||
if (col.cell_width) {
|
if (col.width) {
|
||||||
widths[col.id] = col.cell_width
|
widths[col.id] = col.width
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -199,42 +242,63 @@ watch(() => props.columns, (newColumns) => {
|
||||||
watch(() => props.form, (newForm) => {
|
watch(() => props.form, (newForm) => {
|
||||||
if (!newForm) return
|
if (!newForm) return
|
||||||
|
|
||||||
const properties = newForm.properties || []
|
const properties = candidatesProperties.value
|
||||||
const storedPrefs = columnPreferences.value
|
const storedPrefs = columnPreferences.value
|
||||||
|
const removedProperties = newForm.removed_properties || []
|
||||||
|
|
||||||
// Initialize display columns if not set
|
// Initialize display columns if not set
|
||||||
if (!Object.keys(storedPrefs.display).length) {
|
if (!Object.keys(storedPrefs.display).length) {
|
||||||
|
// Set all non-removed properties to visible by default
|
||||||
properties.forEach((field) => {
|
properties.forEach((field) => {
|
||||||
storedPrefs.display[field.id] = true
|
storedPrefs.display[field.id] = true
|
||||||
})
|
})
|
||||||
|
// Also handle removed properties
|
||||||
|
removedProperties.forEach((field) => {
|
||||||
|
storedPrefs.display[field.id] = false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize wrap columns if not set
|
// Initialize wrap columns if not set
|
||||||
if (!Object.keys(storedPrefs.wrap).length) {
|
if (!Object.keys(storedPrefs.wrap).length) {
|
||||||
properties.forEach((field) => {
|
[...properties, ...removedProperties].forEach((field) => {
|
||||||
storedPrefs.wrap[field.id] = false
|
storedPrefs.wrap[field.id] = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize widths if not set
|
||||||
|
if (!Object.keys(storedPrefs.widths).length) {
|
||||||
|
[...properties, ...removedProperties].forEach((field) => {
|
||||||
|
const defaultWidth = 150
|
||||||
|
storedPrefs.widths[field.id] = field.width || defaultWidth
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Emit initial values
|
// Emit initial values
|
||||||
emit('update:displayColumns', storedPrefs.display)
|
emit('update:displayColumns', storedPrefs.display)
|
||||||
emit('update:wrapColumns', storedPrefs.wrap)
|
emit('update:wrapColumns', storedPrefs.wrap)
|
||||||
|
|
||||||
// Emit initial columns (all visible by default)
|
// Emit initial columns (all non-removed visible by default)
|
||||||
const initialColumns = clonedeep(candidatesProperties.value)
|
const initialColumns = clonedeep(properties)
|
||||||
.concat(props.form?.removed_properties || [])
|
.concat(removedProperties)
|
||||||
.filter((field) => storedPrefs.display[field.id] !== false) // Show all columns by default unless explicitly hidden
|
.filter((field) => storedPrefs.display[field.id] !== false)
|
||||||
|
|
||||||
// Preserve any existing column widths
|
// Preserve any existing column widths
|
||||||
const columnsWithWidths = preserveColumnWidths(initialColumns, props.form.properties)
|
const columnsWithWidths = preserveColumnWidths(initialColumns, properties)
|
||||||
emit('update:columns', columnsWithWidths)
|
emit('update:columns', columnsWithWidths)
|
||||||
}, { immediate: true })
|
}, { immediate: true })
|
||||||
|
|
||||||
|
function toggleAllColumns(fields, show) {
|
||||||
|
fields.forEach((field) => {
|
||||||
|
computedDisplayColumns.value[field.id] = show
|
||||||
|
})
|
||||||
|
onChangeDisplayColumns()
|
||||||
|
}
|
||||||
|
|
||||||
function onChangeDisplayColumns() {
|
function onChangeDisplayColumns() {
|
||||||
if (!import.meta.client) return
|
if (!import.meta.client) return
|
||||||
const properties = clonedeep(candidatesProperties.value)
|
const properties = clonedeep(candidatesProperties.value)
|
||||||
.concat(props.form?.removed_properties || [])
|
.concat(props.form?.removed_properties || [])
|
||||||
.filter((field) => displayColumns.value[field.id] === true)
|
.filter((field) => computedDisplayColumns.value[field.id] === true)
|
||||||
|
|
||||||
// Preserve existing column widths when toggling visibility
|
// Preserve existing column widths when toggling visibility
|
||||||
const columnsWithWidths = preserveColumnWidths(properties, props.form.properties)
|
const columnsWithWidths = preserveColumnWidths(properties, props.form.properties)
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,14 @@
|
||||||
|
|
||||||
<!-- Settings Modal -->
|
<!-- Settings Modal -->
|
||||||
<form-columns-settings-modal
|
<form-columns-settings-modal
|
||||||
|
v-if="form"
|
||||||
:show="showColumnsModal"
|
:show="showColumnsModal"
|
||||||
:form="form"
|
:form="form"
|
||||||
:columns="properties"
|
:columns="properties"
|
||||||
v-model:display-columns="displayColumns"
|
:display-columns="displayColumns"
|
||||||
v-model:wrap-columns="wrapColumns"
|
:wrap-columns="wrapColumns"
|
||||||
|
@update:display-columns="displayColumns = $event"
|
||||||
|
@update:wrap-columns="wrapColumns = $event"
|
||||||
@close="showColumnsModal = false"
|
@close="showColumnsModal = false"
|
||||||
@update:columns="onColumnUpdated"
|
@update:columns="onColumnUpdated"
|
||||||
/>
|
/>
|
||||||
|
|
@ -225,6 +228,7 @@ export default {
|
||||||
},
|
},
|
||||||
onColumnUpdated(columns) {
|
onColumnUpdated(columns) {
|
||||||
this.properties = columns
|
this.properties = columns
|
||||||
|
this.dataChanged()
|
||||||
},
|
},
|
||||||
onUpdateRecord(submission) {
|
onUpdateRecord(submission) {
|
||||||
this.recordStore.save(submission)
|
this.recordStore.save(submission)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
<thead
|
<thead
|
||||||
:id="'table-header-' + tableHash"
|
:id="'table-header-' + tableHash"
|
||||||
ref="header"
|
ref="header"
|
||||||
class="n-table-head top-0"
|
class="n-table-head top-0 z-10"
|
||||||
:class="{ absolute: data.length !== 0 }"
|
:class="{ absolute: data.length !== 0 }"
|
||||||
style="will-change: transform; transform: translate3d(0px, 0px, 0px)"
|
style="will-change: transform; transform: translate3d(0px, 0px, 0px)"
|
||||||
>
|
>
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
:key="col.id"
|
:key="col.id"
|
||||||
scope="col"
|
scope="col"
|
||||||
:allow-resize="allowResize"
|
:allow-resize="allowResize"
|
||||||
:width="col.cell_width ? col.cell_width + 'px' : 'auto'"
|
:width="col.width ? col.width + 'px' : '150px'"
|
||||||
class="n-table-cell p-0 relative"
|
class="n-table-cell p-0 relative"
|
||||||
@resize-width="resizeCol(col, $event)"
|
@resize-width="resizeCol(col, $event)"
|
||||||
>
|
>
|
||||||
|
|
@ -68,7 +68,7 @@
|
||||||
<td
|
<td
|
||||||
v-for="(col, colIndex) in columns"
|
v-for="(col, colIndex) in columns"
|
||||||
:key="col.id"
|
:key="col.id"
|
||||||
:style="{ width: col.cell_width + 'px' }"
|
:style="{ width: col.width ? col.width + 'px' : '150px' }"
|
||||||
class="n-table-cell border-gray-100 dark:border-gray-900 text-sm p-2 overflow-hidden"
|
class="n-table-cell border-gray-100 dark:border-gray-900 text-sm p-2 overflow-hidden"
|
||||||
:class="[
|
:class="[
|
||||||
{
|
{
|
||||||
|
|
@ -179,7 +179,8 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
},
|
},
|
||||||
scrollParent: {
|
scrollParent: {
|
||||||
type: [Boolean]
|
type: [Boolean, Object],
|
||||||
|
default: null
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
emits: ["updated", "deleted", "resize", "update-columns"],
|
emits: ["updated", "deleted", "resize", "update-columns"],
|
||||||
|
|
@ -294,7 +295,7 @@ export default {
|
||||||
if (this.internalColumns) {
|
if (this.internalColumns) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.internalColumns.forEach((col) => {
|
this.internalColumns.forEach((col) => {
|
||||||
if (!_has(col, "cell_width")) {
|
if (!_has(col, "width")) {
|
||||||
if (
|
if (
|
||||||
this.allowResize &&
|
this.allowResize &&
|
||||||
this.internalColumns.length &&
|
this.internalColumns.length &&
|
||||||
|
|
@ -315,7 +316,7 @@ export default {
|
||||||
resizeCol(col, width) {
|
resizeCol(col, width) {
|
||||||
if (!this.form) return
|
if (!this.form) return
|
||||||
const index = this.internalColumns.findIndex((c) => c.id === col.id)
|
const index = this.internalColumns.findIndex((c) => c.id === col.id)
|
||||||
this.internalColumns[index].cell_width = width
|
this.internalColumns[index].width = width
|
||||||
this.setColumns(this.internalColumns)
|
this.setColumns(this.internalColumns)
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.$emit("resize")
|
this.$emit("resize")
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,14 @@ export default {
|
||||||
components: { OpenTag },
|
components: { OpenTag },
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
type: Object,
|
type: [String, Object, Array],
|
||||||
|
required: false,
|
||||||
|
default: null
|
||||||
},
|
},
|
||||||
|
property: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
|
@ -34,10 +40,7 @@ export default {
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
valueIsObject() {
|
valueIsObject() {
|
||||||
if (typeof this.value === "object" && this.value !== null) {
|
return Array.isArray(this.value) || (typeof this.value === "object" && this.value !== null)
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,9 @@ export default {
|
||||||
components: {},
|
components: {},
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
type: String,
|
type: [String, Number],
|
||||||
required: true,
|
required: false,
|
||||||
|
default: null
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue