Compare commits

...
14 changed files with 98 additions and 50 deletions
+22 -11
View File
@@ -17,15 +17,20 @@ import (
func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time) error { func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time) error {
var apps []model.AppInstall var apps []model.AppInstall
if cronjob.AppID == "all" { if strings.Contains(cronjob.AppID, "all") {
apps, _ = appInstallRepo.ListBy() apps, _ = appInstallRepo.ListBy()
} else { } else {
itemID, _ := strconv.Atoi(cronjob.AppID) appIds := strings.Split(cronjob.AppID, ",")
app, err := appInstallRepo.GetFirst(commonRepo.WithByID(uint(itemID))) var idItems []uint
for i := 0; i < len(appIds); i++ {
itemID, _ := strconv.Atoi(appIds[i])
idItems = append(idItems, uint(itemID))
}
appItems, err := appInstallRepo.ListBy(commonRepo.WithIdsIn(idItems))
if err != nil { if err != nil {
return err return err
} }
apps = append(apps, app) apps = appItems
} }
accountMap, err := loadClientMap(cronjob.BackupAccounts) accountMap, err := loadClientMap(cronjob.BackupAccounts)
if err != nil { if err != nil {
@@ -232,7 +237,7 @@ type databaseHelper struct {
func loadDbsForJob(cronjob model.Cronjob) []databaseHelper { func loadDbsForJob(cronjob model.Cronjob) []databaseHelper {
var dbs []databaseHelper var dbs []databaseHelper
if cronjob.DBName == "all" { if strings.Contains(cronjob.DBName, "all") {
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" { if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
mysqlItems, _ := mysqlRepo.List() mysqlItems, _ := mysqlRepo.List()
for _, mysql := range mysqlItems { for _, mysql := range mysqlItems {
@@ -254,7 +259,10 @@ func loadDbsForJob(cronjob model.Cronjob) []databaseHelper {
} }
return dbs return dbs
} }
itemID, _ := strconv.Atoi(cronjob.DBName)
dbNames := strings.Split(cronjob.DBName, ",")
for _, name := range dbNames {
itemID, _ := strconv.Atoi(name)
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" { if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
mysqlItem, _ := mysqlRepo.Get(commonRepo.WithByID(uint(itemID))) mysqlItem, _ := mysqlRepo.Get(commonRepo.WithByID(uint(itemID)))
dbs = append(dbs, databaseHelper{ dbs = append(dbs, databaseHelper{
@@ -270,20 +278,23 @@ func loadDbsForJob(cronjob model.Cronjob) []databaseHelper {
Name: pgItem.Name, Name: pgItem.Name,
}) })
} }
}
return dbs return dbs
} }
func loadWebsForJob(cronjob model.Cronjob) []model.Website { func loadWebsForJob(cronjob model.Cronjob) []model.Website {
var weblist []model.Website var weblist []model.Website
if cronjob.Website == "all" { if strings.Contains(cronjob.Website, "all") {
weblist, _ = websiteRepo.List() weblist, _ = websiteRepo.List()
return weblist return weblist
} }
itemID, _ := strconv.Atoi(cronjob.Website) websites := strings.Split(cronjob.Website, ",")
webItem, _ := websiteRepo.GetFirst(commonRepo.WithByID(uint(itemID))) var idItems []uint
if webItem.ID != 0 { for i := 0; i < len(websites); i++ {
weblist = append(weblist, webItem) itemID, _ := strconv.Atoi(websites[i])
idItems = append(idItems, uint(itemID))
} }
weblist, _ = websiteRepo.List(commonRepo.WithIdsIn(idItems))
return weblist return weblist
} }
+3
View File
@@ -24,6 +24,9 @@ export namespace Cronjob {
backupAccounts: string; backupAccounts: string;
defaultDownload: string; defaultDownload: string;
backupAccountList: Array<string>; backupAccountList: Array<string>;
appIdList: Array<string>;
websiteList: Array<string>;
dbNameList: Array<string>;
retainCopies: number; retainCopies: number;
status: string; status: string;
secret: string; secret: string;
+1
View File
@@ -69,6 +69,7 @@ const message = {
createNewFolder: 'Create new folder', createNewFolder: 'Create new folder',
createNewFile: 'Create new file', createNewFile: 'Create new file',
helpDoc: 'Help Document', helpDoc: 'Help Document',
unbind: 'UnBind',
}, },
search: { search: {
timeStart: 'Time start', timeStart: 'Time start',
+1
View File
@@ -68,6 +68,7 @@ const message = {
createNewFolder: '新建資料夾', createNewFolder: '新建資料夾',
createNewFile: '新建檔案', createNewFile: '新建檔案',
helpDoc: '幫助文档', helpDoc: '幫助文档',
unbind: '解綁',
}, },
search: { search: {
timeStart: '開始時間', timeStart: '開始時間',
+1
View File
@@ -68,6 +68,7 @@ const message = {
createNewFolder: '新建文件夹', createNewFolder: '新建文件夹',
createNewFile: '新建文件', createNewFile: '新建文件',
helpDoc: '帮助文档', helpDoc: '帮助文档',
unbind: '解绑',
}, },
search: { search: {
timeStart: '开始时间', timeStart: '开始时间',
+37 -6
View File
@@ -186,9 +186,9 @@
<el-form-item <el-form-item
v-if="dialogData.rowData!.type === 'website' || dialogData.rowData!.type === 'cutWebsiteLog'" v-if="dialogData.rowData!.type === 'website' || dialogData.rowData!.type === 'cutWebsiteLog'"
:label="dialogData.rowData!.type === 'website' ? $t('cronjob.website'):$t('website.website')" :label="dialogData.rowData!.type === 'website' ? $t('cronjob.website'):$t('website.website')"
prop="website" prop="websiteList"
> >
<el-select class="selectClass" v-model="dialogData.rowData!.website"> <el-select class="selectClass" multiple v-model="dialogData.rowData!.websiteList">
<el-option <el-option
:disabled="websiteOptions.length === 0" :disabled="websiteOptions.length === 0"
:label="$t('commons.table.all')" :label="$t('commons.table.all')"
@@ -212,8 +212,8 @@
</el-form-item> </el-form-item>
<div v-if="dialogData.rowData!.type === 'app'"> <div v-if="dialogData.rowData!.type === 'app'">
<el-form-item :label="$t('cronjob.app')" prop="appID"> <el-form-item :label="$t('cronjob.app')" prop="appIdList">
<el-select class="selectClass" clearable v-model="dialogData.rowData!.appID"> <el-select class="selectClass" multiple clearable v-model="dialogData.rowData!.appIdList">
<el-option <el-option
:disabled="appOptions.length === 0" :disabled="appOptions.length === 0"
:label="$t('commons.table.all')" :label="$t('commons.table.all')"
@@ -239,8 +239,8 @@
<el-radio value="postgresql">PostgreSQL</el-radio> <el-radio value="postgresql">PostgreSQL</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item :label="$t('cronjob.database')" prop="dbName"> <el-form-item :label="$t('cronjob.database')" prop="dbNameList">
<el-select class="selectClass" clearable v-model="dialogData.rowData!.dbName"> <el-select class="selectClass" multiple clearable v-model="dialogData.rowData!.dbNameList">
<el-option <el-option
:disabled="dbInfo.dbs.length === 0" :disabled="dbInfo.dbs.length === 0"
:label="$t('commons.table.all')" :label="$t('commons.table.all')"
@@ -378,6 +378,7 @@ import { listContainer } from '@/api/modules/container';
import { Database } from '@/api/interface/database'; import { Database } from '@/api/interface/database';
import { ListAppInstalled } from '@/api/modules/app'; import { ListAppInstalled } from '@/api/modules/app';
import { loadDefaultSpec, specOptions, transObjToSpec, transSpecToObj, weekOptions } from './../helper'; import { loadDefaultSpec, specOptions, transObjToSpec, transSpecToObj, weekOptions } from './../helper';
const router = useRouter(); const router = useRouter();
interface DialogProps { interface DialogProps {
@@ -385,6 +386,7 @@ interface DialogProps {
rowData?: Cronjob.CronjobInfo; rowData?: Cronjob.CronjobInfo;
getTableList?: () => Promise<any>; getTableList?: () => Promise<any>;
} }
const title = ref<string>(''); const title = ref<string>('');
const drawerVisible = ref(false); const drawerVisible = ref(false);
const dialogData = ref<DialogProps>({ const dialogData = ref<DialogProps>({
@@ -408,6 +410,15 @@ const acceptParams = (params: DialogProps): void => {
if (dialogData.value.rowData.backupAccounts) { if (dialogData.value.rowData.backupAccounts) {
dialogData.value.rowData.backupAccountList = dialogData.value.rowData.backupAccounts.split(','); dialogData.value.rowData.backupAccountList = dialogData.value.rowData.backupAccounts.split(',');
} }
if (dialogData.value.rowData.appID) {
dialogData.value.rowData.appIdList = dialogData.value.rowData.appID.split(',');
}
if (dialogData.value.rowData.website) {
dialogData.value.rowData.websiteList = dialogData.value.rowData.website.split(',');
}
if (dialogData.value.rowData.dbName) {
dialogData.value.rowData.dbNameList = dialogData.value.rowData.dbName.split(',');
}
dialogData.value.rowData!.command = dialogData.value.rowData!.command || 'sh'; dialogData.value.rowData!.command = dialogData.value.rowData!.command || 'sh';
dialogData.value.rowData!.isCustom = dialogData.value.rowData!.isCustom =
dialogData.value.rowData!.command !== 'sh' && dialogData.value.rowData!.command !== 'sh' &&
@@ -718,6 +729,17 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
specs.push(itemSpec); specs.push(itemSpec);
} }
dialogData.value.rowData.backupAccounts = dialogData.value.rowData.backupAccountList.join(','); dialogData.value.rowData.backupAccounts = dialogData.value.rowData.backupAccountList.join(',');
if (dialogData.value.rowData.appIdList) {
dialogData.value.rowData.appID = dialogData.value.rowData.appIdList.join(',');
}
if (dialogData.value.rowData.websiteList) {
dialogData.value.rowData.website = dialogData.value.rowData.websiteList.join(',');
}
if (dialogData.value.rowData.dbNameList) {
dialogData.value.rowData.dbName = dialogData.value.rowData.dbNameList.join(',');
}
dialogData.value.rowData.spec = specs.join(','); dialogData.value.rowData.spec = specs.join(',');
if (!formEl) return; if (!formEl) return;
formEl.validate(async (valid) => { formEl.validate(async (valid) => {
@@ -750,40 +772,49 @@ defineExpose({
.specClass { .specClass {
width: 20% !important; width: 20% !important;
margin-left: 20px; margin-left: 20px;
.append { .append {
width: 20px; width: 20px;
} }
} }
@media only screen and (max-width: 1000px) { @media only screen and (max-width: 1000px) {
.specClass { .specClass {
width: 100% !important; width: 100% !important;
margin-top: 20px; margin-top: 20px;
margin-left: 0; margin-left: 0;
.append { .append {
width: 43px; width: 43px;
} }
} }
} }
.specTypeClass { .specTypeClass {
width: 22% !important; width: 22% !important;
} }
@media only screen and (max-width: 1000px) { @media only screen and (max-width: 1000px) {
.specTypeClass { .specTypeClass {
width: 100% !important; width: 100% !important;
} }
} }
.selectClass { .selectClass {
width: 100%; width: 100%;
} }
.tagClass { .tagClass {
float: right; float: right;
margin-right: 10px; margin-right: 10px;
font-size: 12px; font-size: 12px;
margin-top: 5px; margin-top: 5px;
} }
.logText { .logText {
line-height: 22px; line-height: 22px;
font-size: 12px; font-size: 12px;
.link { .link {
font-size: 12px; font-size: 12px;
margin-top: -3px; margin-top: -3px;
@@ -74,7 +74,7 @@ const submit = async () => {
.then(() => { .then(() => {
loading.value = false; loading.value = false;
emit('search'); emit('search');
MsgSuccess(i18n.global.t('commons.msg.deleteSuccess')); MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
dialogVisible.value = false; dialogVisible.value = false;
}) })
.catch(() => { .catch(() => {
@@ -163,7 +163,7 @@ const buttons = [
}, },
}, },
{ {
label: i18n.global.t('commons.button.delete'), label: i18n.global.t('commons.button.unbind'),
click: (row: Database.DatabaseInfo) => { click: (row: Database.DatabaseInfo) => {
onDelete(row); onDelete(row);
}, },
@@ -74,7 +74,7 @@ const submit = async () => {
.then(() => { .then(() => {
loading.value = false; loading.value = false;
emit('search'); emit('search');
MsgSuccess(i18n.global.t('commons.msg.deleteSuccess')); MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
dialogVisible.value = false; dialogVisible.value = false;
}) })
.catch(() => { .catch(() => {
@@ -163,7 +163,7 @@ const buttons = [
}, },
}, },
{ {
label: i18n.global.t('commons.button.delete'), label: i18n.global.t('commons.button.unbind'),
click: (row: Database.DatabaseInfo) => { click: (row: Database.DatabaseInfo) => {
onDelete(row); onDelete(row);
}, },
@@ -74,7 +74,7 @@ const submit = async () => {
.then(() => { .then(() => {
loading.value = false; loading.value = false;
emit('search'); emit('search');
MsgSuccess(i18n.global.t('commons.msg.deleteSuccess')); MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
dialogVisible.value = false; dialogVisible.value = false;
}) })
.catch(() => { .catch(() => {
@@ -163,7 +163,7 @@ const buttons = [
}, },
}, },
{ {
label: i18n.global.t('commons.button.delete'), label: i18n.global.t('commons.button.unbind'),
click: (row: Database.DatabaseInfo) => { click: (row: Database.DatabaseInfo) => {
onDelete(row); onDelete(row);
}, },
@@ -265,7 +265,7 @@
link link
small small
@click="getDirSize(row, $index)" @click="getDirSize(row, $index)"
:loading="btnLoading == $index" :loading="btnLoading.includes($index)"
> >
<span v-if="row.dirSize == undefined"> <span v-if="row.dirSize == undefined">
{{ $t('file.calculate') }} {{ $t('file.calculate') }}
@@ -387,7 +387,7 @@ const initData = () => ({
}); });
let req = reactive(initData()); let req = reactive(initData());
let loading = ref(false); let loading = ref(false);
let btnLoading = ref(-1); let btnLoading = ref([]);
const paths = ref<FilePaths[]>([]); const paths = ref<FilePaths[]>([]);
let pathWidth = ref(0); let pathWidth = ref(0);
const history: string[] = []; const history: string[] = [];
@@ -638,7 +638,7 @@ const getDirSize = async (row: any, index: number) => {
const req = { const req = {
path: row.path, path: row.path,
}; };
btnLoading.value = index; btnLoading.value.push(index);
await ComputeDirSize(req) await ComputeDirSize(req)
.then(async (res) => { .then(async (res) => {
let newData = [...data.value]; let newData = [...data.value];
@@ -646,7 +646,7 @@ const getDirSize = async (row: any, index: number) => {
data.value = newData; data.value = newData;
}) })
.finally(() => { .finally(() => {
btnLoading.value = -1; btnLoading.value = btnLoading.value.filter((item) => item !== index);
}); });
}; };
@@ -202,7 +202,7 @@ const verifySpec = (rule: any, value: any, callback: any) => {
!Number.isInteger(item.second) || !Number.isInteger(item.second) ||
!Number.isInteger(item.week) !Number.isInteger(item.week)
) { ) {
callback(new Error(i18n.global.t('cronjob.specErr'))); callback(new Error(i18n.global.t('toolbox.clam.specErr')));
return; return;
} }
switch (item.specType) { switch (item.specType) {
@@ -215,7 +215,7 @@ const verifySpec = (rule: any, value: any, callback: any) => {
item.minute < 0 || item.minute < 0 ||
item.minute > 59 item.minute > 59
) { ) {
callback(new Error(i18n.global.t('cronjob.specErr'))); callback(new Error(i18n.global.t('toolbox.clam.specErr')));
return; return;
} }
break; break;
@@ -228,7 +228,7 @@ const verifySpec = (rule: any, value: any, callback: any) => {
item.minute < 0 || item.minute < 0 ||
item.minute > 59 item.minute > 59
) { ) {
callback(new Error(i18n.global.t('cronjob.specErr'))); callback(new Error(i18n.global.t('toolbox.clam.specErr')));
return; return;
} }
break; break;
@@ -241,36 +241,36 @@ const verifySpec = (rule: any, value: any, callback: any) => {
item.minute < 0 || item.minute < 0 ||
item.minute > 59 item.minute > 59
) { ) {
callback(new Error(i18n.global.t('cronjob.specErr'))); callback(new Error(i18n.global.t('toolbox.clam.specErr')));
return; return;
} }
break; break;
case 'perDay': case 'perDay':
if (item.hour < 0 || item.hour > 23 || item.minute < 0 || item.minute > 59) { if (item.hour < 0 || item.hour > 23 || item.minute < 0 || item.minute > 59) {
callback(new Error(i18n.global.t('cronjob.specErr'))); callback(new Error(i18n.global.t('toolbox.clam.specErr')));
return; return;
} }
break; break;
case 'perNHour': case 'perNHour':
if (item.hour < 0 || item.hour > 8784 || item.minute < 0 || item.minute > 59) { if (item.hour < 0 || item.hour > 8784 || item.minute < 0 || item.minute > 59) {
callback(new Error(i18n.global.t('cronjob.specErr'))); callback(new Error(i18n.global.t('toolbox.clam.specErr')));
return; return;
} }
break; break;
case 'perHour': case 'perHour':
if (item.minute < 0 || item.minute > 59) { if (item.minute < 0 || item.minute > 59) {
callback(new Error(i18n.global.t('cronjob.specErr'))); callback(new Error(i18n.global.t('toolbox.clam.specErr')));
return; return;
} }
case 'perNMinute': case 'perNMinute':
if (item.minute < 0 || item.minute > 527040) { if (item.minute < 0 || item.minute > 527040) {
callback(new Error(i18n.global.t('cronjob.specErr'))); callback(new Error(i18n.global.t('toolbox.clam.specErr')));
return; return;
} }
break; break;
case 'perNSecond': case 'perNSecond':
if (item.second < 0 || item.second > 31622400) { if (item.second < 0 || item.second > 31622400) {
callback(new Error(i18n.global.t('cronjob.specErr'))); callback(new Error(i18n.global.t('toolbox.clam.specErr')));
return; return;
} }
break; break;