wad-lab 1.1.4 → 1.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.js +30 -3
- package/package.json +1 -1
- package/templates/vue-axios-basic/src/App.vue +405 -405
- package/templates/vue-axios-pinia/src/App.vue +427 -427
- package/templates/vue-axios-props-emits/src/App.vue +167 -167
- package/templates/vue-axios-props-emits/src/components/DepartmentForm.vue +98 -98
- package/templates/vue-axios-props-emits/src/components/DepartmentList.vue +91 -91
- package/templates/vue-axios-props-emits/src/components/EmployeeForm.vue +128 -128
- package/templates/vue-axios-props-emits/src/components/EmployeeList.vue +94 -94
- package/templates/vue-axios-router/src/App.vue +90 -90
- package/templates/vue-axios-router/src/views/AddEmployeeView.vue +247 -247
- package/templates/vue-axios-router/src/views/DepartmentView.vue +273 -273
- package/templates/vue-axios-router/src/views/EmployeeView.vue +196 -196
- package/templates/vue-axios-router/src/views/HomeDashboardView.vue +263 -263
- package/templates/vue-axios-router-props/src/App.vue +59 -59
|
@@ -1,263 +1,263 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import { ref, computed, onMounted } from 'vue'
|
|
3
|
-
import api from '../services/api'
|
|
4
|
-
|
|
5
|
-
const departments = ref([])
|
|
6
|
-
const employees = ref([])
|
|
7
|
-
const loading = ref(false)
|
|
8
|
-
const errorMessage = ref('')
|
|
9
|
-
|
|
10
|
-
const totalDepartments = computed(() => departments.value.length)
|
|
11
|
-
const totalEmployees = computed(() => employees.value.length)
|
|
12
|
-
|
|
13
|
-
const totalPayroll = computed(() => {
|
|
14
|
-
return employees.value.reduce((sum, emp) => sum + (Number(emp.salary) || 0), 0)
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
const averageSalary = computed(() => {
|
|
18
|
-
if (employees.value.length === 0) return 0
|
|
19
|
-
return Math.round(totalPayroll.value / employees.value.length)
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
async function fetchDashboardData() {
|
|
23
|
-
loading.value = true
|
|
24
|
-
errorMessage.value = ''
|
|
25
|
-
try {
|
|
26
|
-
const [deptRes, empRes] = await Promise.all([
|
|
27
|
-
api.get('/departments'),
|
|
28
|
-
api.get('/employees')
|
|
29
|
-
])
|
|
30
|
-
departments.value = deptRes.data
|
|
31
|
-
employees.value = empRes.data
|
|
32
|
-
} catch (err) {
|
|
33
|
-
errorMessage.value = err.message || 'Failed to load dashboard data'
|
|
34
|
-
} finally {
|
|
35
|
-
loading.value = false
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
onMounted(() => {
|
|
40
|
-
fetchDashboardData()
|
|
41
|
-
})
|
|
42
|
-
</script>
|
|
43
|
-
|
|
44
|
-
<template>
|
|
45
|
-
<div class="dashboard-view">
|
|
46
|
-
<h2>Dashboard Overview</h2>
|
|
47
|
-
|
|
48
|
-
<div v-if="loading" class="state-msg">Loading dashboard stats...</div>
|
|
49
|
-
<div v-if="errorMessage" class="state-msg error">{{ errorMessage }}</div>
|
|
50
|
-
|
|
51
|
-
<div class="stats-grid">
|
|
52
|
-
<div class="stat-card">
|
|
53
|
-
<h3>Departments</h3>
|
|
54
|
-
<p class="stat-value">{{ totalDepartments }}</p>
|
|
55
|
-
<router-link to="/departments" class="stat-link">View all departments →</router-link>
|
|
56
|
-
</div>
|
|
57
|
-
|
|
58
|
-
<div class="stat-card">
|
|
59
|
-
<h3>Employees</h3>
|
|
60
|
-
<p class="stat-value">{{ totalEmployees }}</p>
|
|
61
|
-
<router-link to="/employees" class="stat-link">View all employees →</router-link>
|
|
62
|
-
</div>
|
|
63
|
-
|
|
64
|
-
<div class="stat-card">
|
|
65
|
-
<h3>Total Payroll</h3>
|
|
66
|
-
<p class="stat-value">${{ totalPayroll.toLocaleString() }}</p>
|
|
67
|
-
<span class="stat-sub">Monthly expenditure</span>
|
|
68
|
-
</div>
|
|
69
|
-
|
|
70
|
-
<div class="stat-card">
|
|
71
|
-
<h3>Average Salary</h3>
|
|
72
|
-
<p class="stat-value">${{ averageSalary.toLocaleString() }}</p>
|
|
73
|
-
<span class="stat-sub">Per employee</span>
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
|
|
77
|
-
<div class="dashboard-sections">
|
|
78
|
-
<div class="section-card">
|
|
79
|
-
<div class="section-header">
|
|
80
|
-
<h3>Departments Overview</h3>
|
|
81
|
-
<router-link to="/departments" class="action-btn">Manage</router-link>
|
|
82
|
-
</div>
|
|
83
|
-
<ul v-if="departments.length > 0" class="item-list">
|
|
84
|
-
<li v-for="dept in departments" :key="dept.id" class="list-row">
|
|
85
|
-
<strong>{{ dept.name }}</strong>
|
|
86
|
-
<span class="badge">{{ dept.code }}</span>
|
|
87
|
-
</li>
|
|
88
|
-
</ul>
|
|
89
|
-
<p v-else class="empty-text">No departments recorded.</p>
|
|
90
|
-
</div>
|
|
91
|
-
|
|
92
|
-
<div class="section-card">
|
|
93
|
-
<div class="section-header">
|
|
94
|
-
<h3>Recent Employees</h3>
|
|
95
|
-
<router-link to="/add-employee" class="action-btn">+ Add New</router-link>
|
|
96
|
-
</div>
|
|
97
|
-
<ul v-if="employees.length > 0" class="item-list">
|
|
98
|
-
<li v-for="emp in employees.slice(-5)" :key="emp.id" class="list-row">
|
|
99
|
-
<div>
|
|
100
|
-
<strong>{{ emp.name }}</strong>
|
|
101
|
-
<small class="muted-text">({{ emp.email }})</small>
|
|
102
|
-
</div>
|
|
103
|
-
<span class="salary-text">${{ Number(emp.salary || 0).toLocaleString() }}</span>
|
|
104
|
-
</li>
|
|
105
|
-
</ul>
|
|
106
|
-
<p v-else class="empty-text">No employees recorded.</p>
|
|
107
|
-
</div>
|
|
108
|
-
</div>
|
|
109
|
-
</div>
|
|
110
|
-
</template>
|
|
111
|
-
|
|
112
|
-
<style scoped>
|
|
113
|
-
.dashboard-view {
|
|
114
|
-
display: flex;
|
|
115
|
-
flex-direction: column;
|
|
116
|
-
gap: 20px;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
h2 {
|
|
120
|
-
margin: 0;
|
|
121
|
-
color: #2c3e50;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
.state-msg {
|
|
125
|
-
padding: 10px;
|
|
126
|
-
background-color: #f8f9fa;
|
|
127
|
-
border: 1px solid #ddd;
|
|
128
|
-
border-radius: 4px;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
.state-msg.error {
|
|
132
|
-
background-color: #fde8e8;
|
|
133
|
-
color: #c0392b;
|
|
134
|
-
border-color: #f5c6cb;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
.stats-grid {
|
|
138
|
-
display: grid;
|
|
139
|
-
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
140
|
-
gap: 16px;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
.stat-card {
|
|
144
|
-
background: #ffffff;
|
|
145
|
-
border: 1px solid #ddd;
|
|
146
|
-
border-radius: 6px;
|
|
147
|
-
padding: 16px;
|
|
148
|
-
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
.stat-card h3 {
|
|
152
|
-
margin: 0 0 8px 0;
|
|
153
|
-
font-size: 14px;
|
|
154
|
-
color: #666;
|
|
155
|
-
text-transform: uppercase;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
.stat-value {
|
|
159
|
-
margin: 0 0 10px 0;
|
|
160
|
-
font-size: 28px;
|
|
161
|
-
font-weight: bold;
|
|
162
|
-
color: #2c3e50;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
.stat-link {
|
|
166
|
-
font-size: 13px;
|
|
167
|
-
color: #3498db;
|
|
168
|
-
text-decoration: none;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
.stat-link:hover {
|
|
172
|
-
text-decoration: underline;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
.stat-sub {
|
|
176
|
-
font-size: 13px;
|
|
177
|
-
color: #888;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
.dashboard-sections {
|
|
181
|
-
display: grid;
|
|
182
|
-
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
183
|
-
gap: 16px;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
.section-card {
|
|
187
|
-
background: #ffffff;
|
|
188
|
-
border: 1px solid #ddd;
|
|
189
|
-
border-radius: 6px;
|
|
190
|
-
padding: 16px;
|
|
191
|
-
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
.section-header {
|
|
195
|
-
display: flex;
|
|
196
|
-
justify-content: space-between;
|
|
197
|
-
align-items: center;
|
|
198
|
-
margin-bottom: 12px;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
.section-header h3 {
|
|
202
|
-
margin: 0;
|
|
203
|
-
font-size: 16px;
|
|
204
|
-
color: #2c3e50;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
.action-btn {
|
|
208
|
-
font-size: 12px;
|
|
209
|
-
padding: 4px 8px;
|
|
210
|
-
background: #2c3e50;
|
|
211
|
-
color: #ffffff;
|
|
212
|
-
text-decoration: none;
|
|
213
|
-
border-radius: 4px;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
.action-btn:hover {
|
|
217
|
-
background: #34495e;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
.item-list {
|
|
221
|
-
list-style: none;
|
|
222
|
-
padding: 0;
|
|
223
|
-
margin: 0;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
.list-row {
|
|
227
|
-
display: flex;
|
|
228
|
-
justify-content: space-between;
|
|
229
|
-
align-items: center;
|
|
230
|
-
padding: 8px 0;
|
|
231
|
-
border-bottom: 1px solid #eee;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
.list-row:last-child {
|
|
235
|
-
border-bottom: none;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
.badge {
|
|
239
|
-
background: #ecf0f1;
|
|
240
|
-
color: #2c3e50;
|
|
241
|
-
padding: 2px 6px;
|
|
242
|
-
border-radius: 3px;
|
|
243
|
-
font-size: 12px;
|
|
244
|
-
font-family: monospace;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
.muted-text {
|
|
248
|
-
margin-left: 6px;
|
|
249
|
-
color: #7f8c8d;
|
|
250
|
-
font-size: 12px;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
.salary-text {
|
|
254
|
-
font-weight: bold;
|
|
255
|
-
color: #27ae60;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
.empty-text {
|
|
259
|
-
color: #7f8c8d;
|
|
260
|
-
font-size: 14px;
|
|
261
|
-
margin: 8px 0;
|
|
262
|
-
}
|
|
263
|
-
</style>
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref, computed, onMounted } from 'vue'
|
|
3
|
+
import api from '../services/api'
|
|
4
|
+
|
|
5
|
+
const departments = ref([])
|
|
6
|
+
const employees = ref([])
|
|
7
|
+
const loading = ref(false)
|
|
8
|
+
const errorMessage = ref('')
|
|
9
|
+
|
|
10
|
+
const totalDepartments = computed(() => departments.value.length)
|
|
11
|
+
const totalEmployees = computed(() => employees.value.length)
|
|
12
|
+
|
|
13
|
+
const totalPayroll = computed(() => {
|
|
14
|
+
return employees.value.reduce((sum, emp) => sum + (Number(emp.salary) || 0), 0)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const averageSalary = computed(() => {
|
|
18
|
+
if (employees.value.length === 0) return 0
|
|
19
|
+
return Math.round(totalPayroll.value / employees.value.length)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
async function fetchDashboardData() {
|
|
23
|
+
loading.value = true
|
|
24
|
+
errorMessage.value = ''
|
|
25
|
+
try {
|
|
26
|
+
const [deptRes, empRes] = await Promise.all([
|
|
27
|
+
api.get('/departments'),
|
|
28
|
+
api.get('/employees')
|
|
29
|
+
])
|
|
30
|
+
departments.value = deptRes.data
|
|
31
|
+
employees.value = empRes.data
|
|
32
|
+
} catch (err) {
|
|
33
|
+
errorMessage.value = err.message || 'Failed to load dashboard data'
|
|
34
|
+
} finally {
|
|
35
|
+
loading.value = false
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
onMounted(() => {
|
|
40
|
+
fetchDashboardData()
|
|
41
|
+
})
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<template>
|
|
45
|
+
<div class="dashboard-view">
|
|
46
|
+
<h2>Dashboard Overview</h2>
|
|
47
|
+
|
|
48
|
+
<div v-if="loading" class="state-msg">Loading dashboard stats...</div>
|
|
49
|
+
<div v-if="errorMessage" class="state-msg error">{{ errorMessage }}</div>
|
|
50
|
+
|
|
51
|
+
<div class="stats-grid">
|
|
52
|
+
<div class="stat-card">
|
|
53
|
+
<h3>Departments</h3>
|
|
54
|
+
<p class="stat-value">{{ totalDepartments }}</p>
|
|
55
|
+
<router-link to="/departments" class="stat-link">View all departments →</router-link>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<div class="stat-card">
|
|
59
|
+
<h3>Employees</h3>
|
|
60
|
+
<p class="stat-value">{{ totalEmployees }}</p>
|
|
61
|
+
<router-link to="/employees" class="stat-link">View all employees →</router-link>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<div class="stat-card">
|
|
65
|
+
<h3>Total Payroll</h3>
|
|
66
|
+
<p class="stat-value">${{ totalPayroll.toLocaleString() }}</p>
|
|
67
|
+
<span class="stat-sub">Monthly expenditure</span>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div class="stat-card">
|
|
71
|
+
<h3>Average Salary</h3>
|
|
72
|
+
<p class="stat-value">${{ averageSalary.toLocaleString() }}</p>
|
|
73
|
+
<span class="stat-sub">Per employee</span>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<div class="dashboard-sections">
|
|
78
|
+
<div class="section-card">
|
|
79
|
+
<div class="section-header">
|
|
80
|
+
<h3>Departments Overview</h3>
|
|
81
|
+
<router-link to="/departments" class="action-btn">Manage</router-link>
|
|
82
|
+
</div>
|
|
83
|
+
<ul v-if="departments.length > 0" class="item-list">
|
|
84
|
+
<li v-for="dept in departments" :key="dept.id" class="list-row">
|
|
85
|
+
<strong>{{ dept.name }}</strong>
|
|
86
|
+
<span class="badge">{{ dept.code }}</span>
|
|
87
|
+
</li>
|
|
88
|
+
</ul>
|
|
89
|
+
<p v-else class="empty-text">No departments recorded.</p>
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<div class="section-card">
|
|
93
|
+
<div class="section-header">
|
|
94
|
+
<h3>Recent Employees</h3>
|
|
95
|
+
<router-link to="/add-employee" class="action-btn">+ Add New</router-link>
|
|
96
|
+
</div>
|
|
97
|
+
<ul v-if="employees.length > 0" class="item-list">
|
|
98
|
+
<li v-for="emp in employees.slice(-5)" :key="emp.id" class="list-row">
|
|
99
|
+
<div>
|
|
100
|
+
<strong>{{ emp.name }}</strong>
|
|
101
|
+
<small class="muted-text">({{ emp.email }})</small>
|
|
102
|
+
</div>
|
|
103
|
+
<span class="salary-text">${{ Number(emp.salary || 0).toLocaleString() }}</span>
|
|
104
|
+
</li>
|
|
105
|
+
</ul>
|
|
106
|
+
<p v-else class="empty-text">No employees recorded.</p>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</template>
|
|
111
|
+
|
|
112
|
+
<style scoped>
|
|
113
|
+
.dashboard-view {
|
|
114
|
+
display: flex;
|
|
115
|
+
flex-direction: column;
|
|
116
|
+
gap: 20px;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
h2 {
|
|
120
|
+
margin: 0;
|
|
121
|
+
color: #2c3e50;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.state-msg {
|
|
125
|
+
padding: 10px;
|
|
126
|
+
background-color: #f8f9fa;
|
|
127
|
+
border: 1px solid #ddd;
|
|
128
|
+
border-radius: 4px;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.state-msg.error {
|
|
132
|
+
background-color: #fde8e8;
|
|
133
|
+
color: #c0392b;
|
|
134
|
+
border-color: #f5c6cb;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.stats-grid {
|
|
138
|
+
display: grid;
|
|
139
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
140
|
+
gap: 16px;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.stat-card {
|
|
144
|
+
background: #ffffff;
|
|
145
|
+
border: 1px solid #ddd;
|
|
146
|
+
border-radius: 6px;
|
|
147
|
+
padding: 16px;
|
|
148
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.stat-card h3 {
|
|
152
|
+
margin: 0 0 8px 0;
|
|
153
|
+
font-size: 14px;
|
|
154
|
+
color: #666;
|
|
155
|
+
text-transform: uppercase;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.stat-value {
|
|
159
|
+
margin: 0 0 10px 0;
|
|
160
|
+
font-size: 28px;
|
|
161
|
+
font-weight: bold;
|
|
162
|
+
color: #2c3e50;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.stat-link {
|
|
166
|
+
font-size: 13px;
|
|
167
|
+
color: #3498db;
|
|
168
|
+
text-decoration: none;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.stat-link:hover {
|
|
172
|
+
text-decoration: underline;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.stat-sub {
|
|
176
|
+
font-size: 13px;
|
|
177
|
+
color: #888;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.dashboard-sections {
|
|
181
|
+
display: grid;
|
|
182
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
183
|
+
gap: 16px;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.section-card {
|
|
187
|
+
background: #ffffff;
|
|
188
|
+
border: 1px solid #ddd;
|
|
189
|
+
border-radius: 6px;
|
|
190
|
+
padding: 16px;
|
|
191
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.section-header {
|
|
195
|
+
display: flex;
|
|
196
|
+
justify-content: space-between;
|
|
197
|
+
align-items: center;
|
|
198
|
+
margin-bottom: 12px;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.section-header h3 {
|
|
202
|
+
margin: 0;
|
|
203
|
+
font-size: 16px;
|
|
204
|
+
color: #2c3e50;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.action-btn {
|
|
208
|
+
font-size: 12px;
|
|
209
|
+
padding: 4px 8px;
|
|
210
|
+
background: #2c3e50;
|
|
211
|
+
color: #ffffff;
|
|
212
|
+
text-decoration: none;
|
|
213
|
+
border-radius: 4px;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.action-btn:hover {
|
|
217
|
+
background: #34495e;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.item-list {
|
|
221
|
+
list-style: none;
|
|
222
|
+
padding: 0;
|
|
223
|
+
margin: 0;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.list-row {
|
|
227
|
+
display: flex;
|
|
228
|
+
justify-content: space-between;
|
|
229
|
+
align-items: center;
|
|
230
|
+
padding: 8px 0;
|
|
231
|
+
border-bottom: 1px solid #eee;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.list-row:last-child {
|
|
235
|
+
border-bottom: none;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.badge {
|
|
239
|
+
background: #ecf0f1;
|
|
240
|
+
color: #2c3e50;
|
|
241
|
+
padding: 2px 6px;
|
|
242
|
+
border-radius: 3px;
|
|
243
|
+
font-size: 12px;
|
|
244
|
+
font-family: monospace;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.muted-text {
|
|
248
|
+
margin-left: 6px;
|
|
249
|
+
color: #7f8c8d;
|
|
250
|
+
font-size: 12px;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.salary-text {
|
|
254
|
+
font-weight: bold;
|
|
255
|
+
color: #27ae60;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.empty-text {
|
|
259
|
+
color: #7f8c8d;
|
|
260
|
+
font-size: 14px;
|
|
261
|
+
margin: 8px 0;
|
|
262
|
+
}
|
|
263
|
+
</style>
|
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
</script>
|
|
3
|
-
|
|
4
|
-
<template>
|
|
5
|
-
<div class="app-container">
|
|
6
|
-
<header class="navbar">
|
|
7
|
-
<h2>Company Management</h2>
|
|
8
|
-
<nav class="nav-links">
|
|
9
|
-
<router-link to="/">Departments</router-link>
|
|
10
|
-
<router-link to="/employees">Employees</router-link>
|
|
11
|
-
</nav>
|
|
12
|
-
</header>
|
|
13
|
-
<main class="content">
|
|
14
|
-
<router-view />
|
|
15
|
-
</main>
|
|
16
|
-
</div>
|
|
17
|
-
</template>
|
|
18
|
-
|
|
19
|
-
<style scoped>
|
|
20
|
-
.app-container {
|
|
21
|
-
max-width: 800px;
|
|
22
|
-
margin: 0 auto;
|
|
23
|
-
padding: 24px 16px;
|
|
24
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
25
|
-
color: #2d3748;
|
|
26
|
-
}
|
|
27
|
-
.navbar {
|
|
28
|
-
display: flex;
|
|
29
|
-
justify-content: space-between;
|
|
30
|
-
align-items: center;
|
|
31
|
-
border-bottom: 2px solid #e2e8f0;
|
|
32
|
-
padding-bottom: 16px;
|
|
33
|
-
margin-bottom: 24px;
|
|
34
|
-
}
|
|
35
|
-
.navbar h2 {
|
|
36
|
-
margin: 0;
|
|
37
|
-
font-size: 22px;
|
|
38
|
-
}
|
|
39
|
-
.nav-links {
|
|
40
|
-
display: flex;
|
|
41
|
-
gap: 12px;
|
|
42
|
-
}
|
|
43
|
-
.nav-links a {
|
|
44
|
-
text-decoration: none;
|
|
45
|
-
color: #4a5568;
|
|
46
|
-
font-weight: 500;
|
|
47
|
-
padding: 6px 14px;
|
|
48
|
-
border-radius: 4px;
|
|
49
|
-
border: 1px solid #cbd5e0;
|
|
50
|
-
}
|
|
51
|
-
.nav-links a.router-link-active {
|
|
52
|
-
background-color: #3182ce;
|
|
53
|
-
border-color: #3182ce;
|
|
54
|
-
color: #fff;
|
|
55
|
-
}
|
|
56
|
-
.content {
|
|
57
|
-
margin-top: 10px;
|
|
58
|
-
}
|
|
59
|
-
</style>
|
|
1
|
+
<script setup>
|
|
2
|
+
</script>
|
|
3
|
+
|
|
4
|
+
<template>
|
|
5
|
+
<div class="app-container">
|
|
6
|
+
<header class="navbar">
|
|
7
|
+
<h2>Company Management</h2>
|
|
8
|
+
<nav class="nav-links">
|
|
9
|
+
<router-link to="/">Departments</router-link>
|
|
10
|
+
<router-link to="/employees">Employees</router-link>
|
|
11
|
+
</nav>
|
|
12
|
+
</header>
|
|
13
|
+
<main class="content">
|
|
14
|
+
<router-view />
|
|
15
|
+
</main>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<style scoped>
|
|
20
|
+
.app-container {
|
|
21
|
+
max-width: 800px;
|
|
22
|
+
margin: 0 auto;
|
|
23
|
+
padding: 24px 16px;
|
|
24
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
25
|
+
color: #2d3748;
|
|
26
|
+
}
|
|
27
|
+
.navbar {
|
|
28
|
+
display: flex;
|
|
29
|
+
justify-content: space-between;
|
|
30
|
+
align-items: center;
|
|
31
|
+
border-bottom: 2px solid #e2e8f0;
|
|
32
|
+
padding-bottom: 16px;
|
|
33
|
+
margin-bottom: 24px;
|
|
34
|
+
}
|
|
35
|
+
.navbar h2 {
|
|
36
|
+
margin: 0;
|
|
37
|
+
font-size: 22px;
|
|
38
|
+
}
|
|
39
|
+
.nav-links {
|
|
40
|
+
display: flex;
|
|
41
|
+
gap: 12px;
|
|
42
|
+
}
|
|
43
|
+
.nav-links a {
|
|
44
|
+
text-decoration: none;
|
|
45
|
+
color: #4a5568;
|
|
46
|
+
font-weight: 500;
|
|
47
|
+
padding: 6px 14px;
|
|
48
|
+
border-radius: 4px;
|
|
49
|
+
border: 1px solid #cbd5e0;
|
|
50
|
+
}
|
|
51
|
+
.nav-links a.router-link-active {
|
|
52
|
+
background-color: #3182ce;
|
|
53
|
+
border-color: #3182ce;
|
|
54
|
+
color: #fff;
|
|
55
|
+
}
|
|
56
|
+
.content {
|
|
57
|
+
margin-top: 10px;
|
|
58
|
+
}
|
|
59
|
+
</style>
|