mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-20 20:39:55 +00:00
feat(任务调度): 重构任务调度界面并替换cron组件
refactor(IntervalTab): 优化时间间隔选择组件样式和功能 feat(任务管理): 使用vue3-cron-plus替换原有cron组件 fix(样式): 修复导航栏下拉菜单图标颜色问题 chore(依赖): 更新package.json依赖项和node版本要求 perf(构建): 优化vite配置和代码分割策略
This commit is contained in:
@@ -17,7 +17,6 @@ import { useAppStore, useSettingsStore } from "@/store";
|
||||
import { defaultSettings } from "@/settings";
|
||||
import { ThemeMode } from "@/enums/settings/theme.enum";
|
||||
import { ComponentSize } from "@/enums/settings/layout.enum";
|
||||
import { ElNotification } from 'element-plus'
|
||||
|
||||
const appStore = useAppStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
@@ -1,37 +1,74 @@
|
||||
<template>
|
||||
<el-form :model="crontabValueObj" ref="formRef" label-width="auto" label-suffix=":" :inline="true" class="flex">
|
||||
<el-form-item label="秒" prop="second" style="width: 20%">
|
||||
<el-select v-model:value="crontabValueObj.second" placeholder="秒">
|
||||
<el-option v-for="second in seconds" :key="second" :value="second">{{ second }}</el-option>
|
||||
<el-form :model="crontabValueObj" ref="formRef" label-width="auto" label-suffix=":" :inline="true" class="interval-tab-form">
|
||||
<el-form-item label="秒" prop="second" class="form-item">
|
||||
<el-select v-model="crontabValueObj.second" placeholder="秒" clearable>
|
||||
<el-option label="每秒" value="*">*</el-option>
|
||||
<el-option v-for="second in seconds" :key="second" :label="second" :value="second.toString()">{{ second }}</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="分" prop="min" style="width: 20%">
|
||||
<el-select v-model:value="crontabValueObj.min" placeholder="分">
|
||||
<el-option v-for="min in minutes" :key="min" :value="min">{{min}}</el-option>
|
||||
<el-form-item label="分" prop="min" class="form-item">
|
||||
<el-select v-model="crontabValueObj.min" placeholder="分" clearable>
|
||||
<el-option label="每分" value="*">*</el-option>
|
||||
<el-option v-for="min in minutes" :key="min" :label="min" :value="min.toString()">{{min}}</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="时" prop="hour" style="width: 20%">
|
||||
<el-select v-model:value="crontabValueObj.hour" placeholder="时">
|
||||
<el-option v-for="hour in hours" :key="hour" :value="hour">{{hour}}</el-option>
|
||||
<el-form-item label="时" prop="hour" class="form-item">
|
||||
<el-select v-model="crontabValueObj.hour" placeholder="时" clearable>
|
||||
<el-option label="每时" value="*">*</el-option>
|
||||
<el-option v-for="hour in hours" :key="hour" :label="hour" :value="hour.toString()">{{hour}}</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="天" prop="day" style="width: 20%">
|
||||
<el-select v-model:value="crontabValueObj.day" placeholder="天">
|
||||
<el-option v-for="day in days" :key="day" :value="day">{{day}}</el-option>
|
||||
<el-form-item label="天" prop="day" class="form-item">
|
||||
<el-select v-model="crontabValueObj.day" placeholder="天" clearable>
|
||||
<el-option label="每天" value="*">*</el-option>
|
||||
<el-option v-for="day in days" :key="day" :label="day" :value="day">{{day}}</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="周" prop="week" style="width: 20%">
|
||||
<el-select v-model:value="crontabValueObj.week" placeholder="周">
|
||||
<el-option v-for="week in weeks" :key="week" :value="week">{{week}}</el-option>
|
||||
<el-form-item label="周" prop="week" class="form-item">
|
||||
<el-select v-model="crontabValueObj.week" placeholder="周" clearable>
|
||||
<el-option label="每周" value="*">*</el-option>
|
||||
<el-option v-for="week in weekOptions" :key="week.value" :label="week.label" :value="week.value">{{week.label}}</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<div class="form-actions">
|
||||
<el-button @click="emit('cancel')">取消</el-button>
|
||||
<el-button type="primary" @click="handleConfirm">确认</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
<script lang="ts" setup>
|
||||
|
||||
const crontabValueObj = ref({
|
||||
// 定义接口,增强类型安全
|
||||
interface CrontabValue {
|
||||
second: string;
|
||||
min: string;
|
||||
hour: string;
|
||||
day: string;
|
||||
week: string;
|
||||
}
|
||||
|
||||
interface WeekOption {
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
// 定义props
|
||||
const props = defineProps<{
|
||||
cronValue?: string;
|
||||
}>();
|
||||
|
||||
// 定义emits
|
||||
const emit = defineEmits<{
|
||||
(e: 'confirm', value: string): void;
|
||||
(e: 'cancel'): void;
|
||||
}>();
|
||||
|
||||
const formRef = ref();
|
||||
|
||||
// 响应式数据
|
||||
const crontabValueObj = ref<CrontabValue>({
|
||||
second: "*",
|
||||
min: "*",
|
||||
hour: "*",
|
||||
@@ -39,20 +76,100 @@ const crontabValueObj = ref({
|
||||
week: "*",
|
||||
});
|
||||
|
||||
const seconds = ref(Array.from({ length: 60 }, (_, i) => i.toString()));
|
||||
const minutes = ref(Array.from({ length: 60 }, (_, i) => i.toString()));
|
||||
const hours = ref(Array.from({ length: 24 }, (_, i) => i.toString()));
|
||||
const days = ref(Array.from({ length: 31 }, (_, i) => (i + 1).toString()));
|
||||
const weeks = ref(["*", "1", "2", "3", "4", "5", "6", "7"]);
|
||||
// 常量定义,避免魔法数字
|
||||
const MAX_SECONDS = 60;
|
||||
const MAX_MINUTES = 60;
|
||||
const MAX_HOURS = 24;
|
||||
const MAX_DAYS = 31;
|
||||
|
||||
// 生成选择器选项
|
||||
const seconds = ref(Array.from({ length: MAX_SECONDS }, (_, i) => i));
|
||||
const minutes = ref(Array.from({ length: MAX_MINUTES }, (_, i) => i));
|
||||
const hours = ref(Array.from({ length: MAX_HOURS }, (_, i) => i));
|
||||
const days = ref(Array.from({ length: MAX_DAYS }, (_, i) => i + 1));
|
||||
const weekOptions: WeekOption[] = [
|
||||
{ value: "1", label: "周一" },
|
||||
{ value: "2", label: "周二" },
|
||||
{ value: "3", label: "周三" },
|
||||
{ value: "4", label: "周四" },
|
||||
{ value: "5", label: "周五" },
|
||||
{ value: "6", label: "周六" },
|
||||
{ value: "7", label: "周日" }
|
||||
];
|
||||
|
||||
// 初始化时设置cron值
|
||||
onMounted(() => {
|
||||
if (props.cronValue) {
|
||||
setCron(props.cronValue);
|
||||
}
|
||||
});
|
||||
|
||||
// 处理确认
|
||||
const handleConfirm = () => {
|
||||
// 简单验证
|
||||
const obj = crontabValueObj.value;
|
||||
return `${obj.second} ${obj.min} ${obj.hour} ${obj.day} ${obj.week}`;
|
||||
if (!obj.second || !obj.min || !obj.hour || !obj.day || !obj.week) {
|
||||
ElMessage.warning('请完善所有时间选项');
|
||||
return;
|
||||
}
|
||||
|
||||
const cronStr = `${obj.second} ${obj.min} ${obj.hour} ${obj.day} ${obj.week}`;
|
||||
emit('confirm', cronStr);
|
||||
};
|
||||
|
||||
// 暴露方法和属性给父组件
|
||||
defineExpose({ handleConfirm, crontabValueObj });
|
||||
// 设置cron表达式的值
|
||||
const setCron = (cronStr: string) => {
|
||||
if (!cronStr) return;
|
||||
const parts = cronStr.split(' ');
|
||||
if (parts.length !== 5) {
|
||||
ElMessage.warning('无效的cron表达式格式');
|
||||
return;
|
||||
}
|
||||
|
||||
const [second, min, hour, day, week] = parts;
|
||||
crontabValueObj.value = {
|
||||
second: second || '*',
|
||||
min: min || '*',
|
||||
hour: hour || '*',
|
||||
day: day || '*',
|
||||
week: week || '*'
|
||||
};
|
||||
};
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({ setCron });
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 样式可以根据需要调整</style>
|
||||
.interval-tab-form {
|
||||
width: 100%;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px 8px;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
width: calc(20% - 8px);
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 16px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
// 响应式调整
|
||||
@media (max-width: 768px) {
|
||||
.form-item {
|
||||
width: calc(33.33% - 8px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.form-item {
|
||||
width: calc(50% - 8px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -152,7 +152,7 @@ function handleDocumentClick() {
|
||||
* Gitee 项目地址
|
||||
*/
|
||||
function handleGiteeClick() {
|
||||
window.open('https://element-plus-admin-doc.cn/')
|
||||
window.open('https://gitee.com/tao__tao/fastapi_vue3_admin')
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,7 +283,7 @@ function logout() {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
// height: 100%;
|
||||
height: 100%;
|
||||
padding: 0 8px;
|
||||
|
||||
&__avatar {
|
||||
@@ -344,4 +344,14 @@ function logout() {
|
||||
}
|
||||
}
|
||||
|
||||
// 确保下拉菜单中的图标不受影响
|
||||
:deep(.el-dropdown-menu) {
|
||||
[class^="i-svg:"] {
|
||||
color: var(--el-text-color-regular) !important;
|
||||
|
||||
&:hover {
|
||||
color: var(--el-color-primary) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,7 +6,7 @@ import { setupStore } from "@/store";
|
||||
import { setupElIcons } from "./icons";
|
||||
import { setupPermission } from "./permission";
|
||||
import { InstallCodeMirror } from "codemirror-editor-vue3";
|
||||
// import ElementPlus from 'element-plus'
|
||||
import ElementPlus from 'element-plus'
|
||||
|
||||
export default {
|
||||
install(app: App<Element>) {
|
||||
@@ -22,7 +22,7 @@ export default {
|
||||
setupPermission();
|
||||
// 注册 CodeMirror
|
||||
app.use(InstallCodeMirror);
|
||||
// // 注册 ElementPlus
|
||||
// app.use(ElementPlus);
|
||||
// 注册 ElementPlus
|
||||
app.use(ElementPlus);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
"info": (
|
||||
"base": #a9aeb8,
|
||||
),
|
||||
"default": (
|
||||
"base": #f5f5f5,
|
||||
),
|
||||
),
|
||||
|
||||
$bg-color: (
|
||||
|
||||
Vendored
+1
-1
@@ -626,4 +626,4 @@ declare module 'vue' {
|
||||
readonly watchWithFilter: UnwrapRef<typeof import('@vueuse/core')['watchWithFilter']>
|
||||
readonly whenever: UnwrapRef<typeof import('@vueuse/core')['whenever']>
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+50
-51
@@ -8,18 +8,18 @@ export {}
|
||||
/* prettier-ignore */
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AppLink: typeof import('./src/components/AppLink/index.vue')['default']
|
||||
AppLogo: typeof import('./src/layouts/components/AppLogo/index.vue')['default']
|
||||
AppMain: typeof import('./src/layouts/components/AppMain/index.vue')['default']
|
||||
BasicMenu: typeof import('./src/layouts/components/Menu/BasicMenu.vue')['default']
|
||||
Breadcrumb: typeof import('./src/components/Breadcrumb/index.vue')['default']
|
||||
CommonWrapper: typeof import('./src/components/CommonWrapper/index.vue')['default']
|
||||
ConfigInfoDrawer: typeof import('./src/views/system/config/components/ConfigInfoDrawer.vue')['default']
|
||||
CopyButton: typeof import('./src/components/CopyButton/index.vue')['default']
|
||||
DarkModeSwitch: typeof import('./src/components/DarkModeSwitch/index.vue')['default']
|
||||
DataDrawer: typeof import('./src/views/system/dict/components/DataDrawer.vue')['default']
|
||||
DeptTree: typeof import('./src/views/system/user/components/DeptTree.vue')['default']
|
||||
ECharts: typeof import('./src/components/ECharts/index.vue')['default']
|
||||
AppLink: typeof import('./../components/AppLink/index.vue')['default']
|
||||
AppLogo: typeof import('./../layouts/components/AppLogo/index.vue')['default']
|
||||
AppMain: typeof import('./../layouts/components/AppMain/index.vue')['default']
|
||||
BasicMenu: typeof import('./../layouts/components/Menu/BasicMenu.vue')['default']
|
||||
Breadcrumb: typeof import('./../components/Breadcrumb/index.vue')['default']
|
||||
CommonWrapper: typeof import('./../components/CommonWrapper/index.vue')['default']
|
||||
ConfigInfoDrawer: typeof import('./../views/system/config/components/ConfigInfoDrawer.vue')['default']
|
||||
CopyButton: typeof import('./../components/CopyButton/index.vue')['default']
|
||||
DarkModeSwitch: typeof import('./../components/DarkModeSwitch/index.vue')['default']
|
||||
DataDrawer: typeof import('./../views/system/dict/components/DataDrawer.vue')['default']
|
||||
DeptTree: typeof import('./../views/system/user/components/DeptTree.vue')['default']
|
||||
ECharts: typeof import('./../components/ECharts/index.vue')['default']
|
||||
ElAlert: typeof import('element-plus/es')['ElAlert']
|
||||
ElAside: typeof import('element-plus/es')['ElAside']
|
||||
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
||||
@@ -30,7 +30,6 @@ declare module 'vue' {
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCard: typeof import('element-plus/es')['ElCard']
|
||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||
ElCol: typeof import('element-plus/es')['ElCol']
|
||||
ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
|
||||
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||
@@ -63,6 +62,7 @@ declare module 'vue' {
|
||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
|
||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||
ElResult: typeof import('element-plus/es')['ElResult']
|
||||
ElRow: typeof import('element-plus/es')['ElRow']
|
||||
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
@@ -85,46 +85,45 @@ declare module 'vue' {
|
||||
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
|
||||
ElUpload: typeof import('element-plus/es')['ElUpload']
|
||||
ElWatermark: typeof import('element-plus/es')['ElWatermark']
|
||||
Vue3CronPlusPicker: typeof import('vue3-cron-plus-picker')['default']
|
||||
FileUpload: typeof import('./src/components/Upload/FileUpload.vue')['default']
|
||||
Frame: typeof import('./src/components/Frame/index.vue')['default']
|
||||
Fullscreen: typeof import('./src/components/Fullscreen/index.vue')['default']
|
||||
GithubCorner: typeof import('./src/components/GithubCorner/index.vue')['default']
|
||||
Guide: typeof import('./src/components/Guide/index.vue')['default']
|
||||
Hamburger: typeof import('./src/components/Hamburger/index.vue')['default']
|
||||
IconSelect: typeof import('./src/components/IconSelect/index.vue')['default']
|
||||
InputTag: typeof import('./src/components/InputTag/index.vue')['default']
|
||||
IntervalTab: typeof import('./src/components/IntervalTab/index.vue')['default']
|
||||
LangSelect: typeof import('./src/components/LangSelect/index.vue')['default']
|
||||
LockDialog: typeof import('./src/layouts/components/NavBar/components/LockDialog.vue')['default']
|
||||
LockPage: typeof import('./src/layouts/components/NavBar/components/LockPage.vue')['default']
|
||||
Login: typeof import('./src/views/system/auth/components/Login.vue')['default']
|
||||
MenuItem: typeof import('./src/layouts/components/Menu/components/MenuItem.vue')['default']
|
||||
MenuItemContent: typeof import('./src/layouts/components/Menu/components/MenuItemContent.vue')['default']
|
||||
MenuSearch: typeof import('./src/components/MenuSearch/index.vue')['default']
|
||||
MixTopMenu: typeof import('./src/layouts/components/Menu/MixTopMenu.vue')['default']
|
||||
MultiImageUpload: typeof import('./src/components/Upload/MultiImageUpload.vue')['default']
|
||||
NavBar: typeof import('./src/layouts/components/NavBar/index.vue')['default']
|
||||
NavbarActions: typeof import('./src/layouts/components/NavBar/components/NavbarActions.vue')['default']
|
||||
Notification: typeof import('./src/components/Notification/index.vue')['default']
|
||||
OperationColumn: typeof import('./src/components/OperationColumn/index.vue')['default']
|
||||
PageContent: typeof import('./src/components/CURD/PageContent.vue')['default']
|
||||
PageModal: typeof import('./src/components/CURD/PageModal.vue')['default']
|
||||
PageSearch: typeof import('./src/components/CURD/PageSearch.vue')['default']
|
||||
Pagination: typeof import('./src/components/Pagination/index.vue')['default']
|
||||
PermissonDrawer: typeof import('./src/views/system/role/components/PermissonDrawer.vue')['default']
|
||||
Register: typeof import('./src/views/system/auth/components/Register.vue')['default']
|
||||
ResetPwd: typeof import('./src/views/system/auth/components/ResetPwd.vue')['default']
|
||||
FileUpload: typeof import('./../components/Upload/FileUpload.vue')['default']
|
||||
Frame: typeof import('./../components/Frame/index.vue')['default']
|
||||
Fullscreen: typeof import('./../components/Fullscreen/index.vue')['default']
|
||||
GithubCorner: typeof import('./../components/GithubCorner/index.vue')['default']
|
||||
Guide: typeof import('./../components/Guide/index.vue')['default']
|
||||
Hamburger: typeof import('./../components/Hamburger/index.vue')['default']
|
||||
IconSelect: typeof import('./../components/IconSelect/index.vue')['default']
|
||||
InputTag: typeof import('./../components/InputTag/index.vue')['default']
|
||||
IntervalTab: typeof import('./../components/IntervalTab/index.vue')['default']
|
||||
LangSelect: typeof import('./../components/LangSelect/index.vue')['default']
|
||||
LockDialog: typeof import('./../layouts/components/NavBar/components/LockDialog.vue')['default']
|
||||
LockPage: typeof import('./../layouts/components/NavBar/components/LockPage.vue')['default']
|
||||
Login: typeof import('./../views/system/auth/components/Login.vue')['default']
|
||||
MenuItem: typeof import('./../layouts/components/Menu/components/MenuItem.vue')['default']
|
||||
MenuItemContent: typeof import('./../layouts/components/Menu/components/MenuItemContent.vue')['default']
|
||||
MenuSearch: typeof import('./../components/MenuSearch/index.vue')['default']
|
||||
MixTopMenu: typeof import('./../layouts/components/Menu/MixTopMenu.vue')['default']
|
||||
MultiImageUpload: typeof import('./../components/Upload/MultiImageUpload.vue')['default']
|
||||
NavBar: typeof import('./../layouts/components/NavBar/index.vue')['default']
|
||||
NavbarActions: typeof import('./../layouts/components/NavBar/components/NavbarActions.vue')['default']
|
||||
Notification: typeof import('./../components/Notification/index.vue')['default']
|
||||
OperationColumn: typeof import('./../components/OperationColumn/index.vue')['default']
|
||||
PageContent: typeof import('./../components/CURD/PageContent.vue')['default']
|
||||
PageModal: typeof import('./../components/CURD/PageModal.vue')['default']
|
||||
PageSearch: typeof import('./../components/CURD/PageSearch.vue')['default']
|
||||
Pagination: typeof import('./../components/Pagination/index.vue')['default']
|
||||
PermissonDrawer: typeof import('./../views/system/role/components/PermissonDrawer.vue')['default']
|
||||
Register: typeof import('./../views/system/auth/components/Register.vue')['default']
|
||||
ResetPwd: typeof import('./../views/system/auth/components/ResetPwd.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
Settings: typeof import('./src/layouts/components/Settings/index.vue')['default']
|
||||
SingleImageUpload: typeof import('./src/components/Upload/SingleImageUpload.vue')['default']
|
||||
SizeSelect: typeof import('./src/components/SizeSelect/index.vue')['default']
|
||||
TableSelect: typeof import('./src/components/TableSelect/index.vue')['default']
|
||||
TagsView: typeof import('./src/layouts/components/TagsView/index.vue')['default']
|
||||
TextScroll: typeof import('./src/components/TextScroll/index.vue')['default']
|
||||
UserImport: typeof import('./src/views/system/user/components/UserImport.vue')['default']
|
||||
WangEditor: typeof import('./src/components/WangEditor/index.vue')['default']
|
||||
Settings: typeof import('./../layouts/components/Settings/index.vue')['default']
|
||||
SingleImageUpload: typeof import('./../components/Upload/SingleImageUpload.vue')['default']
|
||||
SizeSelect: typeof import('./../components/SizeSelect/index.vue')['default']
|
||||
TableSelect: typeof import('./../components/TableSelect/index.vue')['default']
|
||||
TagsView: typeof import('./../layouts/components/TagsView/index.vue')['default']
|
||||
TextScroll: typeof import('./../components/TextScroll/index.vue')['default']
|
||||
UserImport: typeof import('./../views/system/user/components/UserImport.vue')['default']
|
||||
WangEditor: typeof import('./../components/WangEditor/index.vue')['default']
|
||||
}
|
||||
export interface GlobalDirectives {
|
||||
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
|
||||
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
declare module "vue3-cron-plus-picker" {
|
||||
import { DefineComponent } from "vue";
|
||||
|
||||
export const Vue3CronPlusPicker: DefineComponent<{}, {}, any>;
|
||||
|
||||
export default Vue3CronPlusPicker;
|
||||
}
|
||||
|
||||
declare module "vue3-cron-plus-picker/style.css" {
|
||||
const content: any;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module "vue3-cron-plus-picker/vue3-cron-plus-picker.js" {
|
||||
import { DefineComponent } from "vue";
|
||||
|
||||
export const Vue3CronPlusPicker: DefineComponent<{}, {}, any>;
|
||||
|
||||
export default Vue3CronPlusPicker;
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
declare module "vue3-cron-plus" {
|
||||
import { DefineComponent } from "vue";
|
||||
|
||||
export const vue3CronPlus: DefineComponent<{}, {}, any>;
|
||||
|
||||
export default vue3CronPlus;
|
||||
}
|
||||
|
||||
declare module "vue3-cron-plus/dist/index.css" {
|
||||
const content: any;
|
||||
export default content;
|
||||
}
|
||||
@@ -364,37 +364,62 @@
|
||||
v-else-if="formData.trigger === 'interval'"
|
||||
label="间隔时间"
|
||||
prop="trigger_args"
|
||||
:rules="[{ required: true, message: '请输入间隔时间' }]"
|
||||
:rules="[{ required: true, message: '请输入间隔时间', trigger: 'change' }]"
|
||||
style="width: 40%"
|
||||
>
|
||||
<el-input
|
||||
v-model="formData.trigger_args"
|
||||
placeholder="请输入 秒-分-时-天-周 (* * * * 1)"
|
||||
clearable
|
||||
@click="openIntervalTabHandle('create')"
|
||||
/>
|
||||
<el-popover
|
||||
:visible="openIntervalTab"
|
||||
width="600px"
|
||||
trigger="click"
|
||||
:persistent="false"
|
||||
>
|
||||
<template #reference>
|
||||
<el-input
|
||||
v-model="formData.trigger_args"
|
||||
placeholder="请输入 秒-分-时-天-周"
|
||||
readonly
|
||||
@click="openIntervalTab = true"
|
||||
/>
|
||||
</template>
|
||||
<IntervalTab
|
||||
ref="intervalTabRef"
|
||||
@confirm="handleIntervalConfirm"
|
||||
@cancel="openIntervalTab = false"
|
||||
:cron-value="formData.trigger_args"
|
||||
/>
|
||||
</el-popover>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-else-if="formData.trigger === 'cron'"
|
||||
label="Cron表达式"
|
||||
prop="trigger_args"
|
||||
:rules="[{ required: true, message: '请输入Cron表达式' }]"
|
||||
:rules="[{ required: true, message: '请输入Cron表达式', trigger: 'change' }]"
|
||||
style="width: 40%"
|
||||
>
|
||||
<el-input
|
||||
v-model="formData.trigger_args"
|
||||
placeholder="请输入 Cron表达式(*/3 * * * *)"
|
||||
clearable
|
||||
readonly
|
||||
@click="handleShowCron"
|
||||
/>
|
||||
<el-popover
|
||||
:visible="openCron"
|
||||
width="600px"
|
||||
trigger="click"
|
||||
:persistent="false"
|
||||
placement="left"
|
||||
>
|
||||
<template #reference>
|
||||
<el-input
|
||||
v-model="formData.trigger_args"
|
||||
placeholder="请输入 * * * * * ? *"
|
||||
readonly
|
||||
@click="openCron = true"
|
||||
/>
|
||||
</template>
|
||||
<vue3CronPlus @change="handlechangeCron" @close="openCron = false" max-height="500px" i18n="cn"></vue3CronPlus>
|
||||
</el-popover>
|
||||
</el-form-item>
|
||||
<!-- 开始日期和结束日期 -->
|
||||
<el-form-item
|
||||
v-if="formData.trigger && formData.trigger != 'date'"
|
||||
label="开始日期"
|
||||
prop="start_date"
|
||||
:rules="[{ required: false, message: '请选择开始日期' }]"
|
||||
:rules="[{ required: false, message: '请选择开始日期', trigger: 'blur' }]"
|
||||
style="width: 40%"
|
||||
>
|
||||
<el-date-picker
|
||||
@@ -409,7 +434,7 @@
|
||||
v-if="formData.trigger && formData.trigger != 'date'"
|
||||
label="结束日期"
|
||||
prop="end_date"
|
||||
:rules="[{ required: false, message: '请选择结束日期' }]"
|
||||
:rules="[{ required: false, message: '请选择结束日期', trigger: 'blur' }]"
|
||||
style="width: 40%"
|
||||
>
|
||||
<el-date-picker
|
||||
@@ -451,23 +476,6 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 时间间隔组件 -->
|
||||
<el-dialog v-model="openIntervalTab" title="间隔时间设置" :width="700" align-center draggable>
|
||||
<IntervalTab ref="intervalTabRef" />
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="openIntervalTab = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleIntervalConfirm">
|
||||
确认
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- core组件 -->
|
||||
<el-dialog v-model="openCron">
|
||||
<Vue3CronPlusPicker @hide="closeDialog" @fill="fillValue" :expression="expression" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -478,11 +486,10 @@ defineOptions({
|
||||
});
|
||||
|
||||
import JobAPI, { JobTable, JobForm, JobPageQuery } from "@/api/monitor/job";
|
||||
|
||||
import IntervalTab from "@/components/IntervalTab/index.vue";
|
||||
import "vue3-cron-plus-picker/style.css";
|
||||
import { Vue3CronPlusPicker } from "vue3-cron-plus-picker";
|
||||
import { useDictStore } from "@/store/index";
|
||||
import { vue3CronPlus } from 'vue3-cron-plus'
|
||||
import 'vue3-cron-plus/dist/index.css' // 引入样式
|
||||
|
||||
const dictStore = useDictStore();
|
||||
|
||||
@@ -504,8 +511,7 @@ const isExpandable = ref(true);
|
||||
// const tableLoading = ref(false);
|
||||
// const openModal = ref(false);
|
||||
const openCron = ref(false);
|
||||
const cronMode = ref("create");
|
||||
const modalTitle = ref("");
|
||||
|
||||
// const modalSubmitLoading = ref(false);
|
||||
// const detailStateLoading = ref(false);
|
||||
// const dataSource = ref<tableJobType[]>([]);
|
||||
@@ -514,7 +520,6 @@ const modalTitle = ref("");
|
||||
// const detailState = ref<tableJobType>({})
|
||||
const openIntervalTab = ref(false);
|
||||
const intervalTabRef = ref();
|
||||
const expression = ref();
|
||||
|
||||
// 分页表单
|
||||
const pageTableData = ref<JobTable[]>([]);
|
||||
@@ -541,7 +546,7 @@ const formData = reactive<JobForm>({
|
||||
args: undefined,
|
||||
kwargs: undefined,
|
||||
coalesce: undefined,
|
||||
max_instances: undefined,
|
||||
max_instances: 1,
|
||||
jobstore: undefined,
|
||||
executor: undefined,
|
||||
trigger_args: undefined,
|
||||
@@ -659,7 +664,7 @@ async function handleSubmit() {
|
||||
handleCloseDialog();
|
||||
handleResetQuery();
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error.message);
|
||||
console.log(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
@@ -671,7 +676,7 @@ async function handleSubmit() {
|
||||
handleCloseDialog();
|
||||
handleResetQuery();
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error.message);
|
||||
console.log(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
@@ -739,7 +744,6 @@ async function handleExport() {
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
} catch (error: any) {
|
||||
ElMessage.error("文件处理失败", error.message);
|
||||
console.error("导出错误:", error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
@@ -749,27 +753,16 @@ async function handleExport() {
|
||||
});
|
||||
}
|
||||
|
||||
function openIntervalTabHandle(value: any) {
|
||||
openIntervalTab.value = true;
|
||||
modalTitle.value = value;
|
||||
}
|
||||
|
||||
function handleIntervalConfirm() {
|
||||
formData.trigger_args = intervalTabRef.value.handleConfirm();
|
||||
function handleIntervalConfirm(interval: string) {
|
||||
formData.trigger_args = interval;
|
||||
openIntervalTab.value = false;
|
||||
}
|
||||
|
||||
const handleShowCron = () => {
|
||||
openCron.value = true;
|
||||
expression.value = formData.trigger_args;
|
||||
};
|
||||
|
||||
const closeDialog = () => {
|
||||
openCron.value = false;
|
||||
};
|
||||
|
||||
const fillValue = (cronValue: string) => {
|
||||
formData.trigger_args = cronValue;
|
||||
const handlechangeCron = (cronStr: string) => {
|
||||
// formData.trigger_args = cronStr;
|
||||
if (typeof (cronStr) == "string") {
|
||||
formData.trigger_args = cronStr;
|
||||
}
|
||||
};
|
||||
|
||||
// 清空按钮操作
|
||||
|
||||
Reference in New Issue
Block a user