diff --git a/backend/app/api/v1/clam.go b/backend/app/api/v1/clam.go index 261a6308a..0e4e7cf47 100644 --- a/backend/app/api/v1/clam.go +++ b/backend/app/api/v1/clam.go @@ -51,16 +51,38 @@ func (b *BaseApi) UpdateClam(c *gin.Context) { helper.SuccessWithData(c, nil) } +// @Tags Clam +// @Summary Update clam status +// @Description 修改扫描规则状态 +// @Accept json +// @Param request body dto.ClamUpdateStatus true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /toolbox/clam/status/update [post] +// @x-panel-log {"bodyKeys":["id","status"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"clams","output_column":"name","output_value":"name"}],"formatZH":"修改扫描规则 [name] 状态为 [status]","formatEN":"change the status of clam [name] to [status]."} +func (b *BaseApi) UpdateClamStatus(c *gin.Context) { + var req dto.ClamUpdateStatus + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + + if err := clamService.UpdateStatus(req.ID, req.Status); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, nil) +} + // @Tags Clam // @Summary Page clam // @Description 获取扫描规则列表分页 // @Accept json -// @Param request body dto.SearchWithPage true "request" +// @Param request body dto.SearchClamWithPage true "request" // @Success 200 {object} dto.PageResult // @Security ApiKeyAuth // @Router /toolbox/clam/search [post] func (b *BaseApi) SearchClam(c *gin.Context) { - var req dto.SearchWithPage + var req dto.SearchClamWithPage if err := helper.CheckBindAndValidate(&req, c); err != nil { return } diff --git a/backend/app/dto/clam.go b/backend/app/dto/clam.go index 4c93b9d0c..964db15ee 100644 --- a/backend/app/dto/clam.go +++ b/backend/app/dto/clam.go @@ -4,6 +4,13 @@ import ( "time" ) +type SearchClamWithPage struct { + PageInfo + Info string `json:"info"` + OrderBy string `json:"orderBy" validate:"required,oneof=name status created_at"` + Order string `json:"order" validate:"required,oneof=null ascending descending"` +} + type ClamBaseInfo struct { Version string `json:"version"` IsActive bool `json:"isActive"` @@ -19,10 +26,12 @@ type ClamInfo struct { CreatedAt time.Time `json:"createdAt"` Name string `json:"name"` + Status string `json:"status"` Path string `json:"path"` InfectedStrategy string `json:"infectedStrategy"` InfectedDir string `json:"infectedDir"` LastHandleDate string `json:"lastHandleDate"` + Spec string `json:"spec"` Description string `json:"description"` } @@ -56,9 +65,11 @@ type ClamLog struct { type ClamCreate struct { Name string `json:"name"` + Status string `json:"status"` Path string `json:"path"` InfectedStrategy string `json:"infectedStrategy"` InfectedDir string `json:"infectedDir"` + Spec string `json:"spec"` Description string `json:"description"` } @@ -69,9 +80,15 @@ type ClamUpdate struct { Path string `json:"path"` InfectedStrategy string `json:"infectedStrategy"` InfectedDir string `json:"infectedDir"` + Spec string `json:"spec"` Description string `json:"description"` } +type ClamUpdateStatus struct { + ID uint `json:"id"` + Status string `json:"status"` +} + type ClamDelete struct { RemoveRecord bool `json:"removeRecord"` RemoveInfected bool `json:"removeInfected"` diff --git a/backend/app/model/clam.go b/backend/app/model/clam.go index 044c7bb31..ff1a73e67 100644 --- a/backend/app/model/clam.go +++ b/backend/app/model/clam.go @@ -4,8 +4,11 @@ type Clam struct { BaseModel Name string `gorm:"type:varchar(64);not null" json:"name"` + Status string `gorm:"type:varchar(64)" json:"status"` Path string `gorm:"type:varchar(64);not null" json:"path"` InfectedStrategy string `gorm:"type:varchar(64)" json:"infectedStrategy"` InfectedDir string `gorm:"type:varchar(64)" json:"infectedDir"` + Spec string `gorm:"type:varchar(64)" json:"spec"` + EntryID int `gorm:"type:varchar(64)" json:"entryID"` Description string `gorm:"type:varchar(64)" json:"description"` } diff --git a/backend/app/repo/clam.go b/backend/app/repo/clam.go index 215915556..4fd212c8c 100644 --- a/backend/app/repo/clam.go +++ b/backend/app/repo/clam.go @@ -13,6 +13,7 @@ type IClamRepo interface { Update(id uint, vars map[string]interface{}) error Delete(opts ...DBOption) error Get(opts ...DBOption) (model.Clam, error) + List(opts ...DBOption) ([]model.Clam, error) } func NewIClamRepo() IClamRepo { @@ -29,6 +30,16 @@ func (u *ClamRepo) Get(opts ...DBOption) (model.Clam, error) { return clam, err } +func (u *ClamRepo) List(opts ...DBOption) ([]model.Clam, error) { + var clam []model.Clam + db := global.DB + for _, opt := range opts { + db = opt(db) + } + err := db.Find(&clam).Error + return clam, err +} + func (u *ClamRepo) Page(page, size int, opts ...DBOption) (int64, []model.Clam, error) { var users []model.Clam db := global.DB.Model(&model.Clam{}) diff --git a/backend/app/service/clam.go b/backend/app/service/clam.go index 9989e7545..e54c4f3d5 100644 --- a/backend/app/service/clam.go +++ b/backend/app/service/clam.go @@ -12,13 +12,16 @@ import ( "time" "github.com/1Panel-dev/1Panel/backend/app/dto" + "github.com/1Panel-dev/1Panel/backend/app/model" "github.com/1Panel-dev/1Panel/backend/buserr" "github.com/1Panel-dev/1Panel/backend/constant" "github.com/1Panel-dev/1Panel/backend/global" "github.com/1Panel-dev/1Panel/backend/utils/cmd" "github.com/1Panel-dev/1Panel/backend/utils/common" "github.com/1Panel-dev/1Panel/backend/utils/systemctl" + "github.com/1Panel-dev/1Panel/backend/utils/xpack" "github.com/jinzhu/copier" + "github.com/robfig/cron/v3" "github.com/pkg/errors" ) @@ -37,9 +40,10 @@ type ClamService struct { type IClamService interface { LoadBaseInfo() (dto.ClamBaseInfo, error) Operate(operate string) error - SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) + SearchWithPage(search dto.SearchClamWithPage) (int64, interface{}, error) Create(req dto.ClamCreate) error Update(req dto.ClamUpdate) error + UpdateStatus(id uint, status string) error Delete(req dto.ClamDelete) error HandleOnce(req dto.OperateByID) error LoadFile(req dto.ClamFileReq) (string, error) @@ -75,8 +79,7 @@ func (c *ClamService) LoadBaseInfo() (dto.ClamBaseInfo, error) { baseInfo.FreshIsExist = true baseInfo.FreshIsActive, _ = systemctl.IsActive(freshClamService) } - stdout, err := cmd.Exec("which clamdscan") - if err != nil || (len(strings.ReplaceAll(stdout, "\n", "")) == 0 && strings.HasPrefix(stdout, "/")) { + if !cmd.Which("clamdscan") { baseInfo.IsActive = false } @@ -122,8 +125,8 @@ func (c *ClamService) Operate(operate string) error { } } -func (c *ClamService) SearchWithPage(req dto.SearchWithPage) (int64, interface{}, error) { - total, commands, err := clamRepo.Page(req.Page, req.PageSize, commonRepo.WithLikeName(req.Info)) +func (c *ClamService) SearchWithPage(req dto.SearchClamWithPage) (int64, interface{}, error) { + total, commands, err := clamRepo.Page(req.Page, req.PageSize, commonRepo.WithLikeName(req.Info), commonRepo.WithOrderRuleBy(req.OrderBy, req.Order)) if err != nil { return 0, nil, err } @@ -164,6 +167,14 @@ func (c *ClamService) Create(req dto.ClamCreate) error { if clam.InfectedStrategy == "none" || clam.InfectedStrategy == "remove" { clam.InfectedDir = "" } + if len(req.Spec) != 0 { + entryID, err := xpack.StartClam(clam, false) + if err != nil { + return err + } + clam.EntryID = entryID + clam.Status = constant.StatusEnable + } if err := clamRepo.Create(&clam); err != nil { return err } @@ -178,11 +189,36 @@ func (c *ClamService) Update(req dto.ClamUpdate) error { if req.InfectedStrategy == "none" || req.InfectedStrategy == "remove" { req.InfectedDir = "" } + var clamItem model.Clam + if err := copier.Copy(&clamItem, &req); err != nil { + return errors.WithMessage(constant.ErrStructTransform, err.Error()) + } + clamItem.EntryID = clam.EntryID upMap := map[string]interface{}{} + if len(clam.Spec) != 0 && clam.EntryID != 0 { + global.Cron.Remove(cron.EntryID(clamItem.EntryID)) + upMap["entry_id"] = 0 + } + if len(req.Spec) == 0 { + upMap["status"] = "" + upMap["entry_id"] = 0 + } + if len(req.Spec) != 0 && clam.Status != constant.StatusDisable { + newEntryID, err := xpack.StartClam(clamItem, true) + if err != nil { + return err + } + upMap["entry_id"] = newEntryID + } + if len(clam.Spec) == 0 && len(req.Spec) != 0 { + upMap["status"] = constant.StatusEnable + } + upMap["name"] = req.Name upMap["path"] = req.Path upMap["infected_dir"] = req.InfectedDir upMap["infected_strategy"] = req.InfectedStrategy + upMap["spec"] = req.Spec upMap["description"] = req.Description if err := clamRepo.Update(req.ID, upMap); err != nil { return err @@ -190,6 +226,28 @@ func (c *ClamService) Update(req dto.ClamUpdate) error { return nil } +func (c *ClamService) UpdateStatus(id uint, status string) error { + clam, _ := clamRepo.Get(commonRepo.WithByID(id)) + if clam.ID == 0 { + return constant.ErrRecordNotFound + } + var ( + entryID int + err error + ) + if status == constant.StatusEnable { + entryID, err = xpack.StartClam(clam, true) + if err != nil { + return err + } + } else { + global.Cron.Remove(cron.EntryID(clam.EntryID)) + global.LOG.Infof("stop cronjob entryID: %v", clam.EntryID) + } + + return clamRepo.Update(clam.ID, map[string]interface{}{"status": status, "entry_id": entryID}) +} + func (c *ClamService) Delete(req dto.ClamDelete) error { for _, id := range req.Ids { clam, _ := clamRepo.Get(commonRepo.WithByID(id)) diff --git a/backend/init/migration/migrate.go b/backend/init/migration/migrate.go index d374d451b..8711fb0fe 100644 --- a/backend/init/migration/migrate.go +++ b/backend/init/migration/migrate.go @@ -92,6 +92,7 @@ func Init() { migrations.AddForward, migrations.AddShellColumn, migrations.AddClam, + migrations.AddClamStatus, }) if err := m.Migrate(); err != nil { global.LOG.Error(err) diff --git a/backend/init/migration/migrations/v_1_10.go b/backend/init/migration/migrations/v_1_10.go index 61de816ef..c87545da6 100644 --- a/backend/init/migration/migrations/v_1_10.go +++ b/backend/init/migration/migrations/v_1_10.go @@ -278,3 +278,13 @@ var AddClam = &gormigrate.Migration{ return nil }, } + +var AddClamStatus = &gormigrate.Migration{ + ID: "20240716-add-clam-status", + Migrate: func(tx *gorm.DB) error { + if err := tx.AutoMigrate(&model.Clam{}); err != nil { + return err + } + return nil + }, +} diff --git a/backend/router/ro_toolbox.go b/backend/router/ro_toolbox.go index 52b79d9a4..6a331bbb2 100644 --- a/backend/router/ro_toolbox.go +++ b/backend/router/ro_toolbox.go @@ -56,6 +56,7 @@ func (s *ToolboxRouter) InitRouter(Router *gin.RouterGroup) { toolboxRouter.POST("/clam/base", baseApi.LoadClamBaseInfo) toolboxRouter.POST("/clam/operate", baseApi.OperateClam) toolboxRouter.POST("/clam/update", baseApi.UpdateClam) + toolboxRouter.POST("/clam/status/update", baseApi.UpdateClamStatus) toolboxRouter.POST("/clam/del", baseApi.DeleteClam) toolboxRouter.POST("/clam/handle", baseApi.HandleClamScan) } diff --git a/backend/utils/cmd/cmd.go b/backend/utils/cmd/cmd.go index ff81054d6..46b20fc1f 100644 --- a/backend/utils/cmd/cmd.go +++ b/backend/utils/cmd/cmd.go @@ -203,8 +203,11 @@ func SudoHandleCmd() string { } func Which(name string) bool { - _, err := exec.LookPath(name) - return err == nil + stdout, err := Execf("which %s", name) + if err != nil || (len(strings.ReplaceAll(stdout, "\n", "")) == 0 && strings.HasPrefix(stdout, "/")) { + return false + } + return true } func ExecShellWithTimeOut(cmdStr, workdir string, logger *log.Logger, timeout time.Duration) error { diff --git a/backend/utils/xpack/xpack.go b/backend/utils/xpack/xpack.go index 717efbb7e..14cf0b913 100644 --- a/backend/utils/xpack/xpack.go +++ b/backend/utils/xpack/xpack.go @@ -7,6 +7,10 @@ import ( "net" "net/http" "time" + + "github.com/1Panel-dev/1Panel/backend/app/model" + "github.com/1Panel-dev/1Panel/backend/buserr" + "github.com/1Panel-dev/1Panel/backend/constant" ) func RemoveTamper(website string) {} @@ -27,3 +31,7 @@ func LoadRequestTransport() *http.Transport { func LoadGpuInfo() []interface{} { return nil } + +func StartClam(startClam model.Clam, isUpdate bool) (int, error) { + return 0, buserr.New(constant.ErrXpackNotFound) +} diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index e423e7260..b004a49f5 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -11500,6 +11500,58 @@ const docTemplate = `{ } } }, + "/toolbox/clam/status/update": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "修改扫描规则状态", + "consumes": [ + "application/json" + ], + "tags": [ + "Clam" + ], + "summary": "Update clam status", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.ClamUpdateStatus" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFunctions": [ + { + "db": "clams", + "input_column": "id", + "input_value": "id", + "isList": false, + "output_column": "name", + "output_value": "name" + } + ], + "bodyKeys": [ + "id", + "status" + ], + "formatEN": "change the status of clam [name] to [status].", + "formatZH": "修改扫描规则 [name] 状态为 [status]", + "paramKeys": [] + } + } + }, "/toolbox/clam/update": { "post": { "security": [ @@ -15570,6 +15622,12 @@ const docTemplate = `{ }, "path": { "type": "string" + }, + "spec": { + "type": "string" + }, + "status": { + "type": "string" } } }, @@ -15665,6 +15723,20 @@ const docTemplate = `{ }, "path": { "type": "string" + }, + "spec": { + "type": "string" + } + } + }, + "dto.ClamUpdateStatus": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "status": { + "type": "string" } } }, @@ -18468,7 +18540,7 @@ const docTemplate = `{ "type": "string", "enum": [ "name", - "status", + "state", "created_at" ] }, @@ -22601,7 +22673,8 @@ const docTemplate = `{ "primary_domain", "type", "status", - "created_at" + "created_at", + "expire_date" ] }, "page": { @@ -22619,8 +22692,7 @@ const docTemplate = `{ "type": "object", "required": [ "id", - "primaryDomain", - "webSiteGroupID" + "primaryDomain" ], "properties": { "IPV6": { diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index 082ca50fe..de2b02277 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -11493,6 +11493,58 @@ } } }, + "/toolbox/clam/status/update": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "修改扫描规则状态", + "consumes": [ + "application/json" + ], + "tags": [ + "Clam" + ], + "summary": "Update clam status", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.ClamUpdateStatus" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFunctions": [ + { + "db": "clams", + "input_column": "id", + "input_value": "id", + "isList": false, + "output_column": "name", + "output_value": "name" + } + ], + "bodyKeys": [ + "id", + "status" + ], + "formatEN": "change the status of clam [name] to [status].", + "formatZH": "修改扫描规则 [name] 状态为 [status]", + "paramKeys": [] + } + } + }, "/toolbox/clam/update": { "post": { "security": [ @@ -15563,6 +15615,12 @@ }, "path": { "type": "string" + }, + "spec": { + "type": "string" + }, + "status": { + "type": "string" } } }, @@ -15658,6 +15716,20 @@ }, "path": { "type": "string" + }, + "spec": { + "type": "string" + } + } + }, + "dto.ClamUpdateStatus": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "status": { + "type": "string" } } }, @@ -18461,7 +18533,7 @@ "type": "string", "enum": [ "name", - "status", + "state", "created_at" ] }, @@ -22594,7 +22666,8 @@ "primary_domain", "type", "status", - "created_at" + "created_at", + "expire_date" ] }, "page": { @@ -22612,8 +22685,7 @@ "type": "object", "required": [ "id", - "primaryDomain", - "webSiteGroupID" + "primaryDomain" ], "properties": { "IPV6": { diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index 7b975a8ac..9dabd1965 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -243,6 +243,10 @@ definitions: type: string path: type: string + spec: + type: string + status: + type: string type: object dto.ClamDelete: properties: @@ -305,6 +309,15 @@ definitions: type: string path: type: string + spec: + type: string + type: object + dto.ClamUpdateStatus: + properties: + id: + type: integer + status: + type: string type: object dto.Clean: properties: @@ -2198,7 +2211,7 @@ definitions: orderBy: enum: - name - - status + - state - created_at type: string page: @@ -4974,6 +4987,7 @@ definitions: - type - status - created_at + - expire_date type: string page: type: integer @@ -5004,7 +5018,6 @@ definitions: required: - id - primaryDomain - - webSiteGroupID type: object request.WebsiteUpdateDir: properties: @@ -12767,6 +12780,40 @@ paths: summary: Page clam tags: - Clam + /toolbox/clam/status/update: + post: + consumes: + - application/json + description: 修改扫描规则状态 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/dto.ClamUpdateStatus' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Update clam status + tags: + - Clam + x-panel-log: + BeforeFunctions: + - db: clams + input_column: id + input_value: id + isList: false + output_column: name + output_value: name + bodyKeys: + - id + - status + formatEN: change the status of clam [name] to [status]. + formatZH: 修改扫描规则 [name] 状态为 [status] + paramKeys: [] /toolbox/clam/update: post: consumes: diff --git a/frontend/src/api/interface/toolbox.ts b/frontend/src/api/interface/toolbox.ts index 7930e066d..dd94a17ba 100644 --- a/frontend/src/api/interface/toolbox.ts +++ b/frontend/src/api/interface/toolbox.ts @@ -1,4 +1,5 @@ import { ReqPage } from '.'; +import { Cronjob } from './cronjob'; export namespace Toolbox { export interface DeviceBaseInfo { @@ -129,10 +130,14 @@ export namespace Toolbox { export interface ClamInfo { id: number; name: string; + status: string; path: string; infectedStrategy: string; infectedDir: string; lastHandleDate: string; + hasSpec: boolean; + spec: string; + specObj: Cronjob.SpecObj; description: string; } export interface ClamCreate { @@ -140,6 +145,8 @@ export namespace Toolbox { path: string; infectedStrategy: string; infectedDir: string; + spec: string; + specObj: Cronjob.SpecObj; description: string; } export interface ClamUpdate { @@ -148,6 +155,8 @@ export namespace Toolbox { path: string; infectedStrategy: string; infectedDir: string; + spec: string; + specObj: Cronjob.SpecObj; description: string; } export interface ClamSearchLog extends ReqPage { diff --git a/frontend/src/api/modules/toolbox.ts b/frontend/src/api/modules/toolbox.ts index fbcfa3a2e..0002b37a0 100644 --- a/frontend/src/api/modules/toolbox.ts +++ b/frontend/src/api/modules/toolbox.ts @@ -138,6 +138,9 @@ export const createClam = (params: Toolbox.ClamCreate) => { export const updateClam = (params: Toolbox.ClamUpdate) => { return http.post(`/toolbox/clam/update`, params); }; +export const updateClamStatus = (id: number, status: string) => { + return http.post(`/toolbox/clam/status/update`, { id: id, status: status }); +}; export const deleteClam = (params: { ids: number[]; removeRecord: boolean; removeInfected: boolean }) => { return http.post(`/toolbox/clam/del`, params); }; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 02dc6a62b..20e24af6d 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -1082,6 +1082,13 @@ const message = { }, clam: { clam: 'Virus Scan', + cron: 'Scheduled scan', + cronHelper: 'Professional version supports scheduled scan feature', + specErr: 'Execution schedule format error, please check and retry!', + disableMsg: + 'Stopping scheduled execution will prevent this scan task from running automatically. Do you want to continue?', + enableMsg: + 'Enabling scheduled execution will allow this scan task to run automatically at regular intervals. Do you want to continue?', showFresh: 'Show Virus Database Service', hideFresh: 'Hide Virus Database Service', clamHelper: @@ -1577,6 +1584,7 @@ const message = { recoverDetail: 'Recover detail', createSnapshot: 'Create Snapshot', importSnapshot: 'Sync Snapshot', + importHelper: 'Snapshot directory:', recover: 'Recover', lastRecoverAt: 'Last recovery time', lastRollbackAt: 'Last rollback time', diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index e73bc7d80..837246ff0 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -1023,6 +1023,11 @@ const message = { }, clam: { clam: '病毒掃描', + cron: '定時掃描', + cronHelper: '專業版支持定時掃描功能', + specErr: '執行周期格式錯誤,請檢查後重試!', + disableMsg: '停止定時執行會導致該掃描任務不再自動執行。是否繼續?', + enableMsg: '啟用定時執行會讓該掃描任務定期自動執行。是否繼續?', showFresh: '顯示病毒庫服務', hideFresh: '隱藏病毒庫服務', clamHelper: @@ -1395,6 +1400,7 @@ const message = { recoverDetail: '恢復詳情', createSnapshot: '創建快照', importSnapshot: '同步快照', + importHelper: '快照文件目錄:', recover: '恢復', lastRecoverAt: '上次恢復時間', lastRollbackAt: '上次回滾時間', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index da790c3f5..0b6f4548c 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -1024,6 +1024,11 @@ const message = { }, clam: { clam: '病毒扫描', + cron: '定时扫描', + cronHelper: '专业版支持定时扫描功能 ', + specErr: '执行周期格式错误,请检查后重试!', + disableMsg: '停止定时执行会导致该扫描任务不再自动执行。是否继续?', + enableMsg: '启用定时执行会让该扫描任务定期自动执行。是否继续?', showFresh: '显示病毒库服务', hideFresh: '隐藏病毒库服务', clamHelper: @@ -1397,6 +1402,7 @@ const message = { recoverDetail: '恢复详情', createSnapshot: '创建快照', importSnapshot: '同步快照', + importHelper: '快照文件目录:', recover: '恢复', lastRecoverAt: '上次恢复时间', lastRollbackAt: '上次回滚时间', diff --git a/frontend/src/views/setting/snapshot/import/index.vue b/frontend/src/views/setting/snapshot/import/index.vue index f50a694d2..788f34a35 100644 --- a/frontend/src/views/setting/snapshot/import/index.vue +++ b/frontend/src/views/setting/snapshot/import/index.vue @@ -16,6 +16,10 @@ :label="item.label" /> +