This commit is contained in:
2026-04-18 12:25:58 +03:00
parent 2068154656
commit ebabe7e6d8
3 changed files with 237 additions and 18 deletions

View File

@@ -2,36 +2,135 @@
<AppLayout>
<div class="card">
<h1 class="text-2xl font-bold mb-6">Application Settings</h1>
<form @submit.prevent="saveSettings" class="space-y-4 max-w-lg">
<div v-for="(value, key) in settings" :key="key">
<label class="block text-sm font-medium text-gray-700">{{ key }}</label>
<input v-model="settings[key]" type="text" class="input-field mt-1" />
<form @submit.prevent="saveSettings" class="space-y-6 max-w-2xl">
<div v-for="field in meta" :key="field.key" class="border-b border-gray-200 pb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">
{{ field.label }}
<span v-if="field.required" class="text-red-500">*</span>
</label>
<!-- Текстовое поле -->
<input
v-if="field.type === 'text' || field.type === 'number'"
v-model="values[field.key]"
:type="field.type"
:required="field.required"
class="input-field mt-1"
/>
<!-- Текстовая область -->
<textarea
v-else-if="field.type === 'textarea'"
v-model="values[field.key]"
:rows="field.rows || 3"
class="input-field mt-1"
></textarea>
<!-- Чекбокс для булевых значений -->
<div v-else-if="field.type === 'boolean'" class="flex items-center mt-1">
<input
type="checkbox"
:checked="values[field.key] === 'true'"
@change="values[field.key] = $event.target.checked ? 'true' : 'false'"
class="rounded border-gray-300 text-primary-600 focus:ring-primary-500"
/>
<span class="ml-2 text-sm text-gray-600">Enabled</span>
</div>
<!-- Выпадающий список -->
<select
v-else-if="field.type === 'select'"
v-model="values[field.key]"
class="input-field mt-1"
>
<option v-for="opt in field.options" :key="opt.value" :value="opt.value">
{{ opt.label }}
</option>
</select>
<p v-if="field.description" class="mt-1 text-xs text-gray-500">
{{ field.description }}
</p>
</div>
<div class="flex justify-end space-x-3 pt-4">
<button type="button" @click="loadData" class="btn-secondary">Reset</button>
<button type="submit" class="btn-primary">Save Changes</button>
</div>
<button type="submit" class="btn-primary">Save Changes</button>
</form>
<div v-if="message" class="mt-4 p-3 rounded-lg" :class="messageClass">
{{ message }}
</div>
</div>
</AppLayout>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import AppLayout from '../components/Layout/AppLayout.vue'
import { ref, onMounted } from 'vue';
import AppLayout from '../components/Layout/AppLayout.vue';
const settings = ref<Record<string, string>>({})
interface FieldMeta {
key: string;
label: string;
description?: string;
type: string;
required?: boolean;
rows?: number;
options?: Array<{ value: string; label: string }>;
}
async function loadSettings() {
const res = await fetch('/api/settings')
settings.value = await res.json()
const meta = ref<FieldMeta[]>([]);
const values = ref<Record<string, string>>({});
const message = ref('');
const messageClass = ref('');
async function loadMeta() {
const res = await fetch('/api/settings/meta');
if (res.ok) {
meta.value = await res.json();
} else {
showMessage('Failed to load settings metadata', 'bg-red-50 text-red-800');
}
}
async function loadValues() {
const res = await fetch('/api/settings/all');
if (res.ok) {
values.value = await res.json();
} else {
showMessage('Failed to load settings values', 'bg-red-50 text-red-800');
}
}
async function loadData() {
await Promise.all([loadMeta(), loadValues()]);
}
async function saveSettings() {
await fetch('/api/admin/settings', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(settings.value)
})
alert('Settings saved')
try {
const res = await fetch('/api/admin/settings', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(values.value),
});
if (res.ok) {
showMessage('Settings saved successfully', 'bg-green-50 text-green-800');
} else {
showMessage('Failed to save settings', 'bg-red-50 text-red-800');
}
} catch (e) {
showMessage('Network error', 'bg-red-50 text-red-800');
}
}
onMounted(loadSettings)
function showMessage(text: string, cssClass: string) {
message.value = text;
messageClass.value = cssClass;
setTimeout(() => {
message.value = '';
}, 3000);
}
onMounted(loadData);
</script>