diff --git a/src/components/VnTable/VnChip.vue b/src/components/VnTable/VnChip.vue
new file mode 100644
index 000000000..74207b943
--- /dev/null
+++ b/src/components/VnTable/VnChip.vue
@@ -0,0 +1,55 @@
+
+
+
+
+
+ {{ row[col.name] }}
+
+
+
+
+
+
diff --git a/src/components/VnTable/VnColumn.vue b/src/components/VnTable/VnColumn.vue
new file mode 100644
index 000000000..aeccdb2d6
--- /dev/null
+++ b/src/components/VnTable/VnColumn.vue
@@ -0,0 +1,165 @@
+
+
+
+
+
+ {{ value }}
+
+
+
diff --git a/src/components/VnTable/VnFilter.vue b/src/components/VnTable/VnFilter.vue
new file mode 100644
index 000000000..b3386899f
--- /dev/null
+++ b/src/components/VnTable/VnFilter.vue
@@ -0,0 +1,158 @@
+
+
+
+ {{ column?.label }}
+
+
+
+
+
diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue
new file mode 100644
index 000000000..1610735a4
--- /dev/null
+++ b/src/components/VnTable/VnTable.vue
@@ -0,0 +1,658 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ event.index > rows.length - 2 &&
+ CrudModelRef.vnPaginateRef.paginate()
+ "
+ @row-click="(_, row) => rowClickFunction(row)"
+ @update:selected="emit('update:selected', $event)"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ $props.rowClick && $props.rowClick(row);
+ }
+ "
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ row[splittedColumns.title.name] }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ create.title }}
+
+
+
+ create.onDataSaved(res)"
+ >
+
+
+
+
+
+
+
+
+
+
+en:
+ status: Status
+es:
+ status: Estados
+
+
+
diff --git a/src/components/common/TableVisibleColumns.vue b/src/components/common/TableVisibleColumns.vue
index 7aa696a07..a4e4afafe 100644
--- a/src/components/common/TableVisibleColumns.vue
+++ b/src/components/common/TableVisibleColumns.vue
@@ -52,7 +52,7 @@ const toggleMarkAll = (val) => {
const getConfig = async (url, filter) => {
const response = await axios.get(url, {
- params: { filter: filter },
+ params: { filter: JSON.stringify(filter) },
});
return response.data && response.data.length > 0 ? response.data[0] : null;
};
@@ -60,7 +60,7 @@ const getConfig = async (url, filter) => {
const fetchViewConfigData = async () => {
try {
const userConfigFilter = {
- where: { tableCode: $props.tableCode, userFk: user.id },
+ where: { tableCode: $props.tableCode, userFk: user.value.id },
};
const userConfig = await getConfig('UserConfigViews', userConfigFilter);
@@ -74,8 +74,14 @@ const fetchViewConfigData = async () => {
const defaultConfig = await getConfig('DefaultViewConfigs', defaultConfigFilter);
if (defaultConfig) {
+ // Si el backend devuelve una configuración por defecto la usamos
setUserConfigViewData(defaultConfig.columns);
return;
+ } else {
+ // Si no hay configuración por defecto mostramos todas las columnas
+ const defaultColumns = {};
+ $props.allColumns.forEach((col) => (defaultColumns[col] = true));
+ setUserConfigViewData(defaultColumns);
}
} catch (err) {
console.err('Error fetching config view data', err);
diff --git a/src/components/common/VnCard.vue b/src/components/common/VnCard.vue
index b04478070..17fa74317 100644
--- a/src/components/common/VnCard.vue
+++ b/src/components/common/VnCard.vue
@@ -1,5 +1,5 @@
+import { computed, defineModel } from 'vue';
+
+const model = defineModel(undefined, { required: true });
+const $props = defineProps({
+ prop: {
+ type: Object,
+ required: true,
+ },
+ components: {
+ type: Object,
+ default: () => {},
+ },
+ value: {
+ type: [Object, Number, String, Boolean],
+ default: () => {},
+ },
+});
+
+const componentArray = computed(() => {
+ if (typeof $props.prop === 'object') return [$props.prop];
+ return $props.prop;
+});
+
+function mix(toComponent) {
+ const { component, attrs, event } = toComponent;
+ const customComponent = $props.components[component];
+ return {
+ component: customComponent?.component ?? component,
+ attrs: {
+ ...toValueAttrs(attrs),
+ ...toValueAttrs(customComponent?.attrs),
+ ...toComponent,
+ ...toValueAttrs(customComponent?.forceAttrs),
+ },
+ event: event ?? customComponent?.event,
+ };
+}
+
+function toValueAttrs(attrs) {
+ if (!attrs) return;
+ return typeof attrs == 'function' ? attrs($props.value) : attrs;
+}
+
+
+
+
+
+
diff --git a/src/components/common/VnInput.vue b/src/components/common/VnInput.vue
index c84a55122..33b97e29d 100644
--- a/src/components/common/VnInput.vue
+++ b/src/components/common/VnInput.vue
@@ -2,7 +2,12 @@
import { computed, ref } from 'vue';
import { useI18n } from 'vue-i18n';
-const emit = defineEmits(['update:modelValue', 'update:options', 'keyup.enter']);
+const emit = defineEmits([
+ 'update:modelValue',
+ 'update:options',
+ 'keyup.enter',
+ 'remove',
+]);
const $props = defineProps({
modelValue: {
@@ -17,6 +22,10 @@ const $props = defineProps({
type: String,
default: '',
},
+ clearable: {
+ type: Boolean,
+ default: true,
+ },
});
const { t } = useI18n();
@@ -78,14 +87,18 @@ const inputRules = [
-
{
+ value = null;
+ emit('remove');
+ }
+ "
>
diff --git a/src/components/common/VnInputDate.vue b/src/components/common/VnInputDate.vue
index fe0866292..184f8a158 100644
--- a/src/components/common/VnInputDate.vue
+++ b/src/components/common/VnInputDate.vue
@@ -1,80 +1,31 @@
-
-
-
-
-
+ v-if="
+ ($attrs.clearable == undefined || $attrs.clearable) &&
+ hover &&
+ model &&
+ !$attrs.disable
+ "
+ @click="
+ model = null;
+ isPopupOpen = false;
+ "
+ />
+
+
+ {
+ formattedDate = date;
+ isPopupOpen = false;
+ }
+ "
+ />
+
diff --git a/src/components/common/VnInputTime.vue b/src/components/common/VnInputTime.vue
index 4b436c136..9344ff869 100644
--- a/src/components/common/VnInputTime.vue
+++ b/src/components/common/VnInputTime.vue
@@ -1,14 +1,11 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-es:
- Cancel: Cancelar
-
diff --git a/src/components/common/VnLog.vue b/src/components/common/VnLog.vue
index 9d672bc3f..19765b1f7 100644
--- a/src/components/common/VnLog.vue
+++ b/src/components/common/VnLog.vue
@@ -1,5 +1,5 @@
{{ t(modelLog.modelI18n) }}
- #{{ modelLog.id }}#{{ modelLog.summaryId }}
{{ modelLog.showValue }}
diff --git a/src/components/common/VnPopup.vue b/src/components/common/VnPopup.vue
new file mode 100644
index 000000000..7dcb08f53
--- /dev/null
+++ b/src/components/common/VnPopup.vue
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+ {{ content }}
+
+
+
+
+
diff --git a/src/components/common/VnProgressModal.vue b/src/components/common/VnProgressModal.vue
new file mode 100644
index 000000000..cfd948d5f
--- /dev/null
+++ b/src/components/common/VnProgressModal.vue
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+ {{ t('Progress') }}
+
+
+
+
+
+
{{ t('Total progress') }}:
+
+
+
+
+ {{ progressLabel }}
+
+
+
+
+
+
+
+
+ {{ t('globals.cancel') }}
+
+
+
+
+
+
+
+es:
+ Progress: Progreso
+ Total progress: Progreso total
+ Cancelled: Cancelado
+
diff --git a/src/components/common/VnSelect.vue b/src/components/common/VnSelect.vue
index 493f094ce..3e5cd4216 100644
--- a/src/components/common/VnSelect.vue
+++ b/src/components/common/VnSelect.vue
@@ -1,6 +1,5 @@
@@ -178,6 +194,7 @@ watch(modelValue, (newValue) => {
>
$props.dataKey === route.meta.moduleName);
defineExpose({ getData });
onBeforeMount(async () => {
@@ -57,10 +58,12 @@ onBeforeMount(async () => {
store = arrayData.store;
entity = computed(() => (Array.isArray(store.data) ? store.data[0] : store.data));
// It enables to load data only once if the module is the same as the dataKey
- if ($props.dataKey !== useRoute().meta.moduleName) await getData();
+ if (!isSameDataKey.value || !route.params.id) await getData();
watch(
() => [$props.url, $props.filter],
- async () => await getData()
+ async () => {
+ if (!isSameDataKey.value) await getData();
+ }
);
});
@@ -76,14 +79,50 @@ async function getData() {
isLoading.value = false;
}
}
+
+function getValueFromPath(path) {
+ if (!path) return;
+ const keys = path.toString().split('.');
+ let current = entity.value;
+
+ for (let i = 0; i < keys.length; i++) {
+ if (current[keys[i]] === undefined) return undefined;
+ else current = current[keys[i]];
+ }
+ return current;
+}
+
const emit = defineEmits(['onFetch']);
+
+const iconModule = computed(() => route.matched[1].meta.icon);
+const toModule = computed(() =>
+ route.matched[1].path.split('/').length > 2
+ ? route.matched[1].redirect
+ : route.matched[1].children[0].redirect
+);