Многосторнние изменения:
- Обновлены Angular и зависимости до последней версии (22.1.5, postcss, zod и т.д.) - Заменена загрузка данных в конструкторе на API resource() в task-list и task-details - Переименовать селекторы компонентов из app-* в ksk-crm-* - Добавлены конфиги окружения с настраиваемым API URL - Подключены @ng-icons/lucide для иконок - Добавлен шрифт Inter и CSS-переменные для темизации - Обновлён target tsconfig до ES2023 (для доступности методов в js)
This commit is contained in:
+14
-5
@@ -12,7 +12,7 @@
|
|||||||
"schematics": {},
|
"schematics": {},
|
||||||
"root": "",
|
"root": "",
|
||||||
"sourceRoot": "src",
|
"sourceRoot": "src",
|
||||||
"prefix": "app",
|
"prefix": "ksk-crm",
|
||||||
"architect": {
|
"architect": {
|
||||||
"build": {
|
"build": {
|
||||||
"builder": "@angular/build:application",
|
"builder": "@angular/build:application",
|
||||||
@@ -25,9 +25,7 @@
|
|||||||
"input": "public"
|
"input": "public"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": ["src/styles.css"]
|
||||||
"src/styles.css"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
@@ -48,7 +46,13 @@
|
|||||||
"development": {
|
"development": {
|
||||||
"optimization": false,
|
"optimization": false,
|
||||||
"extractLicenses": false,
|
"extractLicenses": false,
|
||||||
"sourceMap": true
|
"sourceMap": true,
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.development.ts"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"defaultConfiguration": "production"
|
"defaultConfiguration": "production"
|
||||||
@@ -63,6 +67,11 @@
|
|||||||
"buildTarget": "kskcrmspa:build:development"
|
"buildTarget": "kskcrmspa:build:development"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"options": {
|
||||||
|
"host": "0.0.0.0",
|
||||||
|
"port": 4200,
|
||||||
|
"allowedHosts": true
|
||||||
|
},
|
||||||
"defaultConfiguration": "development"
|
"defaultConfiguration": "development"
|
||||||
},
|
},
|
||||||
"test": {
|
"test": {
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
"@angular/forms": "^22.1.0",
|
"@angular/forms": "^22.1.0",
|
||||||
"@angular/platform-browser": "^22.1.0",
|
"@angular/platform-browser": "^22.1.0",
|
||||||
"@angular/router": "^22.1.0",
|
"@angular/router": "^22.1.0",
|
||||||
|
"@fontsource/inter": "^5.3.0",
|
||||||
|
"@ng-icons/core": "^36.0.0",
|
||||||
|
"@ng-icons/lucide": "^36.0.0",
|
||||||
"pocketbase": "^0.28.0",
|
"pocketbase": "^0.28.0",
|
||||||
"rxjs": "~7.8.0",
|
"rxjs": "~7.8.0",
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
|
|||||||
Generated
+292
-245
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
|||||||
|
allowBuilds:
|
||||||
|
'@parcel/watcher': true
|
||||||
|
esbuild: true
|
||||||
|
lmdb: true
|
||||||
|
msgpackr-extract: true
|
||||||
@@ -2,11 +2,10 @@ import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/
|
|||||||
import { provideRouter } from '@angular/router';
|
import { provideRouter } from '@angular/router';
|
||||||
|
|
||||||
import { routes } from './app.routes';
|
import { routes } from './app.routes';
|
||||||
import { provideClientHydration } from '@angular/platform-browser';
|
|
||||||
|
|
||||||
export const appConfig: ApplicationConfig = {
|
export const appConfig: ApplicationConfig = {
|
||||||
providers: [
|
providers: [
|
||||||
provideBrowserGlobalErrorListeners(),
|
provideBrowserGlobalErrorListeners(),
|
||||||
provideRouter(routes), provideClientHydration()
|
provideRouter(routes)
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
+10
-14
@@ -2,31 +2,27 @@ import { Component } from '@angular/core';
|
|||||||
import { RouterLink, RouterOutlet } from '@angular/router';
|
import { RouterLink, RouterOutlet } from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'ksk-crm-root',
|
||||||
imports: [RouterOutlet, RouterLink],
|
imports: [RouterOutlet],
|
||||||
template: `
|
template: `
|
||||||
<main>
|
<main>
|
||||||
<a [routerLink]="['/']">На главную</a>
|
<router-outlet />
|
||||||
<section class="content">
|
|
||||||
<router-outlet />
|
|
||||||
</section>
|
|
||||||
</main>
|
</main>
|
||||||
`,
|
`,
|
||||||
styles: `
|
styles: `
|
||||||
:host {
|
:host {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 20px;
|
padding: 8px;
|
||||||
min-height: 100vh;
|
min-height: 100dvh;
|
||||||
background: #2e2e2e;
|
background: var(--bg-base);
|
||||||
|
|
||||||
main {
|
main {
|
||||||
width: 60%;
|
width: 100%;
|
||||||
min-height: 500px;
|
background: var(--surface);
|
||||||
background: white;
|
padding: 1ch;
|
||||||
padding: 20px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
|||||||
@@ -1,31 +1,25 @@
|
|||||||
import { ChangeDetectorRef, Component, inject } from '@angular/core';
|
import { ActivatedRoute, RouterLink } from '@angular/router';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
|
||||||
import { TaskService } from './task-service';
|
import { TaskService } from './task-service';
|
||||||
import { Task } from './task';
|
import { Task } from './task';
|
||||||
|
import { Component, inject, resource, signal } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-task-details',
|
selector: 'ksk-crm-task-details',
|
||||||
imports: [],
|
imports: [RouterLink],
|
||||||
template: `
|
template: `
|
||||||
<p>{{ task?.name }}</p>
|
<a [routerLink]="['/']">На главную</a>
|
||||||
<p>{{ task?.numberPhone }}</p>
|
<p>{{ taskResource.value()?.name }}</p>
|
||||||
<p>{{ task?.streetAddress }}</p>
|
<p>{{ taskResource.value()?.numberPhone }}</p>
|
||||||
|
<p>{{ taskResource.value()?.streetAddress }}</p>
|
||||||
`,
|
`,
|
||||||
styles: ``,
|
styles: ``,
|
||||||
})
|
})
|
||||||
export class TaskDetails {
|
export class TaskDetails {
|
||||||
route: ActivatedRoute = inject(ActivatedRoute);
|
route: ActivatedRoute = inject(ActivatedRoute);
|
||||||
taskId = '';
|
|
||||||
taskService: TaskService = inject(TaskService);
|
taskService: TaskService = inject(TaskService);
|
||||||
changeDetectorRef = inject(ChangeDetectorRef);
|
taskId = signal(this.route.snapshot.params['id']);
|
||||||
task: Task | undefined;
|
taskResource = resource<Task | null, string>({
|
||||||
constructor() {
|
params: () => this.taskId(),
|
||||||
this.taskId = this.route.snapshot.params['id'];
|
loader: ({ params: id }) => this.taskService.getTaskById(id),
|
||||||
this.taskService.getTaskById(this.taskId).then(task => {
|
});
|
||||||
if (task) {
|
|
||||||
this.task = task;
|
|
||||||
this.changeDetectorRef.markForCheck()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,13 @@ import { Task } from './task';
|
|||||||
import { RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-task-item',
|
selector: 'ksk-crm-task-item',
|
||||||
imports: [
|
imports: [
|
||||||
RouterLink
|
RouterLink
|
||||||
],
|
],
|
||||||
template: `
|
template: `
|
||||||
<p>{{ task().name }}</p>
|
<p>{{ task().name }}</p>
|
||||||
<p>{{ task().city }}, {{ task().streetAddress }}</p>
|
<p>{{ task().city }}, {{ task().streetAddress }}</p>
|
||||||
<p>{{ task().numberPhone }}</p>
|
|
||||||
<p><a [routerLink]="['/details', task().id]">Подробнее...</a></p>
|
<p><a [routerLink]="['/details', task().id]">Подробнее...</a></p>
|
||||||
`,
|
`,
|
||||||
styles: `
|
styles: `
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
import { Component, computed, inject, signal } from '@angular/core';
|
import { Component, computed, inject, linkedSignal, resource, signal } from '@angular/core';
|
||||||
import { TaskItem } from './task-item';
|
import { TaskItem } from './task-item';
|
||||||
import { Task } from './task';
|
import { Task } from './task';
|
||||||
import { TaskService } from './task-service';
|
import { TaskService } from './task-service';
|
||||||
import { RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { NgIcon, provideIcons } from '@ng-icons/core';
|
||||||
|
import { lucideSquarePlus } from '@ng-icons/lucide';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-home-page',
|
selector: 'ksk-crm-home-page',
|
||||||
imports: [TaskItem, RouterLink, FormsModule],
|
imports: [TaskItem, RouterLink, FormsModule, NgIcon],
|
||||||
|
providers: [provideIcons({ lucideSquarePlus })],
|
||||||
template: `
|
template: `
|
||||||
<section>
|
<section>
|
||||||
<a [routerLink]="['/new']">Добавить</a><br>
|
|
||||||
<input [(ngModel)]="searchInput" type="text" />
|
<input [(ngModel)]="searchInput" type="text" />
|
||||||
|
<a routerLink="/new"><ng-icon name="lucideSquarePlus" size="20" /> </a>
|
||||||
</section>
|
</section>
|
||||||
<section class="result">
|
<section class="result">
|
||||||
@for (task of filteredTasks(); track $index) {
|
@for (task of filteredTasks(); track $index) {
|
||||||
<app-task-item [task]="task" />
|
<ksk-crm-task-item [task]="task" />
|
||||||
}
|
}
|
||||||
</section>
|
</section>
|
||||||
`,
|
`,
|
||||||
@@ -34,13 +37,23 @@ import { FormsModule } from '@angular/forms';
|
|||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
export class TaskList {
|
export class TaskList {
|
||||||
tasks: Task[] = [];
|
|
||||||
taskService: TaskService = inject(TaskService);
|
taskService: TaskService = inject(TaskService);
|
||||||
|
|
||||||
|
tasks = resource<Task[], null>({
|
||||||
|
params: signal(null),
|
||||||
|
loader: () => this.taskService.getAllTasks(),
|
||||||
|
});
|
||||||
|
|
||||||
searchInput = signal('');
|
searchInput = signal('');
|
||||||
|
|
||||||
filteredTasks = computed<Task[]>(() => {
|
filteredTasks = computed<Task[]>(() => {
|
||||||
const s = this.searchInput();
|
const s = this.searchInput();
|
||||||
if (s === '') return this.tasks;
|
const tasks = this.tasks.value();
|
||||||
return this.tasks.filter(
|
|
||||||
|
if (!tasks) return [];
|
||||||
|
if (s === '') return tasks;
|
||||||
|
|
||||||
|
return tasks.filter(
|
||||||
(task) =>
|
(task) =>
|
||||||
task.name.includes(s) ||
|
task.name.includes(s) ||
|
||||||
task.city.includes(s) ||
|
task.city.includes(s) ||
|
||||||
@@ -48,12 +61,4 @@ export class TaskList {
|
|||||||
task.numberPhone.includes(s),
|
task.numberPhone.includes(s),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.taskService.getAllTasks().then(tasks => {
|
|
||||||
this.tasks = tasks;
|
|
||||||
this.searchInput.update(_ => " ")
|
|
||||||
this.searchInput.update(_ => '');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
|||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-task-new',
|
selector: 'ksk-crm-task-new',
|
||||||
imports: [
|
imports: [
|
||||||
ReactiveFormsModule
|
ReactiveFormsModule
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { Service } from '@angular/core';
|
import { Service } from '@angular/core';
|
||||||
import { Task } from './task';
|
import { Task } from './task';
|
||||||
import PocketBase from 'pocketbase'
|
import PocketBase from 'pocketbase'
|
||||||
|
import { environment } from '../../../environments/environment'
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class TaskService {
|
export class TaskService {
|
||||||
pbTasks = new PocketBase('http://127.0.0.1:8090').collection<Task>('tasks');
|
private apiUrl = environment.apiUrl;
|
||||||
|
private pbTasks = new PocketBase(this.apiUrl).collection<Task>('tasks');
|
||||||
|
|
||||||
async getAllTasks(): Promise<Task[]> {
|
async getAllTasks(): Promise<Task[]> {
|
||||||
return await this.pbTasks.getFullList();
|
return await this.pbTasks.getFullList();
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export const environment = {
|
||||||
|
production: false,
|
||||||
|
apiUrl: "http://192.168.1.22:8090",
|
||||||
|
};
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export const environment = {
|
||||||
|
production: true,
|
||||||
|
apiUrl: 'http://192.168.1.22:8090',
|
||||||
|
};
|
||||||
+1
-1
@@ -9,6 +9,6 @@
|
|||||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<app-root></app-root>
|
<ksk-crm-root></ksk-crm-root>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,5 +1,24 @@
|
|||||||
|
@import '@fontsource/inter/400.css';
|
||||||
|
@import '@fontsource/inter/500.css';
|
||||||
|
@import '@fontsource/inter/600.css';
|
||||||
|
@import '@fontsource/inter/700.css';
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--gray: oklch(28% 0 0);
|
||||||
|
--white: white;
|
||||||
|
|
||||||
|
--font-family-base: 'Inter';
|
||||||
|
|
||||||
|
--bg-base: var(--gray);
|
||||||
|
--surface: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: var(--font-family-base), system-ui, -apple-system, sans-serif;
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@
|
|||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"importHelpers": true,
|
"importHelpers": true,
|
||||||
"target": "ES2022",
|
"target": "ES2023",
|
||||||
"module": "preserve"
|
"module": "preserve"
|
||||||
},
|
},
|
||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
|
|||||||
Reference in New Issue
Block a user