Начало диплома Даны

This commit is contained in:
Mikan
2025-06-03 16:52:30 +03:00
parent 5e198c8b56
commit 7ac8a2c778
4 changed files with 114 additions and 572 deletions

View File

@@ -1,260 +1,40 @@
# Требования к коду # Введение
Используется библиотека `react-router-dom` и `react=markdown`. В условиях динамичного развития рынка коммерческой недвижимости офисным центрам необходимо не только обеспечивать
высокий уровень обслуживания арендаторов, но и эффективно управлять внутренними процессами. Одним из ключевых
направлений деятельности является организация аренды помещений, планирование их загрузки,
своевременное обновление информации об услугах и надёжный контроль за бронированиями и платежами.
Все компоненты должны быть функциональными. На практике многие офисные центры продолжают использовать устаревшие методы учёта, такие как бумажные документы или
props должны быть сразу распакованы. таблицы Excel, что усложняет управление, увеличивает вероятность ошибок и снижает оперативность принятия решений.
export без default Отсутствие единой информационной системы часто приводит к нарушению сроков аренды,
путанице в расписании, неудовлетворённости клиентов и финансовым потерям.
Пример: Внедрение специализированного программного обеспечения для управления арендаторами, помещениями и услугами позволяет
значительно повысить эффективность работы офисного центра, минимизировать влияние человеческого фактора,
автоматизировать документооборот и укрепить доверие клиентов. Это особенно актуально в условиях цифровизации и
роста конкуренции в сегменте коммерческой недвижимости.
```tsx Таким образом, тема данной работы обусловлена необходимостью создания современной информационной системы, которая
export function ProfessionPage() { оптимизирует процессы аренды, обслуживания арендаторов и контроля финансовых операций в офисном центре.
const {professionId} = useParams<{ professionId: string }>();
}
```
Используйте современные практики React (например, хуки). Цель дипломного проекта — разработка программного продукта для автоматизации учёта и контроля деятельности офисного
При создании новых компонентов добавьте комментарии. центра. Приложение предоставляет возможности добавления, редактирования и удаления данных о клиентах, помещениях и
услугах, планирования графика аренды, ведения учёта договоров и контроля оплат.
Если для задачи необходимы новые типы, интерфейсы или вспомогательные компоненты - создавай их в соответвующих файлах. Для достижения поставленной цели необходимо решить следующие задачи:
# Документария 1. Провести анализ существующих программных решений для автоматизации управления коммерческой недвижимостью, выявить их сильные и слабые стороны.
2. Определить функциональные и нефункциональные требования к разрабатываемой системе.
3. Спроектировать архитектуру программного обеспечения с учётом удобства использования, безопасности данных и масштабируемости.
4. Разработать приложение с использованием современных технологий, таких как WPF, C# и MS SQL Server.
5. Реализовать модули управления арендаторами, помещениями, договорами аренды и дополнительными услугами.
6. Внедрить систему авторизации, аутентификации и разграничения прав доступа для различных типов пользователей (администратор, менеджер, бухгалтер).
7. Подготовить и провести комплексное тестирование приложения для проверки его корректной работы и соответствия заданным требованиям.
8. Оценить эффективность разработанного решения и его влияние на процессы управления офисным центром.
## Существующие типы Пояснительная записка дипломной работы содержит следующие разделы: введение, две главы основной части, заключение,
три раздела приложений.
`types/api.ts` В разделе Введения отражены актуальность темы, цель дипломной работы и задачи.
```ts
export interface ApiResponse {
body?: object,
success: boolean
}
export interface PageResponse<T>{
count: number;
next?: string;
previous?: string;
results: T[]
}
```
`types/common.ts`
```ts
export interface UniqueItem{
id: number;
}
export interface PageControl<T>{
items: T[] | null;
hasNext: boolean;
hasPrevious: boolean;
nextPage(): void;
previousPage(): void;
}
export interface FieldInfo {
name: string;
type: string;
title: string;
format?: string;
}
```
`types/survey.ts`
```ts
import {UniqueItem} from "./common.ts";
export interface Survey extends UniqueItem{
title: string;
description: string;
}
interface Statement extends UniqueItem{
text: string;
score_variable: number;
}
export enum QuestionType{
QuestionPair,
AgreementQuestion
}
export interface Question extends UniqueItem{
questionType: QuestionType
}
export interface QuestionPair extends Question{
statements: Statement[]
}
export interface AgreementQuestion extends Question{
question: string;
score_variable: number;
}
export interface ScoreVariable {
id: string;
name: string;
title: string;
description: string;
survey: number;
}
export interface Profession extends UniqueItem {
name: string;
description: string;
}
export interface Specialty extends UniqueItem {
name: string;
institution: number;
link?: string;
}
export interface Institution extends UniqueItem {
name: string;
}
```
`types/users.ts`
```ts
import {UniqueItem} from "./common.ts";
export type UserContextType = {
user: Account | undefined;
login: (credentials: TokenObtainPair) => Promise<void>;
logout: () => void;
};
export interface ContactData{
first_name: string;
last_name?: string;
middle_name?: string;
phone?: string;
email?:string;
}
export interface Account extends UniqueItem, ContactData{
login: string;
role?: number;
roleTitle?: string;
is_staff: boolean;
is_active: boolean;
}
export interface TokenObtainPair {
login: string;
password: string;
}
export interface TokenRefresh {
refresh: string;
}
export interface TokenVerify {
token: string;
}
export interface JwtTokenResponse {
access: string;
refresh: string;
}
```
## Способы запросов
Вместо fetch запросы должны проходить при помощи специальных функций/функции
`API/common.ts`
```ts
async function getFetch(path: string) // Get method
async function postFetch(
path: string,
body: object | FormData
) // Post method
async function patchFetch(
path: string,
body: object | FormData
) // Patch method
async function deleteFetch(path: string) // Delete method
```
## Хуки
### Для загрузки данных
Для упрощения работы с api созданы следующие хуки
`API/hooks.ts`
```ts
function useDataPage<T>(application:string, endpoint: string, params:{[key:string]:string|number}={}, needLoad:boolean=true):PageControl<T>
function useData<T>(application:string, endpoint: string, id: string|number, needLoad:boolean=true): T|null|undefined
function useCachedData<T>(application: string, endpoint: string): (id: string | number, needLoad: boolean = true)=> T|undefined|null
```
- application - Название модуля
- endpoint - Название объекта над которым идёт работа
- id - id искомого объекта
- params - дополнительные параметры (например фильтрация)
- needLoad - указывает нужно ли загружать список/объект прямо сейчас
- null - загрузка еще не происходила
- undefined - не найдено
- T (объект)
### Для ленивой загрузки элементов
`components/LoadingData.tsx`
```tsx
function LoadingData({data, children}: {data: object|null|undefined, children: (ReactElement | null | undefined | boolean)[]})
```
Для загрузки отдельного элемента.
Если data
- null - Возвращает <div className={"loading"}>Идёт загрузка...</div>
- undefined - <Link className={"not-found"} to={"/"}>404 НЕ НАЙДЕНО</Link>
- иначе возвращает children
`components/LoadingList.tsx`
```tsx
function LoadingList({data, listElement}: {data: UniqueItem[]|null, listElement(e:UniqueItem, i:number):unknown})
```
Для загрузки списка. Если data не null - то возвращает элементы результаты `listElement`
### Примеры
```tsx
export function ProfessionPage() {
const { professionId } = useParams<{ professionId: string }>();
const profession = useData<Profession>('surveys', 'professions', professionId || 0);
const specialties = useDataPage<Specialty>('surveys', 'specialties', { profession: professionId || 0 }, !!profession);
const institutions = useCachedData<Institution>("surveys", "institutions");
return (
<div>
<LoadingData data={profession}>
<h1>{profession?.name}</h1>
<div className="description">
<ReactMarkdown>{profession?.description || ''}</ReactMarkdown>
</div>
<div className="specialties-block">
{specialties.items != null ? <h2>Где можно обучиться</h2>:null}
<LoadingList
data={specialties.items}
listElement={specialty => (
<SpecialtyBlock
key={specialty.id}
specialty={specialty as Specialty}
institution={institutions((specialty as Specialty).institution)}
/>
)}
/>
</div>
</LoadingData>
</div>
);
}
```
### Автодокументация
`api/hooks.ts`
```ts
/**
* Хук для получения документации swagger JSON и извлечения структур.
* @param applicationName Название модуля/приложения.
* @param endpointName Название эндпоинта.
* @returns Массив структур без ID с полями: название, тип, title, format.
*/
export function useApiDocumentation(
applicationName: string,
endpointName: string
): { schema: FieldInfo[] | null; loading: boolean; error: Error | null }
```
### Авторизация
Везде доступен хук `useUser():UserContextType | undefined `

View File

@@ -1,14 +1,7 @@
Ты Senior разработчик React. Ты пишешь дипломную работу по специальности "Информационные системы и программирование". Ты должен следовать примерам которые ты получаешь
и следовать теме "Проектирование и разработка системы "Офисный центр"". Твой проект - "Office Flow".
Твоя задача - писать код под задачи (отвечай ТОЛЬКО кодом). Ниже - то что есть на данный момент.
Я могу кидать тебе просто код или информацию. Если я не прошу писать код - отвечай только "Понял". Ты пишешь в формате markdown, поэтому правильно оформляй текст.
Код, по возможности, только тот который необходимо внести в проект. Может быть работа сразу над несколькими файлами
Шаблон ответа кодом:
`Путь и название файла`
```ts
// Код который должен быть в этом файле
```

File diff suppressed because one or more lines are too long

View File

@@ -1,138 +0,0 @@
`components/useTableFilters.tsx`
```ts
// добавьте новую функцию для экспорта CSV
export function useTableFilters(schema: FieldInfo[]| null, initialData: unknown[] | null) {
const [filters, setFilters] = useState<FiltersState>({})
const [visibleColumns, setVisibleColumns] = useState<VisibilityState>({})
// Инициализация видимости колонок
useMemo(() => {
if (!schema){
return;
}
const initialVisibility: VisibilityState = {}
schema.forEach(field => {
initialVisibility[field.name] = true
})
setVisibleColumns(initialVisibility)
}, [schema])
// Обновление фильтров
const handleFilterChange = useCallback((name: string, filterPart: unknown) => {
setFilters(prev => ({
...prev,
[name]: {
...prev[name],
...filterPart
}
}))
}, [])
// Переключатель видимости колонки
const handleColumnToggle = useCallback((name: string) => {
setVisibleColumns(prev => ({
...prev,
[name]: !prev[name]
}))
}, [])
// Функция экспорта данных в CSV
const handleExportCSV = useCallback(() => {
if (!initialData || !schema || initialData.length === 0) {
alert('Нет данных для экспорта')
return
}
const visibleFields = schema.filter(field => visibleColumns[field.name])
const header = visibleFields.map(field => `"${field.title.replace(/"/g, '""')}"`).join(';')
const rows = initialData
.filter(item => schema.every(field => {
const value = item[field.name]
const filter = filters[field.name]
if (!filter) return true
if (field.type === 'string') {
if (filter.searchText) {
if (typeof value !== 'string') return false
if (!value.toLowerCase().includes(filter.searchText.toLowerCase())) return false
}
if (filter.exactMatch && filter.searchText) {
return value.toLowerCase() === filter.searchText.toLowerCase()
}
if (filter.empty !== undefined) {
const isEmpty = value === '' || value === null || value === undefined
if (filter.empty && !isEmpty) return false
if (filter.notEmpty && isEmpty) return false
}
} else if (field.format === 'date') {
const dateValue = new Date(value as string).getTime()
if (filter.fromDate) {
const fromTime = new Date(filter.fromDate).getTime()
if (dateValue < fromTime) return false
}
if (filter.toDate) {
const toTime = new Date(filter.toDate).getTime()
if (dateValue > toTime) return false
}
} else if (field.type === 'number') {
const numValue = Number(value)
if (filter.gte !== undefined && numValue < filter.gte) return false
if (filter.lte !== undefined && numValue > filter.lte) return false
}
return true
}))
.map(item => {
const row = visibleFields.map(field => {
const val = item[field.name]
// Обработка null/undefined
const strVal = val !== undefined && val !== null ? String(val) : ''
// Экранирование кавычек
return `"${strVal.replace(/"/g, '""')}"`
})
return row.join(';')
})
const csvContent = [header, ...rows].join('\n')
// Создаем ссылку для скачивания
const blob = new Blob([csvContent], { type: 'text/csv' })
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = 'export.csv'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
URL.revokeObjectURL(url)
}, [initialData, schema, filters, visibleColumns])
return {
filters,
setFilters,
visibleColumns,
setVisibleColumns,
handleFilterChange,
handleColumnToggle,
filteredData,
handleExportCSV // добавьте сюда
}
}
```
`Ваш файл, где вызывается handleExport` (примеры использования)
```ts
const {
filters,
handleFilterChange,
visibleColumns,
handleColumnToggle,
filteredData,
handleExportCSV // новая функция
} = useTableFilters(schema, dataPage.items)
const handleExport = async () => {
handleExportCSV()
}
```