vue3-admin-gpt 1.0.0

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.
Files changed (118) hide show
  1. package/.env.development +14 -0
  2. package/.env.production +14 -0
  3. package/LICENSE +21 -0
  4. package/README.en.md +106 -0
  5. package/README.md +104 -0
  6. package/build-zip.cjs +53 -0
  7. package/cli.js +110 -0
  8. package/jsconfig.json +9 -0
  9. package/package.json +92 -0
  10. package/public/index.html +20 -0
  11. package/public/robots.txt +2 -0
  12. package/rspack.config.js +282 -0
  13. package/rspack.js +162 -0
  14. package/src/App.vue +9 -0
  15. package/src/api/icon.js +9 -0
  16. package/src/api/router.js +9 -0
  17. package/src/api/table.js +25 -0
  18. package/src/api/tree.js +9 -0
  19. package/src/api/user.js +34 -0
  20. package/src/assets/error_images/401.png +0 -0
  21. package/src/assets/error_images/404.png +0 -0
  22. package/src/assets/error_images/cloud.png +0 -0
  23. package/src/assets/login_images/background.jpg +0 -0
  24. package/src/assets/logo.png +0 -0
  25. package/src/assets/qr_logo/lqr_logo.png +0 -0
  26. package/src/assets/vuejs-fill.svg +4 -0
  27. package/src/components/VabPageHeader/index.vue +133 -0
  28. package/src/config/index.js +7 -0
  29. package/src/config/net.config.js +20 -0
  30. package/src/config/permission.js +136 -0
  31. package/src/config/setting.config.js +62 -0
  32. package/src/config/settings.js +6 -0
  33. package/src/config/theme.config.js +14 -0
  34. package/src/layouts/EmptyLayout.vue +3 -0
  35. package/src/layouts/components/VabAppMain/index.vue +109 -0
  36. package/src/layouts/components/VabAvatar/index.vue +255 -0
  37. package/src/layouts/components/VabBreadcrumb/index.vue +61 -0
  38. package/src/layouts/components/VabFullScreen/index.vue +61 -0
  39. package/src/layouts/components/VabLogo/index.vue +94 -0
  40. package/src/layouts/components/VabNav/index.vue +176 -0
  41. package/src/layouts/components/VabSide/components/VabMenuItem.vue +80 -0
  42. package/src/layouts/components/VabSide/components/VabSideItem.vue +100 -0
  43. package/src/layouts/components/VabSide/components/VabSubmenu.vue +56 -0
  44. package/src/layouts/components/VabSide/index.vue +123 -0
  45. package/src/layouts/components/VabTabs/index.vue +500 -0
  46. package/src/layouts/components/VabTheme/index.vue +603 -0
  47. package/src/layouts/components/VabTop/index.vue +286 -0
  48. package/src/layouts/export.js +29 -0
  49. package/src/layouts/index.vue +339 -0
  50. package/src/main.js +40 -0
  51. package/src/plugins/echarts.js +4 -0
  52. package/src/plugins/index.js +44 -0
  53. package/src/plugins/support.js +16 -0
  54. package/src/router/index.js +400 -0
  55. package/src/store/index.js +26 -0
  56. package/src/store/modules/errorLog.js +27 -0
  57. package/src/store/modules/routes.js +60 -0
  58. package/src/store/modules/settings.js +73 -0
  59. package/src/store/modules/table.js +22 -0
  60. package/src/store/modules/tabsBar.js +109 -0
  61. package/src/store/modules/user.js +131 -0
  62. package/src/styles/element-variables.scss +13 -0
  63. package/src/styles/loading.scss +345 -0
  64. package/src/styles/nav-icons.scss +52 -0
  65. package/src/styles/normalize.scss +353 -0
  66. package/src/styles/spinner/dots.css +68 -0
  67. package/src/styles/spinner/gauge.css +104 -0
  68. package/src/styles/spinner/inner-circles.css +51 -0
  69. package/src/styles/spinner/plus.css +341 -0
  70. package/src/styles/themes/default.scss +1 -0
  71. package/src/styles/transition.scss +18 -0
  72. package/src/styles/vab.scss +476 -0
  73. package/src/styles/variables.scss +69 -0
  74. package/src/utils/accessToken.js +56 -0
  75. package/src/utils/eventBus.js +8 -0
  76. package/src/utils/handleRoutes.js +100 -0
  77. package/src/utils/index.js +231 -0
  78. package/src/utils/message.js +67 -0
  79. package/src/utils/pageTitle.js +11 -0
  80. package/src/utils/password.js +43 -0
  81. package/src/utils/permission.js +19 -0
  82. package/src/utils/request.js +187 -0
  83. package/src/utils/static.js +81 -0
  84. package/src/utils/vab.js +218 -0
  85. package/src/utils/validate.js +48 -0
  86. package/src/views/401.vue +302 -0
  87. package/src/views/404.vue +302 -0
  88. package/src/views/demo/index.vue +591 -0
  89. package/src/views/index/index.vue +1489 -0
  90. package/src/views/login/index.vue +456 -0
  91. package/src/views/register/index.vue +524 -0
  92. package/src/views/vab/calendar.vue +488 -0
  93. package/src/views/vab/campaign.vue +1006 -0
  94. package/src/views/vab/chart.vue +189 -0
  95. package/src/views/vab/customer.vue +666 -0
  96. package/src/views/vab/editor.vue +84 -0
  97. package/src/views/vab/form.vue +151 -0
  98. package/src/views/vab/help.vue +390 -0
  99. package/src/views/vab/icon.vue +113 -0
  100. package/src/views/vab/knowledge.vue +820 -0
  101. package/src/views/vab/nested/menu1/menu2/menu3.vue +29 -0
  102. package/src/views/vab/nested/menu1/menu2.vue +33 -0
  103. package/src/views/vab/nested/menu1.vue +33 -0
  104. package/src/views/vab/nested.vue +97 -0
  105. package/src/views/vab/notification.vue +416 -0
  106. package/src/views/vab/order.vue +507 -0
  107. package/src/views/vab/permissions.vue +214 -0
  108. package/src/views/vab/product.vue +724 -0
  109. package/src/views/vab/project.vue +559 -0
  110. package/src/views/vab/settings.vue +319 -0
  111. package/src/views/vab/statistics.vue +431 -0
  112. package/src/views/vab/table.vue +110 -0
  113. package/src/views/vab/task.vue +613 -0
  114. package/src/views/vab/team.vue +662 -0
  115. package/src/views/vab/tree.vue +44 -0
  116. package/src/views/vab/upload.vue +180 -0
  117. package/src/views/vab/vue3Demo/index.vue +103 -0
  118. package/src/views/vab/workflow.vue +863 -0
@@ -0,0 +1,559 @@
1
+ <template>
2
+ <div class="project-container">
3
+ <el-card shadow="never">
4
+ <template #header>
5
+ <div class="card-header">
6
+ <span>项目管理</span>
7
+ <div class="header-actions">
8
+ <el-input
9
+ v-model="searchText"
10
+ placeholder="搜索项目..."
11
+ clearable
12
+ style="width: 200px; margin-right: 10px"
13
+ >
14
+ <template #prefix>
15
+ <el-icon><Search /></el-icon>
16
+ </template>
17
+ </el-input>
18
+ <el-button type="primary" @click="showAddProjectDialog">添加项目</el-button>
19
+ </div>
20
+ </div>
21
+ </template>
22
+
23
+ <el-table
24
+ :data="filteredProjects"
25
+ style="width: 100%"
26
+ row-key="id"
27
+ v-loading="loading"
28
+ >
29
+ <el-table-column prop="name" label="项目名称" min-width="200">
30
+ <template #default="{ row }">
31
+ <div class="project-name">
32
+ <el-avatar :size="32" :style="{ backgroundColor: row.color }">
33
+ {{ row.name.charAt(0).toUpperCase() }}
34
+ </el-avatar>
35
+ <span style="margin-left: 10px">{{ row.name }}</span>
36
+ </div>
37
+ </template>
38
+ </el-table-column>
39
+ <el-table-column prop="description" label="项目描述" min-width="250">
40
+ <template #default="{ row }">
41
+ <div class="project-description">{{ row.description }}</div>
42
+ </template>
43
+ </el-table-column>
44
+ <el-table-column label="进度" width="150">
45
+ <template #default="{ row }">
46
+ <el-progress
47
+ :percentage="row.progress"
48
+ :status="getProgressStatus(row.progress)"
49
+ />
50
+ </template>
51
+ </el-table-column>
52
+ <el-table-column prop="manager" label="项目经理" width="120" />
53
+ <el-table-column label="状态" width="100">
54
+ <template #default="{ row }">
55
+ <el-tag :type="getStatusType(row.status)">
56
+ {{ getStatusText(row.status) }}
57
+ </el-tag>
58
+ </template>
59
+ </el-table-column>
60
+ <el-table-column prop="startDate" label="开始日期" width="120" />
61
+ <el-table-column prop="endDate" label="结束日期" width="120" />
62
+ <el-table-column label="操作" width="200">
63
+ <template #default="{ row }">
64
+ <el-button type="text" @click="viewProject(row)">查看</el-button>
65
+ <el-button type="text" @click="editProject(row)">编辑</el-button>
66
+ <el-button type="text" @click="deleteProject(row)">删除</el-button>
67
+ </template>
68
+ </el-table-column>
69
+ </el-table>
70
+
71
+ <div class="pagination-container">
72
+ <el-pagination
73
+ v-model:current-page="currentPage"
74
+ v-model:page-size="pageSize"
75
+ :page-sizes="[10, 20, 50, 100]"
76
+ :total="totalProjects"
77
+ layout="total, sizes, prev, pager, next, jumper"
78
+ @size-change="handleSizeChange"
79
+ @current-change="handleCurrentChange"
80
+ />
81
+ </div>
82
+ </el-card>
83
+
84
+ <!-- 添加/编辑项目对话框 -->
85
+ <el-dialog
86
+ v-model="projectDialogVisible"
87
+ :title="editingProject ? '编辑项目' : '添加项目'"
88
+ width="600px"
89
+ >
90
+ <el-form
91
+ ref="projectFormRef"
92
+ :model="projectForm"
93
+ :rules="projectRules"
94
+ label-width="100px"
95
+ >
96
+ <el-form-item label="项目名称" prop="name">
97
+ <el-input v-model="projectForm.name" />
98
+ </el-form-item>
99
+
100
+ <el-form-item label="项目描述" prop="description">
101
+ <el-input
102
+ v-model="projectForm.description"
103
+ type="textarea"
104
+ :rows="3"
105
+ />
106
+ </el-form-item>
107
+
108
+ <el-form-item label="项目经理" prop="manager">
109
+ <el-select v-model="projectForm.manager" placeholder="请选择项目经理" style="width: 100%">
110
+ <el-option
111
+ v-for="user in users"
112
+ :key="user.id"
113
+ :label="user.name"
114
+ :value="user.name"
115
+ />
116
+ </el-select>
117
+ </el-form-item>
118
+
119
+ <el-form-item label="开始日期" prop="startDate">
120
+ <el-date-picker
121
+ v-model="projectForm.startDate"
122
+ type="date"
123
+ placeholder="选择开始日期"
124
+ format="YYYY年MM月DD日"
125
+ value-format="YYYY-MM-DD"
126
+ style="width: 100%"
127
+ />
128
+ </el-form-item>
129
+
130
+ <el-form-item label="结束日期" prop="endDate">
131
+ <el-date-picker
132
+ v-model="projectForm.endDate"
133
+ type="date"
134
+ placeholder="选择结束日期"
135
+ format="YYYY年MM月DD日"
136
+ value-format="YYYY-MM-DD"
137
+ style="width: 100%"
138
+ />
139
+ </el-form-item>
140
+
141
+ <el-form-item label="状态" prop="status">
142
+ <el-select v-model="projectForm.status" placeholder="请选择状态" style="width: 100%">
143
+ <el-option label="未开始" value="not-started"></el-option>
144
+ <el-option label="进行中" value="in-progress"></el-option>
145
+ <el-option label="已完成" value="completed"></el-option>
146
+ <el-option label="已暂停" value="paused"></el-option>
147
+ </el-select>
148
+ </el-form-item>
149
+
150
+ <el-form-item label="项目颜色">
151
+ <el-color-picker v-model="projectForm.color" />
152
+ </el-form-item>
153
+ </el-form>
154
+
155
+ <template #footer>
156
+ <span class="dialog-footer">
157
+ <el-button @click="projectDialogVisible = false">取消</el-button>
158
+ <el-button
159
+ type="primary"
160
+ @click="saveProject"
161
+ >
162
+ 保存
163
+ </el-button>
164
+ </span>
165
+ </template>
166
+ </el-dialog>
167
+
168
+ <!-- 项目详情对话框 -->
169
+ <el-dialog
170
+ v-model="detailDialogVisible"
171
+ title="项目详情"
172
+ width="800px"
173
+ >
174
+ <el-row :gutter="20">
175
+ <el-col :span="16">
176
+ <el-descriptions :column="1" border>
177
+ <el-descriptions-item label="项目名称">{{ detailProject.name }}</el-descriptions-item>
178
+ <el-descriptions-item label="项目描述">{{ detailProject.description }}</el-descriptions-item>
179
+ <el-descriptions-item label="项目经理">{{ detailProject.manager }}</el-descriptions-item>
180
+ <el-descriptions-item label="状态">
181
+ <el-tag :type="getStatusType(detailProject.status)">
182
+ {{ getStatusText(detailProject.status) }}
183
+ </el-tag>
184
+ </el-descriptions-item>
185
+ <el-descriptions-item label="开始日期">{{ detailProject.startDate }}</el-descriptions-item>
186
+ <el-descriptions-item label="结束日期">{{ detailProject.endDate }}</el-descriptions-item>
187
+ <el-descriptions-item label="进度">
188
+ <el-progress
189
+ :percentage="detailProject.progress"
190
+ :status="getProgressStatus(detailProject.progress)"
191
+ />
192
+ </el-descriptions-item>
193
+ </el-descriptions>
194
+ </el-col>
195
+ <el-col :span="8">
196
+ <div class="project-avatar-detail" :style="{ backgroundColor: detailProject.color }">
197
+ {{ detailProject.name.charAt(0).toUpperCase() }}
198
+ </div>
199
+ </el-col>
200
+ </el-row>
201
+
202
+ <el-tabs v-model="activeTab" style="margin-top: 20px">
203
+ <el-tab-pane label="任务" name="tasks">
204
+ <el-table :data="projectTasks" style="width: 100%">
205
+ <el-table-column prop="title" label="任务标题" />
206
+ <el-table-column prop="assignee" label="负责人" width="120" />
207
+ <el-table-column label="状态" width="100">
208
+ <template #default="{ row }">
209
+ <el-tag :type="getTaskStatusType(row.status)">
210
+ {{ getTaskStatusText(row.status) }}
211
+ </el-tag>
212
+ </template>
213
+ </el-table-column>
214
+ <el-table-column prop="dueDate" label="截止日期" width="120" />
215
+ </el-table>
216
+ </el-tab-pane>
217
+ <el-tab-pane label="成员" name="members">
218
+ <el-table :data="projectMembers" style="width: 100%">
219
+ <el-table-column prop="name" label="姓名" />
220
+ <el-table-column prop="role" label="角色" />
221
+ <el-table-column prop="email" label="邮箱" />
222
+ </el-table>
223
+ </el-tab-pane>
224
+ </el-tabs>
225
+
226
+ <template #footer>
227
+ <span class="dialog-footer">
228
+ <el-button @click="detailDialogVisible = false">关闭</el-button>
229
+ </span>
230
+ </template>
231
+ </el-dialog>
232
+ </div>
233
+ </template>
234
+
235
+ <script>
236
+ import { Search } from "@element-plus/icons-vue";
237
+
238
+ export default {
239
+ name: "Project",
240
+ components: {
241
+ Search
242
+ },
243
+ data() {
244
+ return {
245
+ searchText: "",
246
+ currentPage: 1,
247
+ pageSize: 10,
248
+ totalProjects: 0,
249
+ loading: false,
250
+ projectDialogVisible: false,
251
+ detailDialogVisible: false,
252
+ activeTab: "tasks",
253
+ editingProject: null,
254
+ projects: [
255
+ {
256
+ id: 1,
257
+ name: "电商平台开发",
258
+ description: "开发全新的电商平台,包括前端和后端系统",
259
+ progress: 75,
260
+ manager: "张三",
261
+ status: "in-progress",
262
+ startDate: "2023-04-01",
263
+ endDate: "2023-09-30",
264
+ color: "#409EFF"
265
+ },
266
+ {
267
+ id: 2,
268
+ name: "移动端App",
269
+ description: "开发公司业务的移动端应用程序",
270
+ progress: 40,
271
+ manager: "李四",
272
+ status: "in-progress",
273
+ startDate: "2023-05-01",
274
+ endDate: "2023-11-30",
275
+ color: "#67C23A"
276
+ },
277
+ {
278
+ id: 3,
279
+ name: "数据分析系统",
280
+ description: "构建大数据分析平台,支持实时数据处理",
281
+ progress: 90,
282
+ manager: "王五",
283
+ status: "in-progress",
284
+ startDate: "2023-03-01",
285
+ endDate: "2023-08-31",
286
+ color: "#E6A23C"
287
+ },
288
+ {
289
+ id: 4,
290
+ name: "内部管理系统",
291
+ description: "升级公司内部管理系统,提高办公效率",
292
+ progress: 100,
293
+ manager: "赵六",
294
+ status: "completed",
295
+ startDate: "2023-01-01",
296
+ endDate: "2023-05-31",
297
+ color: "#F56C6C"
298
+ },
299
+ {
300
+ id: 5,
301
+ name: "客户关系管理",
302
+ description: "开发CRM系统,提升客户服务质量",
303
+ progress: 20,
304
+ manager: "钱七",
305
+ status: "not-started",
306
+ startDate: "2023-07-01",
307
+ endDate: "2023-12-31",
308
+ color: "#909399"
309
+ }
310
+ ],
311
+ users: [
312
+ { id: 1, name: "张三" },
313
+ { id: 2, name: "李四" },
314
+ { id: 3, name: "王五" },
315
+ { id: 4, name: "赵六" },
316
+ { id: 5, name: "钱七" }
317
+ ],
318
+ projectForm: {
319
+ name: "",
320
+ description: "",
321
+ manager: "",
322
+ startDate: "",
323
+ endDate: "",
324
+ status: "not-started",
325
+ color: "#409EFF"
326
+ },
327
+ detailProject: {},
328
+ projectRules: {
329
+ name: [
330
+ { required: true, message: "请输入项目名称", trigger: "blur" }
331
+ ],
332
+ manager: [
333
+ { required: true, message: "请选择项目经理", trigger: "change" }
334
+ ],
335
+ startDate: [
336
+ { required: true, message: "请选择开始日期", trigger: "change" }
337
+ ],
338
+ endDate: [
339
+ { required: true, message: "请选择结束日期", trigger: "change" }
340
+ ]
341
+ },
342
+ projectTasks: [
343
+ {
344
+ id: 1,
345
+ title: "需求分析",
346
+ assignee: "张三",
347
+ status: "completed",
348
+ dueDate: "2023-04-10"
349
+ },
350
+ {
351
+ id: 2,
352
+ title: "UI设计",
353
+ assignee: "李四",
354
+ status: "completed",
355
+ dueDate: "2023-04-20"
356
+ },
357
+ {
358
+ id: 3,
359
+ title: "前端开发",
360
+ assignee: "王五",
361
+ status: "in-progress",
362
+ dueDate: "2023-06-30"
363
+ },
364
+ {
365
+ id: 4,
366
+ title: "后端开发",
367
+ assignee: "赵六",
368
+ status: "in-progress",
369
+ dueDate: "2023-07-15"
370
+ }
371
+ ],
372
+ projectMembers: [
373
+ { id: 1, name: "张三", role: "项目经理", email: "zhangsan@example.com" },
374
+ { id: 2, name: "李四", role: "UI设计师", email: "lisi@example.com" },
375
+ { id: 3, name: "王五", role: "前端工程师", email: "wangwu@example.com" },
376
+ { id: 4, name: "赵六", role: "后端工程师", email: "zhaoliu@example.com" }
377
+ ]
378
+ };
379
+ },
380
+ computed: {
381
+ filteredProjects() {
382
+ let result = this.projects;
383
+
384
+ // 搜索过滤
385
+ if (this.searchText) {
386
+ result = result.filter(project =>
387
+ project.name.toLowerCase().includes(this.searchText.toLowerCase()) ||
388
+ project.description.toLowerCase().includes(this.searchText.toLowerCase())
389
+ );
390
+ }
391
+
392
+ // 分页处理
393
+ const start = (this.currentPage - 1) * this.pageSize;
394
+ const end = start + this.pageSize;
395
+ return result.slice(start, end);
396
+ }
397
+ },
398
+ methods: {
399
+ handleSizeChange(val) {
400
+ this.pageSize = val;
401
+ this.currentPage = 1;
402
+ },
403
+ handleCurrentChange(val) {
404
+ this.currentPage = val;
405
+ },
406
+ getStatusText(status) {
407
+ const statusMap = {
408
+ "not-started": "未开始",
409
+ "in-progress": "进行中",
410
+ "completed": "已完成",
411
+ "paused": "已暂停"
412
+ };
413
+ return statusMap[status] || status;
414
+ },
415
+ getStatusType(status) {
416
+ const typeMap = {
417
+ "not-started": "info",
418
+ "in-progress": "warning",
419
+ "completed": "success",
420
+ "paused": "danger"
421
+ };
422
+ return typeMap[status] || "info";
423
+ },
424
+ getProgressStatus(progress) {
425
+ if (progress === 100) {
426
+ return "success";
427
+ } else if (progress < 30) {
428
+ return "exception";
429
+ }
430
+ return "";
431
+ },
432
+ getTaskStatusText(status) {
433
+ const statusMap = {
434
+ "pending": "待办",
435
+ "in-progress": "进行中",
436
+ "completed": "已完成"
437
+ };
438
+ return statusMap[status] || status;
439
+ },
440
+ getTaskStatusType(status) {
441
+ const typeMap = {
442
+ "pending": "info",
443
+ "in-progress": "warning",
444
+ "completed": "success"
445
+ };
446
+ return typeMap[status] || "info";
447
+ },
448
+ showAddProjectDialog() {
449
+ this.editingProject = null;
450
+ this.projectForm = {
451
+ name: "",
452
+ description: "",
453
+ manager: "",
454
+ startDate: "",
455
+ endDate: "",
456
+ status: "not-started",
457
+ color: "#409EFF"
458
+ };
459
+ this.projectDialogVisible = true;
460
+ this.$nextTick(() => {
461
+ this.$refs.projectFormRef.resetFields();
462
+ });
463
+ },
464
+ editProject(project) {
465
+ this.editingProject = project;
466
+ this.projectForm = { ...project };
467
+ this.projectDialogVisible = true;
468
+ },
469
+ viewProject(project) {
470
+ this.detailProject = { ...project };
471
+ this.detailDialogVisible = true;
472
+ },
473
+ deleteProject(project) {
474
+ this.$confirm(`确定要删除项目"${project.name}"吗?`, "提示", {
475
+ confirmButtonText: "确定",
476
+ cancelButtonText: "取消",
477
+ type: "warning"
478
+ }).then(() => {
479
+ const index = this.projects.findIndex(p => p.id === project.id);
480
+ if (index !== -1) {
481
+ this.projects.splice(index, 1);
482
+ this.totalProjects = this.projects.length;
483
+ this.$message.success("项目删除成功");
484
+ }
485
+ }).catch(() => {
486
+ this.$message.info("已取消删除");
487
+ });
488
+ },
489
+ saveProject() {
490
+ this.$refs.projectFormRef.validate((valid) => {
491
+ if (valid) {
492
+ if (this.editingProject) {
493
+ // 编辑项目
494
+ const index = this.projects.findIndex(p => p.id === this.editingProject.id);
495
+ if (index !== -1) {
496
+ this.projects[index] = { ...this.editingProject, ...this.projectForm };
497
+ this.$message.success("项目更新成功");
498
+ }
499
+ } else {
500
+ // 添加项目
501
+ const newProject = {
502
+ id: Date.now(),
503
+ progress: 0,
504
+ ...this.projectForm
505
+ };
506
+ this.projects.push(newProject);
507
+ this.totalProjects = this.projects.length;
508
+ this.$message.success("项目添加成功");
509
+ }
510
+ this.projectDialogVisible = false;
511
+ }
512
+ });
513
+ }
514
+ }
515
+ };
516
+ </script>
517
+
518
+ <style lang="scss" scoped>
519
+ .project-container {
520
+ padding: 20px;
521
+
522
+ .card-header {
523
+ display: flex;
524
+ justify-content: space-between;
525
+ align-items: center;
526
+ font-weight: bold;
527
+ }
528
+
529
+ .project-name {
530
+ display: flex;
531
+ align-items: center;
532
+ }
533
+
534
+ .project-description {
535
+ display: -webkit-box;
536
+ -webkit-box-orient: vertical;
537
+ -webkit-line-clamp: 2;
538
+ overflow: hidden;
539
+ text-overflow: ellipsis;
540
+ }
541
+
542
+ .project-avatar-detail {
543
+ width: 100px;
544
+ height: 100px;
545
+ border-radius: 50%;
546
+ display: flex;
547
+ align-items: center;
548
+ justify-content: center;
549
+ font-size: 40px;
550
+ color: white;
551
+ margin: 0 auto;
552
+ }
553
+
554
+ .pagination-container {
555
+ margin-top: 20px;
556
+ text-align: right;
557
+ }
558
+ }
559
+ </style>