mirror of
https://gitlab.com/MoonTestUse1/AdministrationItDepartmens.git
synced 2025-08-14 00:25:46 +02:00
Change code, for build Docker
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold mb-2 flex items-center gap-2">
|
||||
<PhoneIcon size="16" class="text-blue-400" />
|
||||
<PhoneIcon :size="16" class="text-blue-400" />
|
||||
Контактная информация
|
||||
</h3>
|
||||
<div class="space-y-1 text-sm text-slate-300">
|
||||
@@ -14,7 +14,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold mb-2 flex items-center gap-2">
|
||||
<ClockIcon size="16" class="text-blue-400" />
|
||||
<ClockIcon :size="16" class="text-blue-400" />
|
||||
Режим работы
|
||||
</h3>
|
||||
<div class="space-y-1 text-sm text-slate-300">
|
||||
@@ -24,7 +24,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold mb-2 flex items-center gap-2">
|
||||
<MailIcon size="16" class="text-blue-400" />
|
||||
<MailIcon :size="16" class="text-blue-400" />
|
||||
Техподдержка
|
||||
</h3>
|
||||
<div class="space-y-1 text-sm text-slate-300">
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="flex flex-col sm:flex-row justify-between items-center gap-2">
|
||||
<div class="flex items-center space-x-3">
|
||||
<Building2Icon size="28" class="text-blue-400" />
|
||||
<Building2Icon :size="28" class="text-blue-400" />
|
||||
<div class="text-center sm:text-left">
|
||||
<h1 class="text-lg sm:text-xl font-semibold">Администрация КАО</h1>
|
||||
<p class="text-xs sm:text-sm text-slate-300">Портал технической поддержки</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<PhoneIcon size="18" class="text-blue-400" />
|
||||
<PhoneIcon :size="18" class="text-blue-400" />
|
||||
<div class="text-center sm:text-left">
|
||||
<p class="text-xs text-slate-300">Поддержка:</p>
|
||||
<p class="text-sm font-semibold">8 (800) 123-45-67</p>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="p-2 bg-blue-50 rounded-lg">
|
||||
<component
|
||||
:is="employee ? UserIcon : UserPlusIcon"
|
||||
size="24"
|
||||
:size="24"
|
||||
class="text-blue-600"
|
||||
/>
|
||||
</div>
|
||||
@@ -18,7 +18,7 @@
|
||||
@click="$emit('close')"
|
||||
class="text-gray-400 hover:text-gray-500 transition-colors"
|
||||
>
|
||||
<XIcon size="20" />
|
||||
<XIcon :size="20" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<UserIcon size="18" class="text-gray-400" />
|
||||
<UserIcon :size="18" class="text-gray-400" />
|
||||
</div>
|
||||
<input
|
||||
v-model="formData.last_name"
|
||||
@@ -48,7 +48,7 @@
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<UserIcon size="18" class="text-gray-400" />
|
||||
<UserIcon :size="18" class="text-gray-400" />
|
||||
</div>
|
||||
<input
|
||||
v-model="formData.first_name"
|
||||
@@ -66,7 +66,7 @@
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<BuildingIcon size="18" class="text-gray-400" />
|
||||
<BuildingIcon :size="18" class="text-gray-400" />
|
||||
</div>
|
||||
<select
|
||||
v-model="formData.department"
|
||||
@@ -87,7 +87,7 @@
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<DoorClosedIcon size="18" class="text-gray-400" />
|
||||
<DoorClosedIcon :size="18" class="text-gray-400" />
|
||||
</div>
|
||||
<input
|
||||
v-model="formData.office"
|
||||
@@ -105,7 +105,7 @@
|
||||
</label>
|
||||
<div class="relative">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<LockIcon size="18" class="text-gray-400" />
|
||||
<LockIcon :size="18" class="text-gray-400" />
|
||||
</div>
|
||||
<input
|
||||
v-model="formData.password"
|
||||
@@ -127,14 +127,14 @@
|
||||
@click="$emit('close')"
|
||||
class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors flex items-center gap-2"
|
||||
>
|
||||
<XIcon size="16" />
|
||||
<XIcon :size="16" />
|
||||
Отмена
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="px-4 py-2 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors flex items-center gap-2"
|
||||
>
|
||||
<component :is="employee ? SaveIcon : UserPlusIcon" size="16" />
|
||||
<component :is="employee ? SaveIcon : UserPlusIcon" :size="16" />
|
||||
{{ employee ? 'Сохранить' : 'Добавить' }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -147,6 +147,8 @@
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { XIcon, UserIcon, BuildingIcon, DoorClosedIcon, LockIcon, UserPlusIcon, SaveIcon } from 'lucide-vue-next';
|
||||
import { departments } from '@/utils/constants';
|
||||
import type { EmployeeFormData } from '@/types/employee';
|
||||
|
||||
|
||||
const props = defineProps<{
|
||||
employee?: any;
|
||||
@@ -157,7 +159,7 @@ const emit = defineEmits<{
|
||||
(e: 'submit', data: any): void;
|
||||
}>();
|
||||
|
||||
const formData = ref({
|
||||
const formData = ref<EmployeeFormData>({
|
||||
first_name: '',
|
||||
last_name: '',
|
||||
department: '',
|
||||
@@ -165,6 +167,7 @@ const formData = ref({
|
||||
password: ''
|
||||
});
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
if (props.employee) {
|
||||
formData.value = {
|
||||
@@ -180,7 +183,7 @@ onMounted(() => {
|
||||
function handleSubmit() {
|
||||
const data = { ...formData.value };
|
||||
if (props.employee && !data.password) {
|
||||
delete data.password;
|
||||
delete data.password; // Теперь это безопасно, так как password опциональный
|
||||
}
|
||||
emit('submit', data);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { UserPlusIcon, PencilIcon } from 'lucide-vue-next';
|
||||
import { departments } from '@/utils/constants';
|
||||
import EmployeeForm from './EmployeeForm.vue';
|
||||
import EmployeeFormModal from './employee/EmployeeFormModal.vue';
|
||||
import Notification from '@/components/ui/Notification.vue';
|
||||
import type { Employee } from '@/types/employee';
|
||||
|
||||
const employees = ref([]);
|
||||
const employees = ref<Employee[]>([]); // Добавляем типизацию массива сотрудников
|
||||
const showAddForm = ref(false);
|
||||
const editingEmployee = ref(null);
|
||||
const editingEmployee = ref<Employee | null>(null);
|
||||
const showNotification = ref(false);
|
||||
const notificationMessage = ref('');
|
||||
|
||||
function getDepartmentLabel(value: string) {
|
||||
return departments.find(d => d.value === value)?.label || value;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@click="$emit('close')"
|
||||
class="text-gray-400 hover:text-gray-500"
|
||||
>
|
||||
<XIcon size="20" />
|
||||
<XIcon :size="20" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -105,16 +105,16 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import type { Request } from '@/types/request';
|
||||
import RequestStatusBadge from './RequestStatusBadge.vue';
|
||||
import RequestPriorityBadge from './RequestPriorityBadge.vue';
|
||||
import RequestStatusModal from './RequestStatusModal.vue';
|
||||
import RequestDescriptionModal from './RequestDescriptionModal.vue';
|
||||
import Notification from '@/components/ui/Notification.vue';
|
||||
import { getRequestTypeLabel } from '@/utils/constants';
|
||||
|
||||
const requests = ref([]);
|
||||
const selectedRequest = ref(null);
|
||||
const selectedDescription = ref(null);
|
||||
const requests = ref<Request[]>([]); // Типизируем массив запросов
|
||||
const selectedRequest = ref<Request | null>(null);
|
||||
const selectedDescription = ref<Request | null>(null);
|
||||
const showNotification = ref(false);
|
||||
const filter = ref('all');
|
||||
const searchQuery = ref('');
|
||||
@@ -135,6 +135,7 @@ const filteredRequests = computed(() => {
|
||||
return result;
|
||||
});
|
||||
|
||||
|
||||
function formatDate(date: string) {
|
||||
return new Date(date).toLocaleString('ru-RU');
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
const { priority } = defineProps<{
|
||||
priority: 'low' | 'medium' | 'high' | 'critical'
|
||||
}>();
|
||||
|
||||
|
||||
@@ -46,16 +46,17 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import RequestStatusBadge from './RequestStatusBadge.vue';
|
||||
import type { RequestStatus } from '@/types/request';
|
||||
|
||||
const props = defineProps<{
|
||||
currentStatus: string;
|
||||
currentStatus: RequestStatus;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['close', 'update']);
|
||||
|
||||
const allStatuses = ['new', 'in_progress', 'resolved', 'closed'] as const;
|
||||
const allStatuses: RequestStatus[] = ['new', 'in_progress', 'resolved', 'closed'];
|
||||
|
||||
function handleStatusSelect(newStatus: string) {
|
||||
function handleStatusSelect(newStatus: RequestStatus) {
|
||||
if (newStatus === props.currentStatus) return;
|
||||
emit('update', newStatus);
|
||||
emit('close');
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
class="w-full bg-blue-600 text-white py-2 px-4 text-sm sm:text-base rounded-md hover:bg-blue-700 transition-colors flex items-center justify-center gap-2 disabled:opacity-50"
|
||||
>
|
||||
<component :is="isSubmitting ? LoaderIcon : SendIcon"
|
||||
size="18"
|
||||
:size="18"
|
||||
:class="{ 'animate-spin': isSubmitting }"
|
||||
/>
|
||||
{{ isSubmitting ? 'Отправка...' : 'Отправить заявку' }}
|
||||
|
||||
@@ -14,4 +14,23 @@ export interface LoginCredentials {
|
||||
export interface AdminCredentials {
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface Employee {
|
||||
id: number;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
department: string;
|
||||
office: string;
|
||||
}
|
||||
|
||||
export interface Request {
|
||||
id: number;
|
||||
employee_last_name: string;
|
||||
employee_first_name: string;
|
||||
employee_office: string;
|
||||
request_type: string;
|
||||
priority: 'low' | 'medium' | 'high' | 'critical';
|
||||
status: 'new' | 'in_progress' | 'resolved' | 'closed';
|
||||
created_at: string;
|
||||
}
|
||||
17
src/types/employee.ts
Normal file
17
src/types/employee.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export interface Employee {
|
||||
id: number;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
department: string;
|
||||
office: string;
|
||||
created_at?: string;
|
||||
}
|
||||
|
||||
export interface EmployeeFormData {
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
department: string;
|
||||
office: string;
|
||||
password?: string; // Делаем password опциональным
|
||||
}
|
||||
|
||||
14
src/types/request.ts
Normal file
14
src/types/request.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export type RequestStatus = 'new' | 'in_progress' | 'resolved' | 'closed';
|
||||
|
||||
export interface Request {
|
||||
id: number;
|
||||
status: RequestStatus;
|
||||
created_at: string;
|
||||
employee_last_name: string;
|
||||
employee_first_name: string;
|
||||
employee_office: string;
|
||||
request_type: string;
|
||||
priority: 'low' | 'medium' | 'high' | 'critical';
|
||||
description: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user