Woolfich commited on
Commit
ac4facb
·
verified ·
1 Parent(s): 42bc60d

теперь логику на rust

Browse files
Files changed (5) hide show
  1. Cargo.toml +14 -0
  2. plan.html +83 -35
  3. server.rs +145 -0
  4. welder-card.html +73 -23
  5. welders.html +54 -24
Cargo.toml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ```toml
2
+ [package]
3
+ name = "welders-api"
4
+ version = "0.1.0"
5
+ edition = "2021"
6
+
7
+ [dependencies]
8
+ actix-web = "4.0"
9
+ serde = { version = "1.0", features = ["derive"] }
10
+ serde_json = "1.0"
11
+ tokio = { version = "1.0", features = ["full"] }
12
+ ```
13
+
14
+ Now let's update the frontend to use this API:
plan.html CHANGED
@@ -28,47 +28,16 @@
28
  </div>
29
  </div>
30
  </div>
31
-
32
  <!-- Plan List -->
33
- <div class="p-4 space-y-4 mb-24">
34
- <!-- Plan Item (Completed) -->
35
- <div class="bg-white rounded-lg shadow overflow-hidden completed-plan">
36
- <div class="p-4">
37
- <div class="flex items-center">
38
- <div class="flex-1">
39
- <div class="font-medium">HT637</div>
40
- </div>
41
- <div class="text-green-500 font-medium">6/6</div>
42
- </div>
43
- <div class="mt-2 text-sm text-gray-500">
44
- <div>Johnson: 2, Smith: 2, Williams: 2</div>
45
- </div>
46
- </div>
47
- </div>
48
-
49
- <!-- Plan Item (In Progress) -->
50
- <div class="bg-white rounded-lg shadow overflow-hidden">
51
- <div class="p-4">
52
- <div class="flex items-center">
53
- <div class="flex-1">
54
- <div class="font-medium">HT52</div>
55
- </div>
56
- <div class="text-gray-500">3/∞</div>
57
- </div>
58
- <div class="mt-2 text-sm text-gray-500">
59
- <div>Johnson: 1, Williams: 2</div>
60
- </div>
61
- </div>
62
- </div>
63
- </div>
64
 
65
  <!-- Fixed Bottom Panel -->
66
  <div class="fixed bottom-0 left-0 right-0 bg-white shadow-md z-10 p-4">
67
  <div class="font-medium mb-2 text-gray-700">Norms</div>
68
  <div class="flex">
69
- <input type="text" placeholder="Article" class="flex-1 p-2 border rounded-l">
70
- <input type="text" placeholder="Time norm" class="w-24 p-2 border-t border-b">
71
- <button class="bg-gray-600 text-white px-4 rounded-r flex items-center">
72
  <i data-feather="plus" class="mr-2"></i>Add
73
  </button>
74
  </div>
@@ -76,6 +45,85 @@
76
 
77
  <script>
78
  feather.replace();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  </script>
80
  </body>
81
  </html>
 
28
  </div>
29
  </div>
30
  </div>
 
31
  <!-- Plan List -->
32
+ <div id="plan-list" class="p-4 space-y-4 mb-24"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  <!-- Fixed Bottom Panel -->
35
  <div class="fixed bottom-0 left-0 right-0 bg-white shadow-md z-10 p-4">
36
  <div class="font-medium mb-2 text-gray-700">Norms</div>
37
  <div class="flex">
38
+ <input id="norm-article" type="text" placeholder="Article" class="flex-1 p-2 border rounded-l">
39
+ <input id="norm-time" type="number" placeholder="Time norm" step="0.1" class="w-24 p-2 border-t border-b">
40
+ <button id="add-norm" class="bg-gray-600 text-white px-4 rounded-r flex items-center">
41
  <i data-feather="plus" class="mr-2"></i>Add
42
  </button>
43
  </div>
 
45
 
46
  <script>
47
  feather.replace();
48
+
49
+ // Load plans and norms
50
+ async function loadData() {
51
+ try {
52
+ // Load plans
53
+ const plansResponse = await fetch('http://localhost:8080/plans');
54
+ const plans = await plansResponse.json();
55
+
56
+ const planList = document.getElementById('plan-list');
57
+ planList.innerHTML = '';
58
+
59
+ plans.forEach(plan => {
60
+ const assignments = Object.entries(plan.assignments)
61
+ .map(([welderId, qty]) => `${welderId}: ${qty}`)
62
+ .join(', ');
63
+
64
+ const planItem = document.createElement('div');
65
+ planItem.className = plan.completed_quantity === plan.total_quantity
66
+ ? 'bg-white rounded-lg shadow overflow-hidden completed-plan'
67
+ : 'bg-white rounded-lg shadow overflow-hidden';
68
+
69
+ planItem.innerHTML = `
70
+ <div class="p-4">
71
+ <div class="flex items-center">
72
+ <div class="flex-1">
73
+ <div class="font-medium">${plan.article_code}</div>
74
+ </div>
75
+ <div class="${plan.completed_quantity === plan.total_quantity ? 'text-green-500' : 'text-gray-500'} font-medium">
76
+ ${plan.completed_quantity}/${plan.total_quantity}
77
+ </div>
78
+ </div>
79
+ <div class="mt-2 text-sm text-gray-500">
80
+ <div>${assignments}</div>
81
+ </div>
82
+ </div>
83
+ `;
84
+ planList.appendChild(planItem);
85
+ });
86
+
87
+ // Load norms (could be used for display if needed)
88
+ const normsResponse = await fetch('http://localhost:8080/norms');
89
+ const norms = await normsResponse.json();
90
+ console.log('Loaded norms:', norms);
91
+ } catch (error) {
92
+ console.error('Error loading data:', error);
93
+ }
94
+ }
95
+
96
+ // Add new norm
97
+ document.getElementById('add-norm').addEventListener('click', async () => {
98
+ const article = document.getElementById('norm-article').value.trim();
99
+ const timeNorm = parseFloat(document.getElementById('norm-time').value);
100
+
101
+ if (article && !isNaN(timeNorm) && timeNorm > 0) {
102
+ try {
103
+ const response = await fetch('http://localhost:8080/norms', {
104
+ method: 'POST',
105
+ headers: {
106
+ 'Content-Type': 'application/json',
107
+ },
108
+ body: JSON.stringify({
109
+ article_code: article,
110
+ time_norm: timeNorm
111
+ }),
112
+ });
113
+
114
+ if (response.ok) {
115
+ document.getElementById('norm-article').value = '';
116
+ document.getElementById('norm-time').value = '';
117
+ console.log('Norm added successfully');
118
+ }
119
+ } catch (error) {
120
+ console.error('Error adding norm:', error);
121
+ }
122
+ }
123
+ });
124
+
125
+ // Load initial data
126
+ loadData();
127
  </script>
128
  </body>
129
  </html>
server.rs ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ```rust
2
+ use actix_web::{web, App, HttpServer, HttpResponse, Responder};
3
+ use serde::{Deserialize, Serialize};
4
+ use std::sync::Mutex;
5
+ use std::collections::HashMap;
6
+
7
+ // Data models
8
+ #[derive(Debug, Clone, Serialize, Deserialize)]
9
+ struct Welder {
10
+ id: u32,
11
+ name: String,
12
+ articles: Vec<Article>,
13
+ }
14
+
15
+ #[derive(Debug, Clone, Serialize, Deserialize)]
16
+ struct Article {
17
+ id: u32,
18
+ code: String,
19
+ quantity: u32,
20
+ completed: u32,
21
+ }
22
+
23
+ #[derive(Debug, Clone, Serialize, Deserialize)]
24
+ struct Plan {
25
+ id: u32,
26
+ article_code: String,
27
+ total_quantity: u32,
28
+ completed_quantity: u32,
29
+ assignments: HashMap<u32, u32>, // welder_id -> quantity
30
+ }
31
+
32
+ #[derive(Debug, Serialize, Deserialize)]
33
+ struct Norm {
34
+ article_code: String,
35
+ time_norm: f32, // hours per unit
36
+ }
37
+
38
+ // App state
39
+ struct AppState {
40
+ welders: Mutex<Vec<Welder>>,
41
+ plans: Mutex<Vec<Plan>>,
42
+ norms: Mutex<Vec<Norm>>,
43
+ next_welder_id: Mutex<u32>,
44
+ next_article_id: Mutex<u32>,
45
+ next_plan_id: Mutex<u32>,
46
+ }
47
+
48
+ // REST API handlers
49
+ async fn get_welders(data: web::Data<AppState>) -> impl Responder {
50
+ let welders = data.welders.lock().unwrap();
51
+ HttpResponse::Ok().json(welders.clone())
52
+ }
53
+
54
+ async fn add_welder(data: web::Data<AppState>, welder: web::Json<Welder>) -> impl Responder {
55
+ let mut welders = data.welders.lock().unwrap();
56
+ let mut next_id = data.next_welder_id.lock().unwrap();
57
+ let new_welder = Welder {
58
+ id: *next_id,
59
+ name: welder.name.clone(),
60
+ articles: vec![],
61
+ };
62
+ *next_id += 1;
63
+ welders.push(new_welder.clone());
64
+ HttpResponse::Created().json(new_welder)
65
+ }
66
+
67
+ async fn get_plans(data: web::Data<AppState>) -> impl Responder {
68
+ let plans = data.plans.lock().unwrap();
69
+ HttpResponse::Ok().json(plans.clone())
70
+ }
71
+
72
+ async fn add_plan(data: web::Data<AppState>, plan: web::Json<Plan>) -> impl Responder {
73
+ let mut plans = data.plans.lock().unwrap();
74
+ let mut next_id = data.next_plan_id.lock().unwrap();
75
+ let mut new_plan = plan.into_inner();
76
+ new_plan.id = *next_id;
77
+ *next_id += 1;
78
+ plans.push(new_plan.clone());
79
+ HttpResponse::Created().json(new_plan)
80
+ }
81
+
82
+ async fn get_norms(data: web::Data<AppState>) -> impl Responder {
83
+ let norms = data.norms.lock().unwrap();
84
+ HttpResponse::Ok().json(norms.clone())
85
+ }
86
+
87
+ async fn add_norm(data: web::Data<AppState>, norm: web::Json<Norm>) -> impl Responder {
88
+ let mut norms = data.norms.lock().unwrap();
89
+ norms.push(norm.into_inner());
90
+ HttpResponse::Created().json(norms.last().unwrap().clone())
91
+ }
92
+
93
+ async fn assign_article(
94
+ data: web::Data<AppState>,
95
+ path: web::Path<(u32,)>,
96
+ article: web::Json<Article>,
97
+ ) -> impl Responder {
98
+ let (welder_id,) = path.into_inner();
99
+ let mut welders = data.welders.lock().unwrap();
100
+ let mut next_article_id = data.next_article_id.lock().unwrap();
101
+
102
+ if let Some(welder) = welders.iter_mut().find(|w| w.id == welder_id) {
103
+ let new_article = Article {
104
+ id: *next_article_id,
105
+ code: article.code.clone(),
106
+ quantity: article.quantity,
107
+ completed: 0,
108
+ };
109
+ *next_article_id += 1;
110
+ welder.articles.push(new_article.clone());
111
+ HttpResponse::Created().json(new_article)
112
+ } else {
113
+ HttpResponse::NotFound().json("Welder not found")
114
+ }
115
+ }
116
+
117
+ #[actix_web::main]
118
+ async fn main() -> std::io::Result<()> {
119
+ // Initialize app state
120
+ let app_state = web::Data::new(AppState {
121
+ welders: Mutex::new(vec![]),
122
+ plans: Mutex::new(vec![]),
123
+ norms: Mutex::new(vec![]),
124
+ next_welder_id: Mutex::new(1),
125
+ next_article_id: Mutex::new(1),
126
+ next_plan_id: Mutex::new(1),
127
+ });
128
+
129
+ // Start HTTP server
130
+ HttpServer::new(move || {
131
+ App::new()
132
+ .app_data(app_state.clone())
133
+ .route("/welders", web::get().to(get_welders))
134
+ .route("/welders", web::post().to(add_welder))
135
+ .route("/welders/{id}/articles", web::post().to(assign_article))
136
+ .route("/plans", web::get().to(get_plans))
137
+ .route("/plans", web::post().to(add_plan))
138
+ .route("/norms", web::get().to(get_norms))
139
+ .route("/norms", web::post().to(add_norm))
140
+ })
141
+ .bind("127.0.0.1:8080")?
142
+ .run()
143
+ .await
144
+ }
145
+ ```
welder-card.html CHANGED
@@ -31,33 +31,83 @@
31
  </button>
32
  </div>
33
  </div>
34
-
35
  <!-- Articles List -->
36
- <div class="p-4 space-y-4 mb-20">
37
- <!-- Month Divider -->
38
- <div class="bg-gray-200 px-4 py-2 rounded font-medium">August 2023</div>
39
-
40
- <!-- Article Items -->
41
- <div class="bg-white rounded-lg shadow overflow-hidden">
42
- <div class="p-4 border-b flex items-center">
43
- <div class="flex-1">
44
- <div class="font-medium">HT637</div>
45
- <div class="text-sm text-gray-500">4 pieces</div>
46
- </div>
47
- <div class="text-green-500 font-medium">4/6</div>
48
- </div>
49
- <div class="p-4 flex items-center">
50
- <div class="flex-1">
51
- <div class="font-medium">HT52</div>
52
- <div class="text-sm text-gray-500">3 pieces</div>
53
- </div>
54
- <div class="text-gray-500">3/∞</div>
55
- </div>
56
- </div>
57
- </div>
58
 
59
  <script>
60
  feather.replace();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  </script>
62
  </body>
63
  </html>
 
31
  </button>
32
  </div>
33
  </div>
 
34
  <!-- Articles List -->
35
+ <div id="articles-list" class="p-4 space-y-4 mb-20"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
  <script>
38
  feather.replace();
39
+
40
+ // Get welder ID from URL
41
+ const urlParams = new URLSearchParams(window.location.search);
42
+ const welderId = urlParams.get('id');
43
+
44
+ // Load welder's articles
45
+ async function loadArticles() {
46
+ try {
47
+ const response = await fetch(`http://localhost:8080/welders/${welderId}/articles`);
48
+ const articles = await response.json();
49
+
50
+ const articlesList = document.getElementById('articles-list');
51
+ articlesList.innerHTML = '';
52
+
53
+ // Group articles by month (simplified example)
54
+ const monthDivider = document.createElement('div');
55
+ monthDivider.className = 'bg-gray-200 px-4 py-2 rounded font-medium';
56
+ monthDivider.textContent = new Date().toLocaleString('default', { month: 'long', year: 'numeric' });
57
+ articlesList.appendChild(monthDivider);
58
+
59
+ articles.forEach(article => {
60
+ const articleItem = document.createElement('div');
61
+ articleItem.className = 'bg-white rounded-lg shadow overflow-hidden';
62
+ articleItem.innerHTML = `
63
+ <div class="p-4 border-b flex items-center">
64
+ <div class="flex-1">
65
+ <div class="font-medium">${article.code}</div>
66
+ <div class="text-sm text-gray-500">${article.quantity} pieces</div>
67
+ </div>
68
+ <div class="${article.completed === article.quantity ? 'text-green-500' : 'text-gray-500'} font-medium">
69
+ ${article.completed}/${article.quantity}
70
+ </div>
71
+ </div>
72
+ `;
73
+ articlesList.appendChild(articleItem);
74
+ });
75
+ } catch (error) {
76
+ console.error('Error loading articles:', error);
77
+ }
78
+ }
79
+
80
+ // Add new article
81
+ document.querySelector('button.bg-blue-500').addEventListener('click', async () => {
82
+ const codeInput = document.querySelector('input[placeholder="Article"]');
83
+ const qtyInput = document.querySelector('input[placeholder="Qty"]');
84
+
85
+ const code = codeInput.value.trim();
86
+ const quantity = parseInt(qtyInput.value);
87
+
88
+ if (code && quantity > 0) {
89
+ try {
90
+ const response = await fetch(`http://localhost:8080/welders/${welderId}/articles`, {
91
+ method: 'POST',
92
+ headers: {
93
+ 'Content-Type': 'application/json',
94
+ },
95
+ body: JSON.stringify({ code, quantity }),
96
+ });
97
+
98
+ if (response.ok) {
99
+ codeInput.value = '';
100
+ qtyInput.value = '';
101
+ await loadArticles();
102
+ }
103
+ } catch (error) {
104
+ console.error('Error adding article:', error);
105
+ }
106
+ }
107
+ });
108
+
109
+ // Load initial data
110
+ loadArticles();
111
  </script>
112
  </body>
113
  </html>
welders.html CHANGED
@@ -92,33 +92,63 @@
92
  <script>
93
  // Initialize feather icons
94
  feather.replace();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
- // Sample data for demonstration
97
- const welders = [
98
- { id: 1, name: "Smith" },
99
- { id: 2, name: "Johnson" },
100
- { id: 3, name: "Williams" }
101
- ];
102
-
103
- // Render welder's list
104
- const weldersList = document.getElementById('welders-list');
105
- welders.forEach(welder => {
106
- const welderItem = document.createElement('div');
107
- welderItem.className = 'panel p-4 rounded-lg cursor-pointer transition hover:bg-gray-50';
108
- welderItem.innerHTML = `
109
- <div class="flex items-center">
110
- <i data-feather="user" class="text-gray-500 mr-3"></i>
111
- <span class="font-medium">${welder.name}</span>
112
- <i data-feather="chevron-right" class="ml-auto text-gray-400"></i>
113
- </div>
114
- `;
115
- welderItem.addEventListener('click', () => {
116
- window.location.href = `welder-card.html?id=${welder.id}`;
117
- });
118
- weldersList.appendChild(welderItem);
 
119
  });
120
 
121
- // Plan button click handler
 
 
122
  document.getElementById('plan-btn').addEventListener('click', () => {
123
  window.location.href = 'plan.html';
124
  });
 
92
  <script>
93
  // Initialize feather icons
94
  feather.replace();
95
+ // Fetch welders from API
96
+ async function loadWelders() {
97
+ try {
98
+ const response = await fetch('http://localhost:8080/welders');
99
+ const welders = await response.json();
100
+
101
+ const weldersList = document.getElementById('welders-list');
102
+ welders.forEach(welder => {
103
+ const welderItem = document.createElement('div');
104
+ welderItem.className = 'panel p-4 rounded-lg cursor-pointer transition hover:bg-gray-50';
105
+ welderItem.innerHTML = `
106
+ <div class="flex items-center">
107
+ <i data-feather="user" class="text-gray-500 mr-3"></i>
108
+ <span class="font-medium">${welder.name}</span>
109
+ <i data-feather="chevron-right" class="ml-auto text-gray-400"></i>
110
+ </div>
111
+ `;
112
+ welderItem.addEventListener('click', () => {
113
+ window.location.href = `welder-card.html?id=${welder.id}`;
114
+ });
115
+ weldersList.appendChild(welderItem);
116
+ });
117
+ feather.replace();
118
+ } catch (error) {
119
+ console.error('Error loading welders:', error);
120
+ }
121
+ }
122
 
123
+ // Add new welder
124
+ document.querySelector('button.btn-primary').addEventListener('click', async () => {
125
+ const input = document.querySelector('input');
126
+ const name = input.value.trim();
127
+
128
+ if (name) {
129
+ try {
130
+ const response = await fetch('http://localhost:8080/welders', {
131
+ method: 'POST',
132
+ headers: {
133
+ 'Content-Type': 'application/json',
134
+ },
135
+ body: JSON.stringify({ name }),
136
+ });
137
+
138
+ if (response.ok) {
139
+ input.value = '';
140
+ document.getElementById('welders-list').innerHTML = '';
141
+ await loadWelders();
142
+ }
143
+ } catch (error) {
144
+ console.error('Error adding welder:', error);
145
+ }
146
+ }
147
  });
148
 
149
+ // Load initial data
150
+ loadWelders();
151
+ // Plan button click handler
152
  document.getElementById('plan-btn').addEventListener('click', () => {
153
  window.location.href = 'plan.html';
154
  });