diff --git a/internal/biz/project.go b/internal/biz/project.go
index 54910147..dce55e7a 100644
--- a/internal/biz/project.go
+++ b/internal/biz/project.go
@@ -17,7 +17,7 @@ type Project struct {
}
type ProjectRepo interface {
- List(page, limit uint) ([]*types.ProjectDetail, int64, error)
+ List(typ types.ProjectType, page, limit uint) ([]*types.ProjectDetail, int64, error)
Get(id uint) (*types.ProjectDetail, error)
Create(req *request.ProjectCreate) (*types.ProjectDetail, error)
Update(req *request.ProjectUpdate) error
diff --git a/internal/data/project.go b/internal/data/project.go
index 47928336..8ed40055 100644
--- a/internal/data/project.go
+++ b/internal/data/project.go
@@ -21,27 +21,30 @@ import (
)
type projectRepo struct {
- systemdDir string
- t *gotext.Locale
- db *gorm.DB
+ t *gotext.Locale
+ db *gorm.DB
}
func NewProjectRepo(t *gotext.Locale, db *gorm.DB) biz.ProjectRepo {
return &projectRepo{
- systemdDir: "/etc/systemd/system",
- t: t,
- db: db,
+ t: t,
+ db: db,
}
}
-func (r *projectRepo) List(page, limit uint) ([]*types.ProjectDetail, int64, error) {
+func (r *projectRepo) List(typ types.ProjectType, page, limit uint) ([]*types.ProjectDetail, int64, error) {
var projects []*biz.Project
var total int64
- if err := r.db.Model(&biz.Project{}).Count(&total).Error; err != nil {
+ query := r.db.Model(&biz.Project{})
+ if typ != "" {
+ query = query.Where("type = ?", typ)
+ }
+
+ if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
- if err := r.db.Offset(int((page - 1) * limit)).Limit(int(limit)).Order("id desc").Find(&projects).Error; err != nil {
+ if err := query.Offset(int((page - 1) * limit)).Limit(int(limit)).Order("id desc").Find(&projects).Error; err != nil {
return nil, 0, err
}
@@ -148,7 +151,7 @@ func (r *projectRepo) Delete(id uint) error {
// unitFilePath 返回 systemd unit 文件路径
func (r *projectRepo) unitFilePath(name string) string {
- return filepath.Join(r.systemdDir, fmt.Sprintf("acepanel-project-%s.service", name))
+ return filepath.Join("/etc/systemd/system", fmt.Sprintf("%s.service", name))
}
// parseProjectDetail 从数据库记录和 systemd unit 文件解析项目详情
diff --git a/internal/service/project.go b/internal/service/project.go
index f069b743..fa9af6ef 100644
--- a/internal/service/project.go
+++ b/internal/service/project.go
@@ -7,6 +7,7 @@ import (
"github.com/acepanel/panel/internal/biz"
"github.com/acepanel/panel/internal/http/request"
+ "github.com/acepanel/panel/pkg/types"
)
type ProjectService struct {
@@ -26,7 +27,8 @@ func (s *ProjectService) List(w http.ResponseWriter, r *http.Request) {
return
}
- projects, total, err := s.projectRepo.List(req.Page, req.Limit)
+ typ := types.ProjectType(r.URL.Query().Get("type"))
+ projects, total, err := s.projectRepo.List(typ, req.Page, req.Limit)
if err != nil {
Error(w, http.StatusInternalServerError, "%v", err)
return
diff --git a/web/src/api/panel/project/index.ts b/web/src/api/panel/project/index.ts
new file mode 100644
index 00000000..31d8e338
--- /dev/null
+++ b/web/src/api/panel/project/index.ts
@@ -0,0 +1,15 @@
+import { http } from '@/utils'
+
+export default {
+ // 获取项目列表
+ list: (type: string, page: number, limit: number): any =>
+ http.Get('/project', { params: { type, page, limit } }),
+ // 获取项目详情
+ get: (id: number): any => http.Get(`/project/${id}`),
+ // 创建项目
+ create: (data: any): any => http.Post('/project', data),
+ // 更新项目
+ update: (id: number, data: any): any => http.Put(`/project/${id}`, data),
+ // 删除项目
+ delete: (id: number): any => http.Delete(`/project/${id}`)
+}
diff --git a/web/src/views/project/CreateModal.vue b/web/src/views/project/CreateModal.vue
new file mode 100644
index 00000000..a8bcdb55
--- /dev/null
+++ b/web/src/views/project/CreateModal.vue
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/web/src/views/project/IndexView.vue b/web/src/views/project/IndexView.vue
index 75a8e50f..07165b89 100644
--- a/web/src/views/project/IndexView.vue
+++ b/web/src/views/project/IndexView.vue
@@ -3,20 +3,28 @@ defineOptions({
name: 'project-index'
})
-const currentTab = ref('general')
+import CreateModal from '@/views/project/CreateModal.vue'
+import ListView from '@/views/project/ListView.vue'
+
+const currentTab = ref('all')
+
+const createModal = ref(false)
+
-
+
+
+
diff --git a/web/src/views/project/ListView.vue b/web/src/views/project/ListView.vue
new file mode 100644
index 00000000..738c5a93
--- /dev/null
+++ b/web/src/views/project/ListView.vue
@@ -0,0 +1,211 @@
+
+
+
+
+
+
+ {{ $gettext('Create Project') }}
+
+
+
+
+ {{ $gettext('Batch Delete') }}
+
+
+ {{ $gettext('Are you sure you want to delete the selected projects?') }}
+
+
+
+
+