日志管理+任务管理
This commit is contained in:
11
.prettierrc.json
Normal file
11
.prettierrc.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 80,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"semi": true,
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"jsxBracketSameLine": false,
|
||||||
|
"arrowParens": "avoid"
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
"typecheck": "vue-tsc --noEmit --skipLibCheck"
|
"typecheck": "vue-tsc --noEmit --skipLibCheck"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ant-design/icons-vue": "^7.0.1",
|
||||||
"@better-scroll/core": "2.5.1",
|
"@better-scroll/core": "2.5.1",
|
||||||
"@iconify/vue": "4.1.2",
|
"@iconify/vue": "4.1.2",
|
||||||
"@sa/axios": "workspace:*",
|
"@sa/axios": "workspace:*",
|
||||||
|
|||||||
@@ -59,17 +59,16 @@ export type TableConfig<A extends ApiFn, T, C> = {
|
|||||||
immediate?: boolean;
|
immediate?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function useHookTable<A extends ApiFn, T, C>(config: TableConfig<A, T, C>) {
|
export default function useHookTable(config: any) {
|
||||||
const { loading, startLoading, endLoading } = useLoading();
|
const { loading, startLoading, endLoading } = useLoading();
|
||||||
const { bool: empty, setBool: setEmpty } = useBoolean();
|
const { bool: empty, setBool: setEmpty } = useBoolean();
|
||||||
|
|
||||||
const { apiFn, apiParams, transformer, immediate = true, getColumnChecks, getColumns } = config;
|
const { apiFn, apiParams, transformer, immediate = true, getColumnChecks, getColumns } = config;
|
||||||
|
|
||||||
const searchParams: NonNullable<Parameters<A>[0]> = reactive({ ...apiParams });
|
const searchParams: any = reactive({ ...apiParams });
|
||||||
|
const allColumns = ref(config.columns()) as Ref<any>;
|
||||||
|
|
||||||
const allColumns = ref(config.columns()) as Ref<C[]>;
|
const data: Ref<any> = ref([]);
|
||||||
|
|
||||||
const data: Ref<T[]> = ref([]);
|
|
||||||
|
|
||||||
const columnChecks: Ref<TableColumnCheck[]> = ref(getColumnChecks(config.columns()));
|
const columnChecks: Ref<TableColumnCheck[]> = ref(getColumnChecks(config.columns()));
|
||||||
|
|
||||||
@@ -82,7 +81,7 @@ export default function useHookTable<A extends ApiFn, T, C>(config: TableConfig<
|
|||||||
|
|
||||||
const defaultChecks = getColumnChecks(allColumns.value);
|
const defaultChecks = getColumnChecks(allColumns.value);
|
||||||
|
|
||||||
columnChecks.value = defaultChecks.map(col => ({
|
columnChecks.value = defaultChecks.map((col:any) => ({
|
||||||
...col,
|
...col,
|
||||||
checked: checkMap.get(col.key) ?? col.checked
|
checked: checkMap.get(col.key) ?? col.checked
|
||||||
}));
|
}));
|
||||||
@@ -92,10 +91,9 @@ export default function useHookTable<A extends ApiFn, T, C>(config: TableConfig<
|
|||||||
startLoading();
|
startLoading();
|
||||||
|
|
||||||
const formattedParams = formatSearchParams(searchParams);
|
const formattedParams = formatSearchParams(searchParams);
|
||||||
|
|
||||||
const response = await apiFn(formattedParams);
|
const response = await apiFn(formattedParams);
|
||||||
|
|
||||||
const transformed = transformer(response as Awaited<ReturnType<A>>);
|
const transformed = transformer(response as Awaited<any>);
|
||||||
|
|
||||||
data.value = transformed.rows;
|
data.value = transformed.rows;
|
||||||
|
|
||||||
@@ -123,7 +121,7 @@ export default function useHookTable<A extends ApiFn, T, C>(config: TableConfig<
|
|||||||
*
|
*
|
||||||
* @param params
|
* @param params
|
||||||
*/
|
*/
|
||||||
function updateSearchParams(params: Partial<Parameters<A>[0]>) {
|
function updateSearchParams(params: any) {
|
||||||
Object.assign(searchParams, params);
|
Object.assign(searchParams, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -8,6 +8,9 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@ant-design/icons-vue':
|
||||||
|
specifier: ^7.0.1
|
||||||
|
version: 7.0.1(vue@3.4.27(typescript@5.4.5))
|
||||||
'@better-scroll/core':
|
'@better-scroll/core':
|
||||||
specifier: 2.5.1
|
specifier: 2.5.1
|
||||||
version: 2.5.1
|
version: 2.5.1
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ interface Props {
|
|||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
tableType?: string;
|
tableType?: string;
|
||||||
showDelete?: boolean;
|
showDelete?: boolean;
|
||||||
|
showExport?: boolean;
|
||||||
|
notShowAdd?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProps<Props>();
|
defineProps<Props>();
|
||||||
@@ -18,6 +20,7 @@ interface Emits {
|
|||||||
(e: 'add'): void;
|
(e: 'add'): void;
|
||||||
(e: 'delete'): void;
|
(e: 'delete'): void;
|
||||||
(e: 'refresh'): void;
|
(e: 'refresh'): void;
|
||||||
|
(e: 'export'): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits<Emits>();
|
const emit = defineEmits<Emits>();
|
||||||
@@ -37,6 +40,10 @@ function batchDelete() {
|
|||||||
function refresh() {
|
function refresh() {
|
||||||
emit('refresh');
|
emit('refresh');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleExport() {
|
||||||
|
emit('export');
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -49,12 +56,8 @@ function refresh() {
|
|||||||
<span>{{ $t('common.add') }}</span>
|
<span>{{ $t('common.add') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</AButton>
|
</AButton>
|
||||||
<APopconfirm
|
<APopconfirm v-if="isShowBtn(`system:${tableType}:remove`) && showDelete" :title="$t('common.confirmDelete')"
|
||||||
v-if="isShowBtn(`system:${tableType}:remove`) && showDelete"
|
:disabled="disabledDelete" @confirm="batchDelete">
|
||||||
:title="$t('common.confirmDelete')"
|
|
||||||
:disabled="disabledDelete"
|
|
||||||
@confirm="batchDelete"
|
|
||||||
>
|
|
||||||
<AButton size="small" danger :disabled="disabledDelete">
|
<AButton size="small" danger :disabled="disabledDelete">
|
||||||
<div class="flex-y-center gap-8px">
|
<div class="flex-y-center gap-8px">
|
||||||
<icon-ic-round-delete class="text-icon" />
|
<icon-ic-round-delete class="text-icon" />
|
||||||
@@ -69,6 +72,12 @@ function refresh() {
|
|||||||
<span>{{ $t('common.refresh') }}</span>
|
<span>{{ $t('common.refresh') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</AButton>
|
</AButton>
|
||||||
|
<AButton size="small" type="primary" @click="handleExport" v-show="showExport">
|
||||||
|
<div class="flex-y-center gap-8px">
|
||||||
|
<icon-mdi-refresh class="text-icon" :class="{ 'animate-spin': loading }" />
|
||||||
|
<span>{{ $t('common.export') }}</span>
|
||||||
|
</div>
|
||||||
|
</AButton>
|
||||||
<TableColumnSetting v-model:columns="columns" />
|
<TableColumnSetting v-model:columns="columns" />
|
||||||
<slot name="suffix"></slot>
|
<slot name="suffix"></slot>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { transformRecordToOption } from '@/utils/common';
|
import { transformRecordToOption } from '@/utils/common';
|
||||||
|
|
||||||
export const enableStatusRecord: Record<Api.Common.EnableStatus, App.I18n.I18nKey> = {
|
export const enableStatusRecord: any= {
|
||||||
'0': 'page.manage.common.status.enable',
|
'0': 'page.manage.common.status.enable',
|
||||||
'1': 'page.manage.common.status.disable'
|
'1': 'page.manage.common.status.disable'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const enableStatusOptions = transformRecordToOption(enableStatusRecord);
|
export const enableStatusOptions = transformRecordToOption(enableStatusRecord);
|
||||||
|
|
||||||
export const menuIconTypeRecord: Record<Api.SystemManage.IconType, App.I18n.I18nKey> = {
|
export const menuIconTypeRecord: any = {
|
||||||
'1': 'page.manage.menu.iconType.iconify',
|
'1': 'page.manage.menu.iconType.iconify',
|
||||||
'2': 'page.manage.menu.iconType.local'
|
'2': 'page.manage.menu.iconType.local'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,10 +6,8 @@ import { useAppStore } from '@/store/modules/app';
|
|||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
|
|
||||||
type TableData<T = object> = AntDesign.TableData<T>;
|
type TableData<T = object> = AntDesign.TableData<T>;
|
||||||
type GetTableData<A extends AntDesign.TableApiFn> = AntDesign.GetTableData<A>;
|
|
||||||
type TableColumn<T> = AntDesign.TableColumn<T>;
|
|
||||||
|
|
||||||
export function useTable<A extends AntDesign.TableApiFn>(config: AntDesign.AntDesignTableConfig<A>) {
|
export function useTable(config: any) {
|
||||||
const scope = effectScope();
|
const scope = effectScope();
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
|
||||||
@@ -26,21 +24,21 @@ export function useTable<A extends AntDesign.TableApiFn>(config: AntDesign.AntDe
|
|||||||
searchParams,
|
searchParams,
|
||||||
updateSearchParams,
|
updateSearchParams,
|
||||||
resetSearchParams
|
resetSearchParams
|
||||||
} = useHookTable<A, GetTableData<A>, TableColumn<AntDesign.TableDataWithIndex<GetTableData<A>>>>({
|
} = useHookTable({
|
||||||
apiFn,
|
apiFn,
|
||||||
apiParams,
|
apiParams,
|
||||||
columns: config.columns,
|
columns: config.columns,
|
||||||
transformer: res => {
|
transformer: (res:any) => {
|
||||||
const { rows = [], total = 0 } = res.data || {};
|
const { rows = [], total = 0 } = res.data || {};
|
||||||
return {
|
return {
|
||||||
rows: rows.map((row, index) => ({ ...row, id: rowKey ? row[rowKey] : index })),
|
rows: rows.map((row:any, index:any) => ({ ...row, id: rowKey ? row[rowKey] : index })),
|
||||||
total
|
total
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getColumnChecks: cols => {
|
getColumnChecks: (cols:any) => {
|
||||||
const checks: AntDesign.TableColumnCheck[] = [];
|
const checks: AntDesign.TableColumnCheck[] = [];
|
||||||
|
|
||||||
cols.forEach(column => {
|
cols.forEach((column:any) => {
|
||||||
if (column.key) {
|
if (column.key) {
|
||||||
checks.push({
|
checks.push({
|
||||||
key: column.key as string,
|
key: column.key as string,
|
||||||
@@ -52,22 +50,22 @@ export function useTable<A extends AntDesign.TableApiFn>(config: AntDesign.AntDe
|
|||||||
|
|
||||||
return checks;
|
return checks;
|
||||||
},
|
},
|
||||||
getColumns: (cols, checks) => {
|
getColumns: (cols:any, checks:any) => {
|
||||||
const columnMap = new Map<string, TableColumn<GetTableData<A>>>();
|
const columnMap = new Map<string, any>();
|
||||||
|
|
||||||
cols.forEach(column => {
|
cols.forEach((column:any) => {
|
||||||
if (column.key) {
|
if (column.key) {
|
||||||
columnMap.set(column.key as string, column);
|
columnMap.set(column.key as string, column);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const filteredColumns = checks
|
const filteredColumns = checks
|
||||||
.filter(item => item.checked)
|
.filter((item:any) => item.checked)
|
||||||
.map(check => columnMap.get(check.key) as TableColumn<GetTableData<A>>);
|
.map((check:any) => columnMap.get(check.key) );
|
||||||
|
|
||||||
return filteredColumns;
|
return filteredColumns;
|
||||||
},
|
},
|
||||||
onFetched: async transformed => {
|
onFetched: async (transformed:any) => {
|
||||||
const { total } = transformed;
|
const { total } = transformed;
|
||||||
|
|
||||||
updatePagination({
|
updatePagination({
|
||||||
@@ -150,7 +148,7 @@ export function useTableOperate<T extends TableData<{ [key: string]: any }>>(
|
|||||||
) {
|
) {
|
||||||
const { bool: drawerVisible, setTrue: openDrawer, setFalse: closeDrawer } = useBoolean();
|
const { bool: drawerVisible, setTrue: openDrawer, setFalse: closeDrawer } = useBoolean();
|
||||||
|
|
||||||
const operateType = ref<AntDesign.TableOperateType>('add');
|
const operateType = ref<any>('add');
|
||||||
const { getData, idKey = 'id' } = options;
|
const { getData, idKey = 'id' } = options;
|
||||||
/** the editing row data */
|
/** the editing row data */
|
||||||
const editingData: Ref<T | null> = ref(null);
|
const editingData: Ref<T | null> = ref(null);
|
||||||
|
|||||||
@@ -49,7 +49,12 @@ const local: any = {
|
|||||||
yesOrNo: {
|
yesOrNo: {
|
||||||
yes: 'Yes',
|
yes: 'Yes',
|
||||||
no: 'No'
|
no: 'No'
|
||||||
}
|
},
|
||||||
|
ms: 'ms',
|
||||||
|
normal: 'Nomal',
|
||||||
|
abnormal: 'Abnormal',
|
||||||
|
export: 'Export',
|
||||||
|
loading: 'Loading',
|
||||||
},
|
},
|
||||||
request: {
|
request: {
|
||||||
logout: 'Logout user after request failed',
|
logout: 'Logout user after request failed',
|
||||||
@@ -483,6 +488,36 @@ const local: any = {
|
|||||||
},
|
},
|
||||||
addDict: 'Add Dictionary',
|
addDict: 'Add Dictionary',
|
||||||
editDict: 'Edit Dictionary'
|
editDict: 'Edit Dictionary'
|
||||||
|
},
|
||||||
|
log:{
|
||||||
|
logId:'Log ID',
|
||||||
|
module:'System Module',
|
||||||
|
operType:'Operation Type',
|
||||||
|
operName:'Operator',
|
||||||
|
operIp:'Operation Address',
|
||||||
|
operArea:'Operation Location',
|
||||||
|
operStatus:'Status',
|
||||||
|
operTime:'Operation Date',
|
||||||
|
useTime:'Time Consumption',
|
||||||
|
backUser:'Back User',
|
||||||
|
phoneUser:'Phone User',
|
||||||
|
other:'Other',
|
||||||
|
},
|
||||||
|
task:{
|
||||||
|
taskId:'ID',
|
||||||
|
taskName:'Name',
|
||||||
|
group:'Group',
|
||||||
|
invoke:'Invoke',
|
||||||
|
cron:'Cron',
|
||||||
|
status:'Status',
|
||||||
|
log:'Log',
|
||||||
|
createTime:'Create Time',
|
||||||
|
targetParams:'Arguments',
|
||||||
|
remark:'Remark',
|
||||||
|
viewJob:'View Job',
|
||||||
|
addJob:'Add Job',
|
||||||
|
editJob:'Edit Job',
|
||||||
|
getInfoError:'Get Info Error',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -49,7 +49,12 @@ const local:any = {
|
|||||||
yesOrNo: {
|
yesOrNo: {
|
||||||
yes: '是',
|
yes: '是',
|
||||||
no: '否'
|
no: '否'
|
||||||
}
|
},
|
||||||
|
ms: '毫秒',
|
||||||
|
normal: '正常',
|
||||||
|
abnormal: '异常',
|
||||||
|
export:'导出',
|
||||||
|
loading: '加载中...',
|
||||||
},
|
},
|
||||||
request: {
|
request: {
|
||||||
logout: '请求失败后登出用户',
|
logout: '请求失败后登出用户',
|
||||||
@@ -483,6 +488,37 @@ const local:any = {
|
|||||||
},
|
},
|
||||||
addDict: '新增字典',
|
addDict: '新增字典',
|
||||||
editDict: '编辑字典'
|
editDict: '编辑字典'
|
||||||
|
},
|
||||||
|
log:{
|
||||||
|
logId:'日志编号',
|
||||||
|
module:'系统模块',
|
||||||
|
operType:'操作类型',
|
||||||
|
operName:'操作人员',
|
||||||
|
operIp:'操作地址',
|
||||||
|
operArea:'操作地点',
|
||||||
|
operStatus:'操作状态',
|
||||||
|
operTime:'操作日期',
|
||||||
|
useTime:'消耗时间',
|
||||||
|
backUser:'后台用户',
|
||||||
|
phoneUser:'手机用户',
|
||||||
|
other:'其他',
|
||||||
|
},
|
||||||
|
task:{
|
||||||
|
taskId:'ID',
|
||||||
|
taskName:'任务名称',
|
||||||
|
group:'任务组名',
|
||||||
|
invoke:'调用目标',
|
||||||
|
cron:'cron表达式',
|
||||||
|
status:'状态',
|
||||||
|
log:'记录日志',
|
||||||
|
createTime:'创建时间',
|
||||||
|
targetParams:'传入参数',
|
||||||
|
remark:'备注',
|
||||||
|
viewJob:'查看任务',
|
||||||
|
addJob:'新增任务',
|
||||||
|
editJob:'编辑任务',
|
||||||
|
viewInfoErr:'查看异常信息',
|
||||||
|
getInfoError:'获取信息失败',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
18
src/service/api/job.ts
Normal file
18
src/service/api/job.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { request } from '../request';
|
||||||
|
|
||||||
|
|
||||||
|
export function doGetjobList(params?: Api.SystemManage.UserSearchParams) {
|
||||||
|
return request<Api.SystemManage.UserList>({
|
||||||
|
url: '/schedule/job/list',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function doGetjobInfo(paramsId: any) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/schedule/job/${paramsId}`,
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
||||||
15
src/service/api/log.ts
Normal file
15
src/service/api/log.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { request } from '../request';
|
||||||
|
|
||||||
|
|
||||||
|
export function doGetlogList(params?: Api.SystemManage.UserSearchParams) {
|
||||||
|
return request<Api.SystemManage.UserList>({
|
||||||
|
url: '/system/operlog/list',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doDeleteLog(userId: any) {
|
||||||
|
console.log(userId,+userId.join(','));
|
||||||
|
return request({ url: `/system/operlog/${userId.join(',')}`, method: 'delete' });
|
||||||
|
}
|
||||||
4
src/typings/auto-imports.d.ts
vendored
4
src/typings/auto-imports.d.ts
vendored
@@ -56,6 +56,7 @@ declare global {
|
|||||||
const doCheckUserRepeat: typeof import('../service/api/auth')['doCheckUserRepeat']
|
const doCheckUserRepeat: typeof import('../service/api/auth')['doCheckUserRepeat']
|
||||||
const doDeleteDept: typeof import('../service/api/dept')['doDeleteDept']
|
const doDeleteDept: typeof import('../service/api/dept')['doDeleteDept']
|
||||||
const doDeleteDict: typeof import('../service/api/dict')['doDeleteDict']
|
const doDeleteDict: typeof import('../service/api/dict')['doDeleteDict']
|
||||||
|
const doDeleteLog: typeof import('../service/api/log')['doDeleteLog']
|
||||||
const doDeleteLogout: typeof import('../service/api/auth')['doDeleteLogout']
|
const doDeleteLogout: typeof import('../service/api/auth')['doDeleteLogout']
|
||||||
const doDeleteMenu: typeof import('../service/api/menu')['doDeleteMenu']
|
const doDeleteMenu: typeof import('../service/api/menu')['doDeleteMenu']
|
||||||
const doDeletePost: typeof import('../service/api/post')['doDeletePost']
|
const doDeletePost: typeof import('../service/api/post')['doDeletePost']
|
||||||
@@ -81,6 +82,9 @@ declare global {
|
|||||||
const doGetUserList: typeof import('../service/api/user')['doGetUserList']
|
const doGetUserList: typeof import('../service/api/user')['doGetUserList']
|
||||||
const doGetUserPostsAndRoles: typeof import('../service/api/user')['doGetUserPostsAndRoles']
|
const doGetUserPostsAndRoles: typeof import('../service/api/user')['doGetUserPostsAndRoles']
|
||||||
const doGetUserRoutes: typeof import('../service/api/route')['doGetUserRoutes']
|
const doGetUserRoutes: typeof import('../service/api/route')['doGetUserRoutes']
|
||||||
|
const doGetjobInfo: typeof import('../service/api/job')['doGetjobInfo']
|
||||||
|
const doGetjobList: typeof import('../service/api/job')['doGetjobList']
|
||||||
|
const doGetlogList: typeof import('../service/api/log')['doGetlogList']
|
||||||
const doPostRole: typeof import('../service/api/role')['doPostRole']
|
const doPostRole: typeof import('../service/api/role')['doPostRole']
|
||||||
const doPostUser: typeof import('../service/api/user')['doPostUser']
|
const doPostUser: typeof import('../service/api/user')['doPostUser']
|
||||||
const doPutRole: typeof import('../service/api/role')['doPutRole']
|
const doPutRole: typeof import('../service/api/role')['doPutRole']
|
||||||
|
|||||||
2
src/typings/components.d.ts
vendored
2
src/typings/components.d.ts
vendored
@@ -38,6 +38,7 @@ declare module 'vue' {
|
|||||||
AppProvider: typeof import('./../components/common/app-provider.vue')['default']
|
AppProvider: typeof import('./../components/common/app-provider.vue')['default']
|
||||||
ARadio: typeof import('ant-design-vue/es')['Radio']
|
ARadio: typeof import('ant-design-vue/es')['Radio']
|
||||||
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
|
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
|
||||||
|
ARangePicker: typeof import('ant-design-vue/es')['RangePicker']
|
||||||
ARow: typeof import('ant-design-vue/es')['Row']
|
ARow: typeof import('ant-design-vue/es')['Row']
|
||||||
ASegmented: typeof import('ant-design-vue/es')['Segmented']
|
ASegmented: typeof import('ant-design-vue/es')['Segmented']
|
||||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||||
@@ -62,6 +63,7 @@ declare module 'vue' {
|
|||||||
FullScreen: typeof import('./../components/common/full-screen.vue')['default']
|
FullScreen: typeof import('./../components/common/full-screen.vue')['default']
|
||||||
IconAntDesignReloadOutlined: typeof import('~icons/ant-design/reload-outlined')['default']
|
IconAntDesignReloadOutlined: typeof import('~icons/ant-design/reload-outlined')['default']
|
||||||
IconAntDesignSettingOutlined: typeof import('~icons/ant-design/setting-outlined')['default']
|
IconAntDesignSettingOutlined: typeof import('~icons/ant-design/setting-outlined')['default']
|
||||||
|
IconFont: typeof import('./../components/IconFont/index.vue')['default']
|
||||||
IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
|
IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
|
||||||
IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
|
IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
|
||||||
IconIcRoundDelete: typeof import('~icons/ic/round-delete')['default']
|
IconIcRoundDelete: typeof import('~icons/ic/round-delete')['default']
|
||||||
|
|||||||
213
src/views/manage/log/index.vue
Normal file
213
src/views/manage/log/index.vue
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
<script setup lang="tsx">
|
||||||
|
import { Button, Popconfirm, Tag } from 'ant-design-vue';
|
||||||
|
import type { Key } from 'ant-design-vue/es/_util/type';
|
||||||
|
import { useTable, useTableOperate } from '@/hooks/common/table';
|
||||||
|
import { SimpleScrollbar } from '~/packages/materials/src';
|
||||||
|
import logSearch from './modules/log-search.vue';
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
|
||||||
|
const wrapperEl = shallowRef<HTMLElement | null>(null);
|
||||||
|
const { height: wrapperElHeight } = useElementSize(wrapperEl);
|
||||||
|
|
||||||
|
const scrollConfig = computed(() => {
|
||||||
|
return {
|
||||||
|
y: wrapperElHeight.value - 72,
|
||||||
|
x: 1000
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const { columns, columnChecks, data, loading, getData, mobilePagination, searchParams, resetSearchParams } = useTable({
|
||||||
|
apiFn: doGetlogList,
|
||||||
|
apiParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
status: undefined,
|
||||||
|
},
|
||||||
|
rowKey: 'operId',
|
||||||
|
columns: () => [
|
||||||
|
{
|
||||||
|
key: 'operId',
|
||||||
|
dataIndex: 'operId',
|
||||||
|
title: t('page.manage.log.logId'),
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'title',
|
||||||
|
dataIndex: 'title',
|
||||||
|
title: t('page.manage.log.module'),
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'operatorType',
|
||||||
|
dataIndex: 'operatorType',
|
||||||
|
title: t('page.manage.log.operType'),
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({ record }: any) => {
|
||||||
|
if (record.operatorType === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const tagMap: any = {
|
||||||
|
0: t('page.manage.log.other'),
|
||||||
|
1: t('page.manage.log.backUser'),
|
||||||
|
2: t('page.manage.log.phoneUser'),
|
||||||
|
};
|
||||||
|
const tagColor: any = {
|
||||||
|
'0': 'pink',
|
||||||
|
'1': 'warning',
|
||||||
|
'2': 'blue',
|
||||||
|
};
|
||||||
|
return <Tag color={tagColor[record.operatorType]}> {tagMap[record.operatorType]} </Tag>;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'operName',
|
||||||
|
dataIndex: 'operName',
|
||||||
|
title: t('page.manage.log.operName'),
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'operIp',
|
||||||
|
dataIndex: 'operIp',
|
||||||
|
title: t('page.manage.log.operIp'),
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'status',
|
||||||
|
dataIndex: 'status',
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({ record }: any) => {
|
||||||
|
if (record.status === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const tagMap: any = {
|
||||||
|
0: t('common.normal'),
|
||||||
|
1: t('common.abnormal'),
|
||||||
|
};
|
||||||
|
const tagColor: any = {
|
||||||
|
'0': 'success',
|
||||||
|
'1': 'error'
|
||||||
|
};
|
||||||
|
return <Tag color={tagColor[record.status]}> {tagMap[record.status]} </Tag>;
|
||||||
|
},
|
||||||
|
title: t('page.manage.log.operStatus'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'operTime',
|
||||||
|
dataIndex: 'operTime',
|
||||||
|
align: 'center',
|
||||||
|
title: t('page.manage.log.operTime'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'costTime',
|
||||||
|
dataIndex: 'costTime',
|
||||||
|
align: 'center',
|
||||||
|
title: t('page.manage.log.useTime'),
|
||||||
|
customRender: ({ record }: any) => {
|
||||||
|
if (!record.costTime) {
|
||||||
|
return '0ms';
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${record.costTime} ${t('common.ms')}`;
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// key: 'operate',
|
||||||
|
// title: t('common.operate'),
|
||||||
|
// align: 'center',
|
||||||
|
// width: 200,
|
||||||
|
// customRender: ({ record }: any) =>
|
||||||
|
// !record.admin && (
|
||||||
|
// <div class="flex justify-around gap-8px">
|
||||||
|
// {isShowBtn('system:user:remove') && (
|
||||||
|
// <Popconfirm onConfirm={() => handleDelete(record.operId)} title={t('common.confirmDelete')} >
|
||||||
|
// <Button danger size="small" >
|
||||||
|
// {t('common.delete')}
|
||||||
|
// </Button>
|
||||||
|
// </Popconfirm>
|
||||||
|
// )}
|
||||||
|
// </div>
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
handleAdd,
|
||||||
|
checkedRowKeys,
|
||||||
|
onBatchDeleted,
|
||||||
|
onDeleted
|
||||||
|
// closeDrawer
|
||||||
|
} = useTableOperate(data, { getData, idKey: 'operId' });
|
||||||
|
const deptTreeData = ref<Api.Common.CommonTree>([]);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getUserDeptTree();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function handleBatchDelete() {
|
||||||
|
const { error } = await doDeleteLog(checkedRowKeys.value);
|
||||||
|
if (!error) {
|
||||||
|
onBatchDeleted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleDelete(id: number) {
|
||||||
|
const { error } = await doDeleteLog([id]);
|
||||||
|
if (!error) {
|
||||||
|
onDeleted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function handleUserSelectChange(selectedRowKeys: Key[], selectedRows: any[]) {
|
||||||
|
checkedRowKeys.value = selectedRowKeys as number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function fnTest() {
|
||||||
|
searchParams.value = {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
resetSearchParams();
|
||||||
|
// 使用 nextTick 确保视图更新后检查
|
||||||
|
nextTick(() => {
|
||||||
|
console.log('视图更新后:', { ...searchParams.value });
|
||||||
|
console.log(searchParams.value);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getUserDeptTree() {
|
||||||
|
const { error, data: tree } = await doGetUserDeptTree();
|
||||||
|
if (!error) {
|
||||||
|
deptTreeData.value = tree;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<SimpleScrollbar>
|
||||||
|
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
||||||
|
<logSearch v-model:model="searchParams" :dept-tree-data="deptTreeData" @reset="fnTest" @search="getData" />
|
||||||
|
<ACard :title="t('page.manage.user.title')" :bordered="false" :body-style="{ flex: 1, overflow: 'hidden' }"
|
||||||
|
class="flex-col-stretch sm:flex-1-hidden card-wrapper">
|
||||||
|
<template #extra>
|
||||||
|
<TableHeaderOperation v-model:columns="columnChecks" :disabled-delete="checkedRowKeys.length === 0"
|
||||||
|
:loading="loading" :show-delete="true" @add="handleAdd" @delete="handleBatchDelete" @refresh="getData"
|
||||||
|
:not-show-add="true" />
|
||||||
|
</template>
|
||||||
|
<ATable ref="wrapperEl" row-key="operId" :columns="columns" :data-source="data" :loading="loading"
|
||||||
|
:row-selection="{
|
||||||
|
selectedRowKeys: checkedRowKeys,
|
||||||
|
onChange: handleUserSelectChange,
|
||||||
|
}" size="small" :pagination="mobilePagination" :scroll="scrollConfig" class="h-full" />
|
||||||
|
|
||||||
|
</ACard>
|
||||||
|
</div>
|
||||||
|
</SimpleScrollbar>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
127
src/views/manage/log/modules/log-search.vue
Normal file
127
src/views/manage/log/modules/log-search.vue
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { $t } from '@/locales';
|
||||||
|
import { enableStatusOptions } from '@/constants/business';
|
||||||
|
import { SyncOutlined, SearchOutlined } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'logSearch'
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
interface Emits {
|
||||||
|
(e: 'reset'): void;
|
||||||
|
(e: 'search'): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
deptTreeData: Api.Common.CommonTree;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<Emits>();
|
||||||
|
|
||||||
|
const model = defineModel<any>('model', { required: true });
|
||||||
|
|
||||||
|
/**记录开始结束时间 */
|
||||||
|
let queryRangePicker = ref<[string, string]>(['', '']);
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
// 重置表单
|
||||||
|
//formRef.value?.resetFields();
|
||||||
|
|
||||||
|
// 重置日期选择器
|
||||||
|
queryRangePicker.value = ['', ''];
|
||||||
|
|
||||||
|
// 确保 model 也被重置
|
||||||
|
model.value = {};
|
||||||
|
|
||||||
|
// 使用 nextTick 确保视图更新后检查
|
||||||
|
nextTick(() => {
|
||||||
|
console.log('视图更新后:', { ...model.value });
|
||||||
|
console.log(model);
|
||||||
|
});
|
||||||
|
emit('reset');
|
||||||
|
}
|
||||||
|
|
||||||
|
function search() {
|
||||||
|
if (!queryRangePicker.value) {
|
||||||
|
queryRangePicker.value = ['', ''];
|
||||||
|
}
|
||||||
|
model.value.beginTime = queryRangePicker.value[0];
|
||||||
|
model.value.endTime = queryRangePicker.value[1];
|
||||||
|
emit('search');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ACard :title="$t('common.search')" :bordered="false" class="card-wrapper">
|
||||||
|
<AForm :model="model" :label-width="80">
|
||||||
|
<ARow :gutter="[16, 16]" wrap>
|
||||||
|
<ACol :lg="6" :md="12" :xs="24">
|
||||||
|
<AFormItem :label="$t('page.manage.log.operIp')" name="operIp" class="m-0">
|
||||||
|
<AInput v-model:value="model.operIp" />
|
||||||
|
</AFormItem>
|
||||||
|
</ACol>
|
||||||
|
|
||||||
|
<ACol :lg="6" :md="12" :xs="24">
|
||||||
|
<AFormItem :label="$t('page.manage.log.module')" name="title" class="m-0">
|
||||||
|
<AInput v-model:value="model.title" />
|
||||||
|
</AFormItem>
|
||||||
|
</ACol>
|
||||||
|
|
||||||
|
|
||||||
|
<ACol :lg="6" :md="12" :xs="24">
|
||||||
|
<AFormItem :label="$t('page.manage.user.status')" name="status" class="m-0">
|
||||||
|
<ASelect v-model:value="model.status" :placeholder="$t('page.manage.user.form.status')" allow-clear>
|
||||||
|
<ASelectOption v-for="option in enableStatusOptions" :key="option.value" :value="option.value">
|
||||||
|
{{ $t(option.label) }}
|
||||||
|
</ASelectOption>
|
||||||
|
</ASelect>
|
||||||
|
</AFormItem>
|
||||||
|
</ACol>
|
||||||
|
|
||||||
|
<ACol :lg="6" :md="12" :xs="24">
|
||||||
|
<AFormItem :label="$t('page.manage.log.operName')" name="operName" class="m-0">
|
||||||
|
<AInput v-model:value="model.operName" />
|
||||||
|
</AFormItem>
|
||||||
|
</ACol>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a-col :lg="8" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="$t('page.manage.log.useTime')" name="queryRangePicker">
|
||||||
|
<a-range-picker v-model:value="queryRangePicker" allow-clear bordered show-time
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss" style="width: 100%"></a-range-picker>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
<ACol :lg="16" :md="12" :xs="24">
|
||||||
|
<AFormItem class="m-0">
|
||||||
|
<div class="w-full flex-y-center justify-end gap-8px">
|
||||||
|
|
||||||
|
<a-space :size="8">
|
||||||
|
<a-button @click="reset">
|
||||||
|
<template #icon>
|
||||||
|
<SyncOutlined />
|
||||||
|
</template>
|
||||||
|
{{ $t('common.reset') }}
|
||||||
|
</a-button>
|
||||||
|
<AButton type="primary" ghost @click="search">
|
||||||
|
<template #icon>
|
||||||
|
<SearchOutlined />
|
||||||
|
</template>
|
||||||
|
{{ $t('common.search') }}
|
||||||
|
</AButton>
|
||||||
|
</a-space>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</AFormItem>
|
||||||
|
</ACol>
|
||||||
|
|
||||||
|
</ARow>
|
||||||
|
</AForm>
|
||||||
|
</ACard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
@@ -6,6 +6,8 @@ import { $t } from '@/locales';
|
|||||||
import { enableStatusRecord } from '@/constants/business';
|
import { enableStatusRecord } from '@/constants/business';
|
||||||
import RoleOperateDrawer from './modules/role-operate-drawer.vue';
|
import RoleOperateDrawer from './modules/role-operate-drawer.vue';
|
||||||
import RoleSearch from './modules/role-search.vue';
|
import RoleSearch from './modules/role-search.vue';
|
||||||
|
import {useI18n} from "vue-i18n";
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
const wrapperEl = shallowRef<HTMLElement | null>(null);
|
const wrapperEl = shallowRef<HTMLElement | null>(null);
|
||||||
const { height: wrapperElHeight } = useElementSize(wrapperEl);
|
const { height: wrapperElHeight } = useElementSize(wrapperEl);
|
||||||
@@ -45,17 +47,17 @@ const { columns, columnChecks, data, loading, getData, mobilePagination, searchP
|
|||||||
dataIndex: 'status',
|
dataIndex: 'status',
|
||||||
title: $t('page.manage.role.roleStatus'),
|
title: $t('page.manage.role.roleStatus'),
|
||||||
align: 'center',
|
align: 'center',
|
||||||
customRender: ({ record }) => {
|
customRender: ({ record }:any) => {
|
||||||
if (record.status === null) {
|
if (record.status === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagMap: Record<Api.Common.EnableStatus, string> = {
|
const tagMap: any = {
|
||||||
'0': 'success',
|
'0': 'success',
|
||||||
'1': 'warning'
|
'1': 'warning'
|
||||||
};
|
};
|
||||||
|
|
||||||
const label = $t(enableStatusRecord[record.status]);
|
const label = t(enableStatusRecord[record.status]);
|
||||||
|
|
||||||
return <Tag color={tagMap[record.status]}>{label}</Tag>;
|
return <Tag color={tagMap[record.status]}>{label}</Tag>;
|
||||||
}
|
}
|
||||||
@@ -76,7 +78,7 @@ const { columns, columnChecks, data, loading, getData, mobilePagination, searchP
|
|||||||
title: $t('common.operate'),
|
title: $t('common.operate'),
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 200,
|
width: 200,
|
||||||
customRender: ({ record }) =>
|
customRender: ({ record }:any) =>
|
||||||
!record.admin && (
|
!record.admin && (
|
||||||
<div class="flex justify-around gap-8px">
|
<div class="flex justify-around gap-8px">
|
||||||
{isShowBtn('system:role:edit') && (
|
{isShowBtn('system:role:edit') && (
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ interface Props {
|
|||||||
/** the type of operation */
|
/** the type of operation */
|
||||||
operateType: AntDesign.TableOperateType;
|
operateType: AntDesign.TableOperateType;
|
||||||
/** the edit row data */
|
/** the edit row data */
|
||||||
rowData?: Api.SystemManage.Role | null;
|
rowData?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
const props = defineProps<Props>();
|
||||||
|
|||||||
630
src/views/manage/task/index.vue
Normal file
630
src/views/manage/task/index.vue
Normal file
@@ -0,0 +1,630 @@
|
|||||||
|
<script setup lang="tsx">
|
||||||
|
import { message, Tag } from 'ant-design-vue';
|
||||||
|
import type { Key } from 'ant-design-vue/es/_util/type';
|
||||||
|
import { useTable, useTableOperate } from '@/hooks/common/table';
|
||||||
|
import { SimpleScrollbar } from '~/packages/materials/src';
|
||||||
|
import taskOperateDrawer from './modules/task-operate-drawer.vue';
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { SyncOutlined, SearchOutlined, ProfileOutlined, FormOutlined, DeleteOutlined, RocketOutlined, ContainerOutlined } from '@ant-design/icons-vue';
|
||||||
|
import { enableStatusOptions } from '@/constants/business';
|
||||||
|
|
||||||
|
import { useAntdForm, useFormRules } from '@/hooks/common/form';
|
||||||
|
const { defaultRequiredRule, formRules } = useFormRules();
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
jonName: defaultRequiredRule,
|
||||||
|
invokeTarget: defaultRequiredRule,
|
||||||
|
cronExpression: defaultRequiredRule,
|
||||||
|
};
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
|
||||||
|
const wrapperEl = shallowRef<HTMLElement | null>(null);
|
||||||
|
const { height: wrapperElHeight } = useElementSize(wrapperEl);
|
||||||
|
|
||||||
|
|
||||||
|
/**对话框对象信息状态 */
|
||||||
|
let modalState: any = reactive({
|
||||||
|
openByView: false,
|
||||||
|
openByEdit: false,
|
||||||
|
title: '任务',
|
||||||
|
from: {
|
||||||
|
jobId: undefined,
|
||||||
|
jobName: '',
|
||||||
|
invokeTarget: '',
|
||||||
|
cronExpression: '',
|
||||||
|
misfirePolicy: '3',
|
||||||
|
concurrent: '0',
|
||||||
|
jobGroup: 'DEFAULT',
|
||||||
|
status: '0',
|
||||||
|
saveLog: '0',
|
||||||
|
targetParams: '',
|
||||||
|
remark: '',
|
||||||
|
},
|
||||||
|
confirmLoading: false,
|
||||||
|
openByCron: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const scrollConfig = computed(() => {
|
||||||
|
return {
|
||||||
|
y: wrapperElHeight.value - 72,
|
||||||
|
x: 1000
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const { columns, columnChecks, data, loading, getData, mobilePagination, searchParams, resetSearchParams } = useTable({
|
||||||
|
apiFn: doGetjobList,
|
||||||
|
apiParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
},
|
||||||
|
rowKey: 'jobId',
|
||||||
|
columns: () => [
|
||||||
|
{
|
||||||
|
key: 'jobId',
|
||||||
|
dataIndex: 'jobId',
|
||||||
|
title: t('page.manage.task.taskId'),
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'jobName',
|
||||||
|
dataIndex: 'jobName',
|
||||||
|
title: t('page.manage.task.taskName'),
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'jobGroup',
|
||||||
|
dataIndex: 'jobGroup',
|
||||||
|
title: t('page.manage.task.group'),
|
||||||
|
align: 'center',
|
||||||
|
// customRender: ({ record }: any) => {
|
||||||
|
// if (record.operatorType === null) {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// const tagMap: any = {
|
||||||
|
// 0: t('page.manage.log.other'),
|
||||||
|
// 1: t('page.manage.log.backUser'),
|
||||||
|
// 2: t('page.manage.log.phoneUser'),
|
||||||
|
// };
|
||||||
|
// const tagColor: any = {
|
||||||
|
// '0': 'pink',
|
||||||
|
// '1': 'warning',
|
||||||
|
// '2': 'blue',
|
||||||
|
// };
|
||||||
|
// return <Tag color={tagColor[record.operatorType]}>{tagMap[record.operatorType]}</Tag>;
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'invokeTarget',
|
||||||
|
dataIndex: 'invokeTarget',
|
||||||
|
title: t('page.manage.task.invoke'),
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'cronExpression',
|
||||||
|
dataIndex: 'cronExpression',
|
||||||
|
title: t('page.manage.task.cron'),
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'status',
|
||||||
|
dataIndex: 'status',
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({ record }: any) => {
|
||||||
|
if (record.status === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const tagMap: any = {
|
||||||
|
'0': t('common.normal'),
|
||||||
|
'1': t('common.abnormal'),
|
||||||
|
};
|
||||||
|
const tagColor: any = {
|
||||||
|
'0': 'success',
|
||||||
|
'1': 'error'
|
||||||
|
};
|
||||||
|
return <Tag color={tagColor[record.status]}>{tagMap[record.status]}</Tag>;
|
||||||
|
},
|
||||||
|
title: t('page.manage.log.operStatus'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'operate',
|
||||||
|
title: t('common.operate'),
|
||||||
|
align: 'center',
|
||||||
|
width: 200,
|
||||||
|
// customRender: ({ record }: any) =>
|
||||||
|
// !record.admin && (
|
||||||
|
// <div class="flex justify-around gap-8px">
|
||||||
|
// <Popconfirm onConfirm={() => handleDelete(record.operId)} title={t('common.confirmDelete')}>
|
||||||
|
// <a-button danger size="small">
|
||||||
|
// <template #icon>
|
||||||
|
// <SyncOutlined />
|
||||||
|
// </template>
|
||||||
|
// </a-button>
|
||||||
|
// </Popconfirm>
|
||||||
|
// </div>
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
drawerVisible,
|
||||||
|
operateType,
|
||||||
|
editingData,
|
||||||
|
handleAdd,
|
||||||
|
checkedRowKeys,
|
||||||
|
onBatchDeleted,
|
||||||
|
onDeleted
|
||||||
|
// closeDrawer
|
||||||
|
} = useTableOperate(data, { getData, idKey: 'jobId' });
|
||||||
|
const deptTreeData = ref<Api.Common.CommonTree>([]);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
});
|
||||||
|
|
||||||
|
async function handleBatchDelete() {
|
||||||
|
const { error } = await doDeleteLog(checkedRowKeys.value);
|
||||||
|
if (!error) {
|
||||||
|
onBatchDeleted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleDelete(id: number) {
|
||||||
|
const { error } = await doDeleteLog([id]);
|
||||||
|
if (!error) {
|
||||||
|
onDeleted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function handleUserSelectChange(selectedRowKeys: Key[], selectedRows: any[]) {
|
||||||
|
checkedRowKeys.value = selectedRowKeys as number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function fnTest() {
|
||||||
|
searchParams.value = {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
resetSearchParams();
|
||||||
|
// 使用 nextTick 确保视图更新后检查
|
||||||
|
nextTick(() => {
|
||||||
|
console.log(operateType)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fnRecordView(jobId: number) {
|
||||||
|
// const { error, data } = await doGetjobInfo(jobId);
|
||||||
|
// // if (!error) {
|
||||||
|
// // onDeleted();
|
||||||
|
// // }
|
||||||
|
// console.log(data);
|
||||||
|
operateType.value = 'view';
|
||||||
|
|
||||||
|
if (modalState.confirmLoading) return;
|
||||||
|
const hide = message.loading('Waiting...', 0);
|
||||||
|
modalState.confirmLoading = true;
|
||||||
|
doGetjobInfo(jobId).then(res => {
|
||||||
|
modalState.confirmLoading = false;
|
||||||
|
hide();
|
||||||
|
console.log(res);
|
||||||
|
if (!res.error) {
|
||||||
|
modalState.from = Object.assign(modalState.from, res.data);
|
||||||
|
modalState.openByView = true;
|
||||||
|
modalState.title = t('page.manage.task.viewJob');
|
||||||
|
console.log(modalState.openByView);
|
||||||
|
}
|
||||||
|
// if (res.code === RESULT_CODE_SUCCESS && res.data) {
|
||||||
|
// modalState.from = Object.assign(modalState.from, res.data);
|
||||||
|
// modalState.title = t('views.manage.job.viewJob');
|
||||||
|
// modalState.openByView = true;
|
||||||
|
// } else {
|
||||||
|
// message.error(t('views.manage.job.viewInfoErr'), 2);
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话框弹出关闭执行函数
|
||||||
|
* 进行表达规则校验
|
||||||
|
*/
|
||||||
|
function fnModalCancel() {
|
||||||
|
modalState.openByEdit = false;
|
||||||
|
modalState.openByView = false;
|
||||||
|
// modalStateFrom.resetFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话框弹出显示为 新增或者修改
|
||||||
|
* @param jobId 任务id, 不传为新增
|
||||||
|
*/
|
||||||
|
function fnModalVisibleByEdit(jobId?: string | number) {
|
||||||
|
if (!jobId) {
|
||||||
|
//modalStateFrom.resetFields();
|
||||||
|
modalState.title = t('page.manage.task.addJob');
|
||||||
|
modalState.openByEdit = true;
|
||||||
|
} else {
|
||||||
|
if (modalState.confirmLoading) return;
|
||||||
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
|
modalState.confirmLoading = true;
|
||||||
|
doGetjobInfo(jobId).then(res => {
|
||||||
|
modalState.confirmLoading = false;
|
||||||
|
hide();
|
||||||
|
if (!res.error) {
|
||||||
|
modalState.from = Object.assign(modalState.from, res.data);
|
||||||
|
modalState.title = t('page.manage.task.editJob');
|
||||||
|
modalState.openByEdit = true;
|
||||||
|
} else {
|
||||||
|
message.error(t('page.manage.task.getInfoError'), 2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<SimpleScrollbar>
|
||||||
|
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
||||||
|
<!-- 搜索框 -->
|
||||||
|
<ACard :title="$t('common.search')" :bordered="false" class="card-wrapper">
|
||||||
|
<AForm :model="searchParams" :label-width="80">
|
||||||
|
<ARow :gutter="[16, 16]" wrap>
|
||||||
|
<ACol :lg="6" :md="12" :xs="24">
|
||||||
|
<AFormItem label="Name" name="operIp" class="m-0">
|
||||||
|
<AInput v-model:value="searchParams.operIp" />
|
||||||
|
</AFormItem>
|
||||||
|
</ACol>
|
||||||
|
|
||||||
|
<ACol :lg="6" :md="12" :xs="24">
|
||||||
|
<AFormItem label="Group" name="title" class="m-0">
|
||||||
|
<AInput v-model:value="searchParams.title" />
|
||||||
|
</AFormItem>
|
||||||
|
</ACol>
|
||||||
|
|
||||||
|
|
||||||
|
<ACol :lg="6" :md="12" :xs="24">
|
||||||
|
<AFormItem :label="$t('page.manage.user.status')" name="status" class="m-0">
|
||||||
|
<ASelect v-model:value="searchParams.status" :placeholder="$t('page.manage.user.form.status')"
|
||||||
|
allow-clear>
|
||||||
|
<ASelectOption v-for="option in enableStatusOptions" :key="option.value" :value="option.value">
|
||||||
|
{{ $t(option.label) }}
|
||||||
|
</ASelectOption>
|
||||||
|
</ASelect>
|
||||||
|
</AFormItem>
|
||||||
|
</ACol>
|
||||||
|
|
||||||
|
|
||||||
|
<ACol :lg="6" :md="12" :xs="24">
|
||||||
|
<AFormItem class="m-0">
|
||||||
|
<div class="w-full flex-y-center justify-end gap-8px">
|
||||||
|
<a-space :size="8">
|
||||||
|
<a-button @click="fnTest">
|
||||||
|
<template #icon>
|
||||||
|
<SyncOutlined />
|
||||||
|
</template>
|
||||||
|
{{ $t('common.reset') }}
|
||||||
|
</a-button>
|
||||||
|
<AButton type="primary" ghost @click="getData">
|
||||||
|
<template #icon>
|
||||||
|
<SearchOutlined />
|
||||||
|
</template>
|
||||||
|
{{ $t('common.search') }}
|
||||||
|
</AButton>
|
||||||
|
</a-space>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</AFormItem>
|
||||||
|
</ACol>
|
||||||
|
</ARow>
|
||||||
|
</AForm>
|
||||||
|
</ACard>
|
||||||
|
|
||||||
|
<ACard title="Task Management" :bordered="false" :body-style="{ flex: 1, overflow: 'hidden' }"
|
||||||
|
class="flex-col-stretch sm:flex-1-hidden card-wrapper">
|
||||||
|
<template #extra>
|
||||||
|
<!-- <TableHeaderOperation v-model:columns="columnChecks" :disabled-delete="checkedRowKeys.length === 0"
|
||||||
|
:loading="loading" :show-delete="true" @add="handleAdd" @delete="handleBatchDelete" @refresh="getData"
|
||||||
|
:showExport="true" :not-show-add="false" /> -->
|
||||||
|
|
||||||
|
<div class="flex flex-wrap justify-end gap-x-12px gap-y-8px lt-sm:(w-200px py-12px)">
|
||||||
|
<slot name="prefix"></slot>
|
||||||
|
<slot name="default">
|
||||||
|
<AButton size="small" ghost type="primary" @click="fnModalVisibleByEdit()">
|
||||||
|
<div class="flex-y-center gap-8px">
|
||||||
|
<icon-ic-round-plus class="text-icon" />
|
||||||
|
<span>{{ $t('common.add') }}</span>
|
||||||
|
</div>
|
||||||
|
</AButton>
|
||||||
|
<APopconfirm :title="$t('common.confirmDelete')" :disabled="checkedRowKeys.length === 0"
|
||||||
|
@confirm="handleBatchDelete">
|
||||||
|
<AButton size="small" danger :disabled="checkedRowKeys.length <= 0">
|
||||||
|
<div class="flex-y-center gap-8px">
|
||||||
|
<icon-ic-round-delete class="text-icon" />
|
||||||
|
<span>{{ $t('common.batchDelete') }}</span>
|
||||||
|
</div>
|
||||||
|
</AButton>
|
||||||
|
</APopconfirm>
|
||||||
|
</slot>
|
||||||
|
<AButton size="small" @click="getData">
|
||||||
|
<div class="flex-y-center gap-8px">
|
||||||
|
<icon-mdi-refresh class="text-icon" :class="{ 'animate-spin': loading }" />
|
||||||
|
<span>{{ $t('common.refresh') }}</span>
|
||||||
|
</div>
|
||||||
|
</AButton>
|
||||||
|
<!-- <AButton size="small" type="primary" @click="handleExport" v-show="showExport">
|
||||||
|
<div class="flex-y-center gap-8px">
|
||||||
|
<icon-mdi-refresh class="text-icon" :class="{ 'animate-spin': loading }" />
|
||||||
|
<span>{{ $t('common.export') }}</span>
|
||||||
|
</div>
|
||||||
|
</AButton> -->
|
||||||
|
<TableColumnSetting v-model:columns="columns" />
|
||||||
|
<slot name="suffix"></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<ATable ref="wrapperEl" row-key="jobId" :columns="columns" :data-source="data" :loading="loading"
|
||||||
|
:row-selection="{
|
||||||
|
selectedRowKeys: checkedRowKeys,
|
||||||
|
onChange: handleUserSelectChange,
|
||||||
|
}" size="small" :pagination="mobilePagination" :scroll="scrollConfig" class="h-full">
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
|
||||||
|
<template v-if="column.key === 'status'">
|
||||||
|
<a-switch v-model:checked="record.status" checked-value="0" un-checked-value="1" size="small" />
|
||||||
|
<!-- <DictTag :options="{
|
||||||
|
'0': t('common.normal'),
|
||||||
|
'1': t('common.abnormal'),
|
||||||
|
}" :value="record.status" /> -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="column.key === 'operate'">
|
||||||
|
<a-space :size="8" align="center">
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>{{ 'View' }}</template>
|
||||||
|
<a-button type="link" @click.prevent="fnRecordView(record.jobId)">
|
||||||
|
<template #icon>
|
||||||
|
<ProfileOutlined />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>{{ 'Edit' }}</template>
|
||||||
|
<a-button type="link" @click.prevent="fnModalVisibleByEdit(record.jobId)">
|
||||||
|
<template #icon>
|
||||||
|
<FormOutlined />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>{{ 'Delete' }}</template>
|
||||||
|
<a-button type="link">
|
||||||
|
<template #icon>
|
||||||
|
<DeleteOutlined />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>{{ 'run' }}</template>
|
||||||
|
<a-button type="link">
|
||||||
|
<template #icon>
|
||||||
|
<RocketOutlined />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>{{ 'Job Log' }}</template>
|
||||||
|
<a-button type="link">
|
||||||
|
<template #icon>
|
||||||
|
<ContainerOutlined />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
</ATable>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- <taskOperateDrawer v-model:visible="drawerVisible" :dept-tree-data="deptTreeData" :operate-type="operateType"
|
||||||
|
:row-data="editingData" @submitted="getData" /> -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 详情框 -->
|
||||||
|
<a-modal :width="800" v-model:open="modalState.openByView" :title="modalState.title" @cancel="fnModalCancel">
|
||||||
|
<a-form layout=" horizontal" :label-col="{ span: 6 }" :label-wrap="true">
|
||||||
|
<a-row>
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="$t('page.manage.task.taskName')" name="jobName">
|
||||||
|
{{ modalState.from.jobName }}
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="t('page.manage.task.status')" name="status">
|
||||||
|
{{
|
||||||
|
[{
|
||||||
|
label: t('common.normal'),
|
||||||
|
value: '0',
|
||||||
|
}, {
|
||||||
|
label: t('common.abnormal'),
|
||||||
|
value: '1',
|
||||||
|
}].find(s => s.value === modalState.from.status)
|
||||||
|
?.label
|
||||||
|
}}
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<a-row>
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="t('page.manage.task.invoke')" name="invokeTarget">
|
||||||
|
{{ modalState.from.invokeTarget }}
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="t('page.manage.task.group')" name="jobGroup">
|
||||||
|
<!-- <DictTag
|
||||||
|
:options="dict.sysJobGroup"
|
||||||
|
:value="modalState.from.jobGroup"
|
||||||
|
/> -->
|
||||||
|
{{ modalState.from.jobGroup }}
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<a-row>
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="t('page.manage.task.cron')" name="cronExpression">
|
||||||
|
<a-tag color="default">
|
||||||
|
{{ modalState.from.cronExpression }}
|
||||||
|
</a-tag>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<!-- <a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="t('page.manage.task.log')" name="saveLog">
|
||||||
|
<DictTag
|
||||||
|
:options="dict.sysJobSaveLog"
|
||||||
|
:value="modalState.from.saveLog"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col> -->
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="t('page.manage.task.createTime')" name="createTime" :label-wrap="true">
|
||||||
|
{{ modalState.from.createTime }}
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a-form-item :label="t('page.manage.task.targetParams')" name="targetParams" :label-col="{ span: 3 }"
|
||||||
|
:label-wrap="true">
|
||||||
|
<a-textarea v-model:value="modalState.from.targetParams" :auto-size="{ minRows: 2, maxRows: 6 }"
|
||||||
|
:disabled="true" />
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item :label="t('page.manage.task.remark')" name="remark" :label-col="{ span: 3 }"
|
||||||
|
:label-wrap="true">
|
||||||
|
<a-textarea v-model:value="modalState.from.remark" :auto-size="{ minRows: 2, maxRows: 6 }"
|
||||||
|
:disabled="true" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
<template #footer>
|
||||||
|
<a-button key="cancel" @click="fnModalCancel">
|
||||||
|
{{ t('common.close') }}
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</a-modal>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 新增框或修改框 -->
|
||||||
|
<!-- <a-modal :drag="true" :width="800" :destroyOnClose="true" :keyboard="false" :mask-closable="false"
|
||||||
|
:open="modalState.openByEdit" :title="modalState.title" :confirm-loading="modalState.confirmLoading"
|
||||||
|
@ok="fnModalOk" @cancel="fnModalCancel">
|
||||||
|
<a-form name="modalStateFrom" layout="horizontal" :label-col="{ span: 6 }" :label-wrap="true" :rules="rules">
|
||||||
|
<a-row>
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="t('page.manage.task.taskName')" name="jobName">
|
||||||
|
<a-input v-model:value="modalState.from.jobName" allow-clear
|
||||||
|
:placeholder="t('page.manage.task.jobNamePlease')"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="t('page.manage.task.status')" name="status">
|
||||||
|
<a-select v-model:value="modalState.from.status" default-value="0"
|
||||||
|
:placeholder="t('common.selectPlease')" :options="dict.sysJobStatus">
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<a-row>
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="t('page.manage.task.jobGroup')" name="jobGroup">
|
||||||
|
<a-select v-model:value="modalState.from.jobGroup" default-value="DEFAULT"
|
||||||
|
:placeholder="t('common.selectPlease')" :options="dict.sysJobGroup">
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="t('page.manage.task.saveLog')" name="saveLog">
|
||||||
|
<a-select v-model:value="modalState.from.saveLog" default-value="0"
|
||||||
|
:placeholder="t('common.selectPlease')" :options="dict.sysJobSaveLog">
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<a-form-item :label="t('page.manage.task.invokeTarget')" name="invokeTarget" :label-col="{ span: 3 }"
|
||||||
|
:label-wrap="true">
|
||||||
|
<a-input v-model:value="modalState.from.invokeTarget" allow-clear
|
||||||
|
:placeholder="t('page.manage.task.invokeTargetPlease')">
|
||||||
|
<template #prefix>
|
||||||
|
<a-tooltip placement="topLeft">
|
||||||
|
<template #title>
|
||||||
|
<div>{{ t('page.manage.task.invokeTargetTip') }}</div>
|
||||||
|
</template>
|
||||||
|
<InfoCircleOutlined style="opacity: 0.45; color: inherit" />
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
</a-input>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item :label="t('page.manage.task.cronExpression')" name="cronExpression" :label-col="{ span: 3 }"
|
||||||
|
:label-wrap="true">
|
||||||
|
<a-input v-model:value="modalState.from.cronExpression" allow-clear
|
||||||
|
:placeholder="t('page.manage.task.cronExpressionPlease')">
|
||||||
|
<template #prefix>
|
||||||
|
<a-tooltip placement="topLeft">
|
||||||
|
<template #title>
|
||||||
|
<div>
|
||||||
|
{{ t('page.manage.task.cronExpressionTip') }}<br />
|
||||||
|
{{ t('page.manage.task.cronExpressionTip1') }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<InfoCircleOutlined style="opacity: 0.45; color: inherit" />
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<template #addonAfter>
|
||||||
|
<a-button type="text" size="small" @click.prevent="fnModalCron(true)">
|
||||||
|
<template #icon>
|
||||||
|
<FieldTimeOutlined />
|
||||||
|
</template>
|
||||||
|
{{ t('page.manage.task.cronExpressionNew') }}
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</a-input>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item :label="t('page.manage.task.targetParams')" name="targetParams" :label-col="{ span: 3 }"
|
||||||
|
:label-wrap="true">
|
||||||
|
<a-textarea v-model:value="modalState.from.targetParams" :auto-size="{ minRows: 2, maxRows: 6 }"
|
||||||
|
:maxlength="400" :placeholder="t('page.manage.task.targetParamsPlease')" />
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item :label="t('page.manage.task.remark')" name="remark" :label-col="{ span: 3 }"
|
||||||
|
:label-wrap="true">
|
||||||
|
<a-textarea v-model:value="modalState.from.remark" :auto-size="{ minRows: 2, maxRows: 6 }"
|
||||||
|
:maxlength="400" :show-count="true" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal> -->
|
||||||
|
|
||||||
|
</ACard>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</SimpleScrollbar>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
222
src/views/manage/task/modules/task-operate-drawer.vue
Normal file
222
src/views/manage/task/modules/task-operate-drawer.vue
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { SimpleScrollbar } from '@sa/materials';
|
||||||
|
import { useAntdForm, useFormRules } from '@/hooks/common/form';
|
||||||
|
import { $t } from '@/locales';
|
||||||
|
import { enableStatusOptions } from '@/constants/business';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'logOperateDrawer'
|
||||||
|
});
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
/** the type of operation */
|
||||||
|
operateType: any;
|
||||||
|
/** the edit row data */
|
||||||
|
rowData?:any;
|
||||||
|
deptTreeData:any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>();
|
||||||
|
|
||||||
|
interface Emits {
|
||||||
|
(e: 'submitted'): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits<Emits>();
|
||||||
|
|
||||||
|
const visible = defineModel<boolean>('visible', {
|
||||||
|
default: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const { formRef, validate, resetFields } = useAntdForm();
|
||||||
|
const { defaultRequiredRule, formRules } = useFormRules();
|
||||||
|
const [spinning, spin] = useToggle();
|
||||||
|
|
||||||
|
const title = computed(() => {
|
||||||
|
const titles: any = {
|
||||||
|
add: $t('page.manage.user.addUser'),
|
||||||
|
edit: $t('page.manage.user.editUser')
|
||||||
|
};
|
||||||
|
return titles[props.operateType];
|
||||||
|
});
|
||||||
|
|
||||||
|
type Model = Partial<
|
||||||
|
Pick<Api.Auth.User, 'userName' | 'nickName' | 'email' | 'phonenumber' | 'status' | 'deptId' | 'remark'> & {
|
||||||
|
postIds: number[];
|
||||||
|
roleIds: number[];
|
||||||
|
password?: string;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
|
||||||
|
const model = ref<Model>(createDefaultModel());
|
||||||
|
|
||||||
|
const userPosts = ref<Api.SystemManage.Post[]>([]);
|
||||||
|
const userRoles = ref<Api.SystemManage.Role[]>([]);
|
||||||
|
|
||||||
|
function createDefaultModel(): Model {
|
||||||
|
return {
|
||||||
|
userName: '',
|
||||||
|
nickName: '',
|
||||||
|
email: '',
|
||||||
|
phonenumber: '',
|
||||||
|
status: '0',
|
||||||
|
deptId: undefined,
|
||||||
|
remark: '',
|
||||||
|
postIds: [],
|
||||||
|
roleIds: [],
|
||||||
|
password: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//制定规则
|
||||||
|
const rules = {
|
||||||
|
userName: defaultRequiredRule,
|
||||||
|
nickName: defaultRequiredRule,
|
||||||
|
status: defaultRequiredRule,
|
||||||
|
deptId: defaultRequiredRule,
|
||||||
|
email: formRules.email,
|
||||||
|
phonenumber: formRules.phone,
|
||||||
|
password: formRules.pwd,
|
||||||
|
postIds: defaultRequiredRule,
|
||||||
|
roleIds: defaultRequiredRule
|
||||||
|
};
|
||||||
|
|
||||||
|
// 修改时触发
|
||||||
|
async function init(userId: number | undefined = undefined) {
|
||||||
|
spin(true);
|
||||||
|
try {
|
||||||
|
await Promise.all([getUserPostAndRole(userId)]);
|
||||||
|
spin(false);
|
||||||
|
} catch (error) {
|
||||||
|
spin(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getUserPostAndRole(userId: number | undefined) {
|
||||||
|
const { error, data } = await doGetUserPostsAndRoles(userId);
|
||||||
|
//渲染用户岗位和角色option
|
||||||
|
if (!error) {
|
||||||
|
const { postIds, posts, roleIds, roles } = data;
|
||||||
|
userPosts.value = posts;
|
||||||
|
userRoles.value = roles;
|
||||||
|
model.value.postIds = postIds;
|
||||||
|
model.value.roleIds = roleIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleUpdateModelWhenEdit() {
|
||||||
|
if (props.operateType === 'add') {
|
||||||
|
model.value = createDefaultModel(); //新增时赋值
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.operateType === 'edit' && props.rowData) {
|
||||||
|
await init(props.rowData.userId);
|
||||||
|
model.value = Object.assign(model.value, omit(props.rowData, ['postIds', 'roleIds']));
|
||||||
|
} else {
|
||||||
|
await init();
|
||||||
|
model.value = createDefaultModel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeDrawer() {
|
||||||
|
visible.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSubmit() {
|
||||||
|
await validate();
|
||||||
|
|
||||||
|
const { error } = await (props.operateType === 'edit' ? doPutUser : doPostUser)(model.value as Api.Auth.User);
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
$message?.success($t(props.operateType === 'add' ? 'common.addSuccess' : 'common.updateSuccess'));
|
||||||
|
closeDrawer();
|
||||||
|
emit('submitted');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => visible.value,
|
||||||
|
val => {
|
||||||
|
if (val) {
|
||||||
|
handleUpdateModelWhenEdit();
|
||||||
|
resetFields();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// console.log(props.operateType)
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ADrawer
|
||||||
|
v-model:open="visible"
|
||||||
|
:body-style="{ paddingRight: '0px', paddingTop: '0', paddingBottom: '0' }"
|
||||||
|
:title="title"
|
||||||
|
:width="460"
|
||||||
|
>
|
||||||
|
<SimpleScrollbar>
|
||||||
|
<ASpin :spinning="spinning" size="small">
|
||||||
|
<AForm ref="formRef" py-20px pr-20px layout="vertical" :model="model" :rules="rules">
|
||||||
|
<AFormItem :label="$t('page.manage.user.userName')" name="userName">
|
||||||
|
<AInput v-model:value="model.userName" :placeholder="$t('page.manage.user.form.userName')" />
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem :label="$t('page.manage.user.nickName')" name="nickName">
|
||||||
|
<AInput v-model:value="model.nickName" :placeholder="$t('page.manage.user.form.nickName')" />
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem :label="$t('page.manage.user.email')" name="email">
|
||||||
|
<AInput v-model:value="model.email" :placeholder="$t('page.manage.user.form.email')" />
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem :label="$t('page.manage.user.phonenumber')" name="phonenumber">
|
||||||
|
<AInput v-model:value="model.phonenumber" :placeholder="$t('page.manage.user.form.phonenumber')" />
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem v-if="props.operateType === 'add'" :label="$t('page.manage.user.password')" name="password">
|
||||||
|
<AInput
|
||||||
|
v-model:value="model.password"
|
||||||
|
type="password"
|
||||||
|
:placeholder="$t('page.manage.user.form.password')"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem :label="$t('page.manage.user.post')" name="postIds">
|
||||||
|
<ASelect
|
||||||
|
v-model:value="model.postIds"
|
||||||
|
:field-names="{ label: 'postName', value: 'postId' }"
|
||||||
|
mode="multiple"
|
||||||
|
:options="userPosts"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem :label="$t('page.manage.user.role')" name="roleIds">
|
||||||
|
<ASelect
|
||||||
|
v-model:value="model.roleIds"
|
||||||
|
:field-names="{ label: 'roleName', value: 'roleId' }"
|
||||||
|
mode="multiple"
|
||||||
|
:options="userRoles"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem :label="$t('page.manage.user.status')" name="status">
|
||||||
|
<ARadioGroup v-model:value="model.status">
|
||||||
|
<ARadio v-for="item in enableStatusOptions" :key="item.value" :value="item.value">
|
||||||
|
{{ $t(item.label) }}
|
||||||
|
</ARadio>
|
||||||
|
</ARadioGroup>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem :label="$t('page.manage.user.dept')" name="deptId">
|
||||||
|
<ATreeSelect v-model:value="model.deptId" :field-names="{ value: 'id' }" :tree-data="deptTreeData" />
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem :label="$t('page.manage.user.remark')" name="remark">
|
||||||
|
<ATextarea v-model:value="model.remark" :placeholder="$t('page.manage.user.form.remark')" />
|
||||||
|
</AFormItem>
|
||||||
|
</AForm>
|
||||||
|
</ASpin>
|
||||||
|
</SimpleScrollbar>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="flex-y-center justify-end gap-12px">
|
||||||
|
<AButton @click="closeDrawer">{{ $t('common.cancel') }}</AButton>
|
||||||
|
<AButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</AButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ADrawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
109
src/views/manage/task/modules/task-search.vue
Normal file
109
src/views/manage/task/modules/task-search.vue
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { $t } from '@/locales';
|
||||||
|
import { enableStatusOptions } from '@/constants/business';
|
||||||
|
import { SyncOutlined, SearchOutlined } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'logSearch'
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
interface Emits {
|
||||||
|
(e: 'reset'): void;
|
||||||
|
(e: 'search'): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const emit = defineEmits<Emits>();
|
||||||
|
|
||||||
|
const model = defineModel<any>('model', { required: true });
|
||||||
|
|
||||||
|
/**记录开始结束时间 */
|
||||||
|
let queryRangePicker = ref<[string, string]>(['', '']);
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
// 重置表单
|
||||||
|
//formRef.value?.resetFields();
|
||||||
|
|
||||||
|
// 重置日期选择器
|
||||||
|
queryRangePicker.value = ['', ''];
|
||||||
|
|
||||||
|
// 确保 model 也被重置
|
||||||
|
model.value = {};
|
||||||
|
|
||||||
|
// 使用 nextTick 确保视图更新后检查
|
||||||
|
nextTick(() => {
|
||||||
|
console.log('视图更新后:', { ...model.value });
|
||||||
|
console.log(model);
|
||||||
|
});
|
||||||
|
emit('reset');
|
||||||
|
}
|
||||||
|
|
||||||
|
function search() {
|
||||||
|
if (!queryRangePicker.value) {
|
||||||
|
queryRangePicker.value = ['', ''];
|
||||||
|
}
|
||||||
|
model.value.beginTime = queryRangePicker.value[0];
|
||||||
|
model.value.endTime = queryRangePicker.value[1];
|
||||||
|
emit('search');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ACard :title="$t('common.search')" :bordered="false" class="card-wrapper">
|
||||||
|
<AForm :model="model" :label-width="80">
|
||||||
|
<ARow :gutter="[16, 16]" wrap>
|
||||||
|
<ACol :lg="6" :md="12" :xs="24">
|
||||||
|
<AFormItem label="Name" name="operIp" class="m-0">
|
||||||
|
<AInput v-model:value="model.operIp" />
|
||||||
|
</AFormItem>
|
||||||
|
</ACol>
|
||||||
|
|
||||||
|
<ACol :lg="6" :md="12" :xs="24">
|
||||||
|
<AFormItem label="Group" name="title" class="m-0">
|
||||||
|
<AInput v-model:value="model.title" />
|
||||||
|
</AFormItem>
|
||||||
|
</ACol>
|
||||||
|
|
||||||
|
|
||||||
|
<ACol :lg="6" :md="12" :xs="24">
|
||||||
|
<AFormItem :label="$t('page.manage.user.status')" name="status" class="m-0">
|
||||||
|
<ASelect v-model:value="model.status" :placeholder="$t('page.manage.user.form.status')" allow-clear>
|
||||||
|
<ASelectOption v-for="option in enableStatusOptions" :key="option.value" :value="option.value">
|
||||||
|
{{ $t(option.label) }}
|
||||||
|
</ASelectOption>
|
||||||
|
</ASelect>
|
||||||
|
</AFormItem>
|
||||||
|
</ACol>
|
||||||
|
|
||||||
|
|
||||||
|
<ACol :lg="6" :md="12" :xs="24">
|
||||||
|
<AFormItem class="m-0">
|
||||||
|
<div class="w-full flex-y-center justify-end gap-8px">
|
||||||
|
|
||||||
|
<a-space :size="8">
|
||||||
|
<a-button @click="reset">
|
||||||
|
<template #icon>
|
||||||
|
<SyncOutlined />
|
||||||
|
</template>
|
||||||
|
{{ $t('common.reset') }}
|
||||||
|
</a-button>
|
||||||
|
<AButton type="primary" ghost @click="search">
|
||||||
|
<template #icon>
|
||||||
|
<SearchOutlined />
|
||||||
|
</template>
|
||||||
|
{{ $t('common.search') }}
|
||||||
|
</AButton>
|
||||||
|
</a-space>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</AFormItem>
|
||||||
|
</ACol>
|
||||||
|
</ARow>
|
||||||
|
</AForm>
|
||||||
|
</ACard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
Reference in New Issue
Block a user