mirror of https://github.com/certd/certd
perf: 修复删除历史记录没有删除log的bug,新增history管理页面,演示站点启动时不自动启动非管理员用户的定时任务
parent
0227155ab4
commit
f78ae93eed
|
@ -1,9 +1,9 @@
|
||||||
import { request } from "../service";
|
import { request } from "../service";
|
||||||
|
|
||||||
export type SysPublicSetting = {
|
export type SysPublicSetting = {
|
||||||
registerEnabled:boolean
|
registerEnabled: boolean;
|
||||||
}
|
managerOtherUserPipeline: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export async function getSysPublicSettings(): Promise<SysPublicSetting> {
|
export async function getSysPublicSettings(): Promise<SysPublicSetting> {
|
||||||
return await request({
|
return await request({
|
||||||
|
|
|
@ -18,6 +18,7 @@ export interface UserInfoRes {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
username: string;
|
username: string;
|
||||||
nickName: string;
|
nickName: string;
|
||||||
|
roles: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LoginRes {
|
export interface LoginRes {
|
||||||
|
|
|
@ -27,6 +27,15 @@ export const certdResources = [
|
||||||
isMenu: false
|
isMenu: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "执行历史记录",
|
||||||
|
name: "pipelineHistory",
|
||||||
|
path: "/certd/history",
|
||||||
|
component: "/certd/history/index.vue",
|
||||||
|
meta: {
|
||||||
|
icon: "ion:timer-outline"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "授权管理",
|
title: "授权管理",
|
||||||
name: "access",
|
name: "access",
|
||||||
|
|
|
@ -4,9 +4,8 @@ import _ from "lodash-es";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { LocalStorage } from "/src/utils/util.storage";
|
import { LocalStorage } from "/src/utils/util.storage";
|
||||||
|
|
||||||
|
import * as basicApi from "/@/api/modules/api.basic";
|
||||||
import { SysPublicSetting } from "/@/api/modules/api.basic";
|
import { SysPublicSetting } from "/@/api/modules/api.basic";
|
||||||
import * as basicApi from '/@/api/modules/api.basic'
|
|
||||||
import _ from "lodash-es";
|
|
||||||
|
|
||||||
export type ThemeToken = {
|
export type ThemeToken = {
|
||||||
token: {
|
token: {
|
||||||
|
@ -21,7 +20,7 @@ export type ThemeConfig = {
|
||||||
export interface SettingState {
|
export interface SettingState {
|
||||||
themeConfig?: ThemeConfig;
|
themeConfig?: ThemeConfig;
|
||||||
themeToken: ThemeToken;
|
themeToken: ThemeToken;
|
||||||
sysPublic?: SysPublicSetting
|
sysPublic?: SysPublicSetting;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultThemeConfig = {
|
const defaultThemeConfig = {
|
||||||
|
@ -38,7 +37,8 @@ export const useSettingStore = defineStore({
|
||||||
algorithm: theme.defaultAlgorithm
|
algorithm: theme.defaultAlgorithm
|
||||||
},
|
},
|
||||||
sysPublic: {
|
sysPublic: {
|
||||||
registerEnabled: false
|
registerEnabled: false,
|
||||||
|
managerOtherUserPipeline: false
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
|
@ -46,13 +46,13 @@ export const useSettingStore = defineStore({
|
||||||
return this.themeConfig || _.merge({}, defaultThemeConfig, LocalStorage.get(SETTING_THEME_KEY) || {});
|
return this.themeConfig || _.merge({}, defaultThemeConfig, LocalStorage.get(SETTING_THEME_KEY) || {});
|
||||||
},
|
},
|
||||||
getSysPublic(): SysPublicSetting {
|
getSysPublic(): SysPublicSetting {
|
||||||
return this.sysPublic
|
return this.sysPublic;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async loadSysSettings() {
|
async loadSysSettings() {
|
||||||
const settings = await basicApi.getSysPublicSettings()
|
const settings = await basicApi.getSysPublicSettings();
|
||||||
_.merge(this.sysPublic,settings)
|
_.merge(this.sysPublic, settings);
|
||||||
},
|
},
|
||||||
persistThemeConfig() {
|
persistThemeConfig() {
|
||||||
LocalStorage.set(SETTING_THEME_KEY, this.getThemeConfig);
|
LocalStorage.set(SETTING_THEME_KEY, this.getThemeConfig);
|
||||||
|
@ -92,7 +92,7 @@ export const useSettingStore = defineStore({
|
||||||
},
|
},
|
||||||
async init() {
|
async init() {
|
||||||
await this.setThemeConfig(this.getThemeConfig);
|
await this.setThemeConfig(this.getThemeConfig);
|
||||||
await this.loadSysSettings()
|
await this.loadSysSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -34,6 +34,9 @@ export const useUserStore = defineStore({
|
||||||
},
|
},
|
||||||
getToken(): string {
|
getToken(): string {
|
||||||
return this.token || LocalStorage.get(TOKEN_KEY);
|
return this.token || LocalStorage.get(TOKEN_KEY);
|
||||||
|
},
|
||||||
|
isAdmin(): boolean {
|
||||||
|
return this.getUserInfo?.id === 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { request } from "/src/api/service";
|
||||||
|
|
||||||
|
const apiPrefix = "/pi/history";
|
||||||
|
|
||||||
|
export function GetList(query: any) {
|
||||||
|
return request({
|
||||||
|
url: apiPrefix + "/page",
|
||||||
|
method: "post",
|
||||||
|
data: query
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AddObj(obj: any) {
|
||||||
|
return request({
|
||||||
|
url: apiPrefix + "/add",
|
||||||
|
method: "post",
|
||||||
|
data: obj
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UpdateObj(obj: any) {
|
||||||
|
return request({
|
||||||
|
url: apiPrefix + "/update",
|
||||||
|
method: "post",
|
||||||
|
data: obj
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DelObj(id: any) {
|
||||||
|
return request({
|
||||||
|
url: apiPrefix + "/delete",
|
||||||
|
method: "post",
|
||||||
|
params: { id }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GetObj(id: any) {
|
||||||
|
return request({
|
||||||
|
url: apiPrefix + "/info",
|
||||||
|
method: "post",
|
||||||
|
params: { id }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GetDetail(id: any) {
|
||||||
|
return request({
|
||||||
|
url: apiPrefix + "/detail",
|
||||||
|
method: "post",
|
||||||
|
params: { id }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DeleteBatch(ids: any[]) {
|
||||||
|
return request({
|
||||||
|
url: apiPrefix + "/deleteByIds",
|
||||||
|
method: "post",
|
||||||
|
data: { ids }
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
import * as api from "./api";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { computed, Ref, ref } from "vue";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes, utils } from "@fast-crud/fast-crud";
|
||||||
|
import { useUserStore } from "/@/store/modules/user";
|
||||||
|
import { useSettingStore } from "/@/store/modules/settings";
|
||||||
|
|
||||||
|
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||||
|
const router = useRouter();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||||
|
return await api.GetList(query);
|
||||||
|
};
|
||||||
|
const editRequest = async ({ form, row }: EditReq) => {
|
||||||
|
form.id = row.id;
|
||||||
|
const res = await api.UpdateObj(form);
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
const delRequest = async ({ row }: DelReq) => {
|
||||||
|
return await api.DelObj(row.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addRequest = async ({ form }: AddReq) => {
|
||||||
|
form.content = JSON.stringify({
|
||||||
|
title: form.title
|
||||||
|
});
|
||||||
|
const res = await api.AddObj(form);
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const settingStore = useSettingStore();
|
||||||
|
const selectedRowKeys: Ref<any[]> = ref([]);
|
||||||
|
context.selectedRowKeys = selectedRowKeys;
|
||||||
|
|
||||||
|
return {
|
||||||
|
crudOptions: {
|
||||||
|
settings: {
|
||||||
|
plugins: {
|
||||||
|
//这里使用行选择插件,生成行选择crudOptions配置,最终会与crudOptions合并
|
||||||
|
rowSelection: {
|
||||||
|
enabled: true,
|
||||||
|
order: -2,
|
||||||
|
before: true,
|
||||||
|
// handle: (pluginProps,useCrudProps)=>CrudOptions,
|
||||||
|
props: {
|
||||||
|
multiple: true,
|
||||||
|
crossPage: true,
|
||||||
|
selectedRowKeys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
request: {
|
||||||
|
pageRequest,
|
||||||
|
addRequest,
|
||||||
|
editRequest,
|
||||||
|
delRequest
|
||||||
|
},
|
||||||
|
actionbar: {
|
||||||
|
buttons: {
|
||||||
|
add: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rowHandle: {
|
||||||
|
minWidth: 200,
|
||||||
|
fixed: "right",
|
||||||
|
buttons: {
|
||||||
|
edit: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
id: {
|
||||||
|
title: "ID",
|
||||||
|
key: "id",
|
||||||
|
type: "number",
|
||||||
|
column: {
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
userId: {
|
||||||
|
title: "用户Id",
|
||||||
|
type: "number",
|
||||||
|
search: {
|
||||||
|
show: computed(() => {
|
||||||
|
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
show: computed(() => {
|
||||||
|
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pipelineId: {
|
||||||
|
title: "流水线Id",
|
||||||
|
type: "number",
|
||||||
|
search: {
|
||||||
|
show: true
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pipelineTitle: {
|
||||||
|
title: "流水线名称",
|
||||||
|
type: "link",
|
||||||
|
search: {
|
||||||
|
show: true,
|
||||||
|
component: {
|
||||||
|
name: "a-input"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
width: 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
createTime: {
|
||||||
|
title: "创建时间",
|
||||||
|
type: "datetime",
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
sorter: true,
|
||||||
|
width: 125,
|
||||||
|
align: "center"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateTime: {
|
||||||
|
title: "更新时间",
|
||||||
|
type: "datetime",
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
show: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
<template>
|
||||||
|
<fs-page class="page-cert">
|
||||||
|
<template #header>
|
||||||
|
<div class="title">流水线执行记录</div>
|
||||||
|
</template>
|
||||||
|
<fs-crud ref="crudRef" v-bind="crudBinding">
|
||||||
|
<template #pagination-left>
|
||||||
|
<a-tooltip title="批量删除">
|
||||||
|
<fs-button icon="DeleteOutlined" @click="handleBatchDelete"></fs-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
</fs-crud>
|
||||||
|
</fs-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted } from "vue";
|
||||||
|
import { useFs } from "@fast-crud/fast-crud";
|
||||||
|
import createCrudOptions from "./crud";
|
||||||
|
import { message, Modal } from "ant-design-vue";
|
||||||
|
import { DeleteBatch } from "/@/views/certd/history/api";
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: "PipelineHistory"
|
||||||
|
});
|
||||||
|
const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions });
|
||||||
|
|
||||||
|
const selectedRowKeys = context.selectedRowKeys;
|
||||||
|
const handleBatchDelete = () => {
|
||||||
|
if (selectedRowKeys.value?.length > 0) {
|
||||||
|
Modal.confirm({
|
||||||
|
title: "确认",
|
||||||
|
content: `确定要批量删除这${selectedRowKeys.value.length}条记录吗`,
|
||||||
|
async onOk() {
|
||||||
|
await DeleteBatch(selectedRowKeys.value);
|
||||||
|
message.info("删除成功");
|
||||||
|
crudExpose.doRefresh();
|
||||||
|
selectedRowKeys.value = [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
message.error("请先勾选记录");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 页面打开后获取列表数据
|
||||||
|
onMounted(() => {
|
||||||
|
crudExpose.doRefresh();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="less"></style>
|
|
@ -1,6 +1,6 @@
|
||||||
import * as api from "./api";
|
import * as api from "./api";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||||
import { statusUtil } from "/@/views/certd/pipeline/pipeline/utils/util.status";
|
import { statusUtil } from "/@/views/certd/pipeline/pipeline/utils/util.status";
|
||||||
|
@ -9,6 +9,7 @@ import { message, Modal } from "ant-design-vue";
|
||||||
import { env } from "/@/utils/util.env";
|
import { env } from "/@/utils/util.env";
|
||||||
import { useUserStore } from "/@/store/modules/user";
|
import { useUserStore } from "/@/store/modules/user";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import { useSettingStore } from "/@/store/modules/settings";
|
||||||
|
|
||||||
export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -94,6 +95,7 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
const settingStore = useSettingStore();
|
||||||
return {
|
return {
|
||||||
crudOptions: {
|
crudOptions: {
|
||||||
request: {
|
request: {
|
||||||
|
@ -192,6 +194,23 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
userId: {
|
||||||
|
title: "用户Id",
|
||||||
|
type: "number",
|
||||||
|
search: {
|
||||||
|
show: computed(() => {
|
||||||
|
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
show: computed(() => {
|
||||||
|
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
title: {
|
title: {
|
||||||
title: "流水线名称",
|
title: "流水线名称",
|
||||||
type: "link",
|
type: "link",
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<a-form ref="formRef" class="user-layout-login" name="custom-validation" :model="formState" :rules="rules" v-bind="layout" @finish="handleFinish" @finishFailed="handleFinishFailed">
|
<a-form
|
||||||
|
ref="formRef"
|
||||||
|
class="user-layout-login"
|
||||||
|
name="custom-validation"
|
||||||
|
:model="formState"
|
||||||
|
:rules="rules"
|
||||||
|
v-bind="layout"
|
||||||
|
@finish="handleFinish"
|
||||||
|
@finish-failed="handleFinishFailed"
|
||||||
|
>
|
||||||
<!-- <div class="login-title">登录</div>-->
|
<!-- <div class="login-title">登录</div>-->
|
||||||
<a-tabs :active-key="formState.loginType" :tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }">
|
<a-tabs :active-key="formState.loginType" :tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }">
|
||||||
<a-tab-pane key="password" tab="用户名密码登录">
|
<a-tab-pane key="password" tab="用户名密码登录">
|
||||||
|
@ -55,7 +64,13 @@
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col class="gutter-row" :span="8">
|
<a-col class="gutter-row" :span="8">
|
||||||
<a-button class="getCaptcha" tabindex="-1" :disabled="smsSendBtnDisabled" @click="sendSmsCode" v-text="smsTime <= 0 ? '发送' : smsTime + ' s'"></a-button>
|
<a-button
|
||||||
|
class="getCaptcha"
|
||||||
|
tabindex="-1"
|
||||||
|
:disabled="smsSendBtnDisabled"
|
||||||
|
@click="sendSmsCode"
|
||||||
|
v-text="smsTime <= 0 ? '发送' : smsTime + ' s'"
|
||||||
|
></a-button>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
@ -81,7 +96,7 @@ export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const settingStore = useSettingStore()
|
const settingStore = useSettingStore();
|
||||||
const formRef = ref();
|
const formRef = ref();
|
||||||
const formState = reactive({
|
const formState = reactive({
|
||||||
username: "",
|
username: "",
|
||||||
|
@ -168,7 +183,7 @@ export default defineComponent({
|
||||||
function sendSmsCode() {
|
function sendSmsCode() {
|
||||||
//api.sendSmsCode();
|
//api.sendSmsCode();
|
||||||
}
|
}
|
||||||
const sysPublicSettings = settingStore.getSysPublic
|
const sysPublicSettings = settingStore.getSysPublic;
|
||||||
return {
|
return {
|
||||||
loading,
|
loading,
|
||||||
formState,
|
formState,
|
||||||
|
|
|
@ -1,6 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<a-form ref="formRef" class="user-layout-register" name="custom-validation" :model="formState" :rules="rules" v-bind="layout" @finish="handleFinish" @finishFailed="handleFinishFailed">
|
<a-form
|
||||||
|
ref="formRef"
|
||||||
|
class="user-layout-register"
|
||||||
|
name="custom-validation"
|
||||||
|
:model="formState"
|
||||||
|
:rules="rules"
|
||||||
|
v-bind="layout"
|
||||||
|
:label-col="{ span: 5 }"
|
||||||
|
@finish="handleFinish"
|
||||||
|
@finish-failed="handleFinishFailed"
|
||||||
|
>
|
||||||
<a-tabs :tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }">
|
<a-tabs :tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }">
|
||||||
<a-tab-pane key="register" tab="用户注册"> </a-tab-pane>
|
<a-tab-pane key="register" tab="用户注册"> </a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
|
|
|
@ -4,8 +4,7 @@ const apiPrefix = "/sys/settings";
|
||||||
|
|
||||||
export const SettingKeys = {
|
export const SettingKeys = {
|
||||||
SysPublic: "sys.public",
|
SysPublic: "sys.public",
|
||||||
SysPrivate: "sys.private",
|
SysPrivate: "sys.private"
|
||||||
|
|
||||||
};
|
};
|
||||||
export async function SettingsGet(key: string) {
|
export async function SettingsGet(key: string) {
|
||||||
return await request({
|
return await request({
|
||||||
|
@ -23,12 +22,11 @@ export async function SettingsSave(key: string,setting: any) {
|
||||||
method: "post",
|
method: "post",
|
||||||
data: {
|
data: {
|
||||||
key,
|
key,
|
||||||
setting: JSON.stringify(setting),
|
setting: JSON.stringify(setting)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export async function PublicSettingsSave(setting: any) {
|
export async function PublicSettingsSave(setting: any) {
|
||||||
await request({
|
await request({
|
||||||
url: apiPrefix + "/savePublicSettings",
|
url: apiPrefix + "/savePublicSettings",
|
||||||
|
@ -36,3 +34,10 @@ export async function PublicSettingsSave(setting: any) {
|
||||||
data: setting
|
data: setting
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function stopOtherUserTimer() {
|
||||||
|
await request({
|
||||||
|
url: apiPrefix + "/stopOtherUserTimer",
|
||||||
|
method: "post"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -4,14 +4,31 @@
|
||||||
<div class="title">系统设置</div>
|
<div class="title">系统设置</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="sys-settings-form">
|
<div class="sys-settings-form">
|
||||||
<a-form :model="formState" name="basic" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }" autocomplete="off" @finish="onFinish" @finish-failed="onFinishFailed">
|
<a-form
|
||||||
|
:model="formState"
|
||||||
|
name="basic"
|
||||||
|
:label-col="{ span: 8 }"
|
||||||
|
:wrapper-col="{ span: 16 }"
|
||||||
|
autocomplete="off"
|
||||||
|
@finish="onFinish"
|
||||||
|
@finish-failed="onFinishFailed"
|
||||||
|
>
|
||||||
<a-form-item label="开启自助注册" name="registerEnabled">
|
<a-form-item label="开启自助注册" name="registerEnabled">
|
||||||
<a-switch v-model:checked="formState.registerEnabled" />
|
<a-switch v-model:checked="formState.registerEnabled" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item label="管理其他用户流水线" name="managerOtherUserPipeline">
|
||||||
|
<a-switch v-model:checked="formState.managerOtherUserPipeline" />
|
||||||
|
</a-form-item>
|
||||||
<a-form-item :wrapper-col="{ offset: 8, span: 16 }">
|
<a-form-item :wrapper-col="{ offset: 8, span: 16 }">
|
||||||
<a-button type="primary" html-type="submit">保存</a-button>
|
<a-button type="primary" html-type="submit">保存</a-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
|
|
||||||
|
<!-- <a-descriptions label="系统维护操作">-->
|
||||||
|
<!-- <a-descriptions-item label="自动化任务">-->
|
||||||
|
<!-- <a-button @click="stopOtherUserTimer">停止所有其他用户的定时任务</a-button>-->
|
||||||
|
<!-- </a-descriptions-item>-->
|
||||||
|
<!-- </a-descriptions>-->
|
||||||
</div>
|
</div>
|
||||||
</fs-page>
|
</fs-page>
|
||||||
</template>
|
</template>
|
||||||
|
@ -25,7 +42,6 @@ import { useSettingStore } from "/@/store/modules/settings";
|
||||||
|
|
||||||
interface FormState {
|
interface FormState {
|
||||||
registerEnabled: boolean;
|
registerEnabled: boolean;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const formState = reactive<Partial<FormState>>({
|
const formState = reactive<Partial<FormState>>({
|
||||||
|
@ -39,11 +55,11 @@ async function loadSysPublicSettings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
loadSysPublicSettings();
|
loadSysPublicSettings();
|
||||||
const settingsStore= useSettingStore()
|
const settingsStore = useSettingStore();
|
||||||
const onFinish = async (form: any) => {
|
const onFinish = async (form: any) => {
|
||||||
console.log("Success:", form);
|
console.log("Success:", form);
|
||||||
await api.PublicSettingsSave(form);
|
await api.PublicSettingsSave(form);
|
||||||
await settingsStore.loadSysSettings()
|
await settingsStore.loadSysSettings();
|
||||||
notification.success({
|
notification.success({
|
||||||
message: "保存成功"
|
message: "保存成功"
|
||||||
});
|
});
|
||||||
|
@ -53,6 +69,12 @@ const onFinishFailed = (errorInfo: any) => {
|
||||||
// console.log("Failed:", errorInfo);
|
// console.log("Failed:", errorInfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function stopOtherUserTimer() {
|
||||||
|
await api.stopOtherUserTimer();
|
||||||
|
notification.success({
|
||||||
|
message: "停止成功"
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
|
|
@ -10,7 +10,7 @@ export abstract class BaseController {
|
||||||
* 成功返回
|
* 成功返回
|
||||||
* @param data 返回数据
|
* @param data 返回数据
|
||||||
*/
|
*/
|
||||||
ok(data: any) {
|
ok(data?: any) {
|
||||||
const res = {
|
const res = {
|
||||||
...Constants.res.success,
|
...Constants.res.success,
|
||||||
data: undefined,
|
data: undefined,
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import { Config, Inject, Provide } from '@midwayjs/core';
|
import { Config, Inject, MidwayWebRouterService, Provide } from '@midwayjs/core';
|
||||||
import { IMidwayKoaContext, IWebMiddleware, NextFunction } from '@midwayjs/koa';
|
import { IMidwayKoaContext, IWebMiddleware, NextFunction } from '@midwayjs/koa';
|
||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
import { Constants } from '../basic/constants.js';
|
import { Constants } from '../basic/constants.js';
|
||||||
import { MidwayWebRouterService } from '@midwayjs/core';
|
|
||||||
import { RoleService } from '../modules/authority/service/role-service.js';
|
|
||||||
import { logger } from '../utils/logger.js';
|
import { logger } from '../utils/logger.js';
|
||||||
|
import { AuthService } from '../modules/authority/service/auth-service.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 权限校验
|
* 权限校验
|
||||||
|
@ -16,7 +15,7 @@ export class AuthorityMiddleware implements IWebMiddleware {
|
||||||
@Inject()
|
@Inject()
|
||||||
webRouterService: MidwayWebRouterService;
|
webRouterService: MidwayWebRouterService;
|
||||||
@Inject()
|
@Inject()
|
||||||
roleService: RoleService;
|
authService: AuthService;
|
||||||
|
|
||||||
resolve() {
|
resolve() {
|
||||||
return async (ctx: IMidwayKoaContext, next: NextFunction) => {
|
return async (ctx: IMidwayKoaContext, next: NextFunction) => {
|
||||||
|
@ -59,11 +58,8 @@ export class AuthorityMiddleware implements IWebMiddleware {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (permission !== Constants.per.authOnly) {
|
if (permission !== Constants.per.authOnly) {
|
||||||
//如果不是仅校验登录,还需要校验是否拥有权限
|
const pass = await this.authService.checkPermission(ctx, permission);
|
||||||
const roleIds: number[] = ctx.user.roles;
|
if (!pass) {
|
||||||
const permissions = await this.roleService.getCachedPermissionSetByRoleIds(roleIds);
|
|
||||||
|
|
||||||
if (!permissions.has(permission)) {
|
|
||||||
logger.info('not permission: ', ctx.req.url);
|
logger.info('not permission: ', ctx.req.url);
|
||||||
ctx.status = 401;
|
ctx.status = 401;
|
||||||
ctx.body = Constants.res.permission;
|
ctx.body = Constants.res.permission;
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
|
import { RoleService } from './role-service.js';
|
||||||
|
import { BaseService } from '../../../basic/base-service.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限校验
|
||||||
|
*/
|
||||||
|
@Provide()
|
||||||
|
@Scope(ScopeEnum.Singleton)
|
||||||
|
export class AuthService {
|
||||||
|
@Inject()
|
||||||
|
roleService: RoleService;
|
||||||
|
|
||||||
|
async checkPermission(ctx: any, permission: string) {
|
||||||
|
//如果不是仅校验登录,还需要校验是否拥有权限
|
||||||
|
const roleIds: number[] = ctx.user.roles;
|
||||||
|
const permissions = await this.roleService.getCachedPermissionSetByRoleIds(roleIds);
|
||||||
|
if (!permissions.has(permission)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async isAdmin(ctx: any) {
|
||||||
|
const roleIds: number[] = ctx.user.roles;
|
||||||
|
if (roleIds.includes(1)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkEntityUserId(ctx: any, service: BaseService<any>, id: any = 0, userKey = 'userId') {
|
||||||
|
const isAdmin = await this.isAdmin(ctx);
|
||||||
|
if (isAdmin) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
await service.checkUserId(id, ctx.user.id, userKey);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import { Autoload, Config, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Autoload, Config, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import { PipelineService } from '../service/pipeline-service.js';
|
import { PipelineService } from '../pipeline/service/pipeline-service.js';
|
||||||
import { logger } from '../../../utils/logger.js';
|
import { logger } from '../../utils/logger.js';
|
||||||
|
|
||||||
@Autoload()
|
@Autoload()
|
||||||
@Scope(ScopeEnum.Singleton)
|
@Scope(ScopeEnum.Singleton)
|
||||||
|
@ -8,6 +8,9 @@ export class AutoRegisterCron {
|
||||||
@Inject()
|
@Inject()
|
||||||
pipelineService: PipelineService;
|
pipelineService: PipelineService;
|
||||||
|
|
||||||
|
@Config('preview.enabled')
|
||||||
|
private preview: boolean;
|
||||||
|
|
||||||
// @Inject()
|
// @Inject()
|
||||||
// echoPlugin: EchoPlugin;
|
// echoPlugin: EchoPlugin;
|
||||||
@Config('cron.immediateTriggerOnce')
|
@Config('cron.immediateTriggerOnce')
|
||||||
|
@ -16,7 +19,7 @@ export class AutoRegisterCron {
|
||||||
@Init()
|
@Init()
|
||||||
async init() {
|
async init() {
|
||||||
logger.info('加载定时trigger开始');
|
logger.info('加载定时trigger开始');
|
||||||
await this.pipelineService.onStartup(this.immediateTriggerOnce);
|
await this.pipelineService.onStartup(this.immediateTriggerOnce, this.preview);
|
||||||
// logger.info(this.echoPlugin, this.echoPlugin.test);
|
// logger.info(this.echoPlugin, this.echoPlugin.test);
|
||||||
// logger.info('加载定时trigger完成');
|
// logger.info('加载定时trigger完成');
|
||||||
//
|
//
|
|
@ -11,6 +11,8 @@ import { CommonException } from '../../../basic/exception/common-exception.js';
|
||||||
import { PermissionException } from '../../../basic/exception/permission-exception.js';
|
import { PermissionException } from '../../../basic/exception/permission-exception.js';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { logger } from '../../../utils/logger.js';
|
import { logger } from '../../../utils/logger.js';
|
||||||
|
import { AuthService } from '../../authority/service/auth-service.js';
|
||||||
|
import { SysSettingsService } from '../../system/service/sys-settings-service.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 证书
|
* 证书
|
||||||
|
@ -25,19 +27,35 @@ export class HistoryController extends CrudController<HistoryService> {
|
||||||
@Inject()
|
@Inject()
|
||||||
logService: HistoryLogService;
|
logService: HistoryLogService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
authService: AuthService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
sysSettingsService: SysSettingsService;
|
||||||
|
|
||||||
getService() {
|
getService() {
|
||||||
return this.service;
|
return this.service;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/page', { summary: Constants.per.authOnly })
|
@Post('/page', { summary: Constants.per.authOnly })
|
||||||
async page(@Body(ALL) body) {
|
async page(@Body(ALL) body) {
|
||||||
|
const isAdmin = await this.authService.isAdmin(this.ctx);
|
||||||
|
const publicSettings = await this.sysSettingsService.getPublicSettings();
|
||||||
|
if (!(publicSettings.managerOtherUserPipeline && isAdmin)) {
|
||||||
body.query.userId = this.ctx.user.id;
|
body.query.userId = this.ctx.user.id;
|
||||||
return super.page(body);
|
}
|
||||||
|
|
||||||
|
const res = await super.page(body);
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/list', { summary: Constants.per.authOnly })
|
@Post('/list', { summary: Constants.per.authOnly })
|
||||||
async list(@Body(ALL) body) {
|
async list(@Body(ALL) body) {
|
||||||
|
const isAdmin = await this.authService.isAdmin(this.ctx);
|
||||||
|
if (!isAdmin) {
|
||||||
body.userId = this.ctx.user.id;
|
body.userId = this.ctx.user.id;
|
||||||
|
}
|
||||||
if (body.pipelineId == null) {
|
if (body.pipelineId == null) {
|
||||||
return this.ok([]);
|
return this.ok([]);
|
||||||
}
|
}
|
||||||
|
@ -56,7 +74,7 @@ export class HistoryController extends CrudController<HistoryService> {
|
||||||
|
|
||||||
@Post('/update', { summary: Constants.per.authOnly })
|
@Post('/update', { summary: Constants.per.authOnly })
|
||||||
async update(@Body(ALL) bean) {
|
async update(@Body(ALL) bean) {
|
||||||
await this.service.checkUserId(bean.id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), bean.id);
|
||||||
return super.update(bean);
|
return super.update(bean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +82,7 @@ export class HistoryController extends CrudController<HistoryService> {
|
||||||
async save(@Body(ALL) bean: HistoryEntity) {
|
async save(@Body(ALL) bean: HistoryEntity) {
|
||||||
bean.userId = this.ctx.user.id;
|
bean.userId = this.ctx.user.id;
|
||||||
if (bean.id > 0) {
|
if (bean.id > 0) {
|
||||||
await this.service.checkUserId(bean.id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), bean.id);
|
||||||
}
|
}
|
||||||
await this.service.save(bean);
|
await this.service.save(bean);
|
||||||
return this.ok(bean.id);
|
return this.ok(bean.id);
|
||||||
|
@ -74,7 +92,7 @@ export class HistoryController extends CrudController<HistoryService> {
|
||||||
async saveLog(@Body(ALL) bean: HistoryLogEntity) {
|
async saveLog(@Body(ALL) bean: HistoryLogEntity) {
|
||||||
bean.userId = this.ctx.user.id;
|
bean.userId = this.ctx.user.id;
|
||||||
if (bean.id > 0) {
|
if (bean.id > 0) {
|
||||||
await this.service.checkUserId(bean.id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), bean.id);
|
||||||
}
|
}
|
||||||
await this.logService.save(bean);
|
await this.logService.save(bean);
|
||||||
return this.ok(bean.id);
|
return this.ok(bean.id);
|
||||||
|
@ -82,26 +100,37 @@ export class HistoryController extends CrudController<HistoryService> {
|
||||||
|
|
||||||
@Post('/delete', { summary: Constants.per.authOnly })
|
@Post('/delete', { summary: Constants.per.authOnly })
|
||||||
async delete(@Query('id') id) {
|
async delete(@Query('id') id) {
|
||||||
await this.service.checkUserId(id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), id);
|
||||||
return super.delete(id);
|
await super.delete(id);
|
||||||
|
return this.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/deleteByIds', { summary: Constants.per.authOnly })
|
||||||
|
async deleteByIds(@Body(ALL) body) {
|
||||||
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), body.ids);
|
||||||
|
const isAdmin = await this.authService.isAdmin(this.ctx);
|
||||||
|
const userId = isAdmin ? null : this.ctx.user.id;
|
||||||
|
await this.getService().deleteByIds(body.ids, userId);
|
||||||
|
return this.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/detail', { summary: Constants.per.authOnly })
|
@Post('/detail', { summary: Constants.per.authOnly })
|
||||||
async detail(@Query('id') id) {
|
async detail(@Query('id') id) {
|
||||||
await this.service.checkUserId(id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), id);
|
||||||
const detail = await this.service.detail(id);
|
const detail = await this.service.detail(id);
|
||||||
return this.ok(detail);
|
return this.ok(detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/logs', { summary: Constants.per.authOnly })
|
@Post('/logs', { summary: Constants.per.authOnly })
|
||||||
async logs(@Query('id') id) {
|
async logs(@Query('id') id) {
|
||||||
await this.logService.checkUserId(id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.logService, id);
|
||||||
const logInfo = await this.logService.info(id);
|
const logInfo = await this.logService.info(id);
|
||||||
return this.ok(logInfo);
|
return this.ok(logInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/files', { summary: Constants.per.authOnly })
|
@Post('/files', { summary: Constants.per.authOnly })
|
||||||
async files(@Query('pipelineId') pipelineId, @Query('historyId') historyId) {
|
async files(@Query('pipelineId') pipelineId, @Query('historyId') historyId) {
|
||||||
|
await this.authService.checkEntityUserId(this.ctx, this.service, historyId);
|
||||||
const files = await this.getFiles(historyId, pipelineId);
|
const files = await this.getFiles(historyId, pipelineId);
|
||||||
return this.ok(files);
|
return this.ok(files);
|
||||||
}
|
}
|
||||||
|
@ -125,6 +154,7 @@ export class HistoryController extends CrudController<HistoryService> {
|
||||||
|
|
||||||
@Get('/download', { summary: Constants.per.authOnly })
|
@Get('/download', { summary: Constants.per.authOnly })
|
||||||
async download(@Query('pipelineId') pipelineId, @Query('historyId') historyId, @Query('fileId') fileId) {
|
async download(@Query('pipelineId') pipelineId, @Query('historyId') historyId, @Query('fileId') fileId) {
|
||||||
|
await this.authService.checkEntityUserId(this.ctx, this.service, historyId);
|
||||||
const files = await this.getFiles(historyId, pipelineId);
|
const files = await this.getFiles(historyId, pipelineId);
|
||||||
const file = files.find(f => f.id === fileId);
|
const file = files.find(f => f.id === fileId);
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
|
|
|
@ -4,6 +4,8 @@ import { PipelineService } from '../service/pipeline-service.js';
|
||||||
import { PipelineEntity } from '../entity/pipeline.js';
|
import { PipelineEntity } from '../entity/pipeline.js';
|
||||||
import { Constants } from '../../../basic/constants.js';
|
import { Constants } from '../../../basic/constants.js';
|
||||||
import { HistoryService } from '../service/history-service.js';
|
import { HistoryService } from '../service/history-service.js';
|
||||||
|
import { AuthService } from '../../authority/service/auth-service.js';
|
||||||
|
import { SysSettingsService } from '../../system/service/sys-settings-service.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 证书
|
* 证书
|
||||||
|
@ -15,6 +17,10 @@ export class PipelineController extends CrudController<PipelineService> {
|
||||||
service: PipelineService;
|
service: PipelineService;
|
||||||
@Inject()
|
@Inject()
|
||||||
historyService: HistoryService;
|
historyService: HistoryService;
|
||||||
|
@Inject()
|
||||||
|
authService: AuthService;
|
||||||
|
@Inject()
|
||||||
|
sysSettingsService: SysSettingsService;
|
||||||
|
|
||||||
getService() {
|
getService() {
|
||||||
return this.service;
|
return this.service;
|
||||||
|
@ -22,7 +28,11 @@ export class PipelineController extends CrudController<PipelineService> {
|
||||||
|
|
||||||
@Post('/page', { summary: Constants.per.authOnly })
|
@Post('/page', { summary: Constants.per.authOnly })
|
||||||
async page(@Body(ALL) body) {
|
async page(@Body(ALL) body) {
|
||||||
|
const isAdmin = await this.authService.isAdmin(this.ctx);
|
||||||
|
const publicSettings = await this.sysSettingsService.getPublicSettings();
|
||||||
|
if (!(publicSettings.managerOtherUserPipeline && isAdmin)) {
|
||||||
body.query.userId = this.ctx.user.id;
|
body.query.userId = this.ctx.user.id;
|
||||||
|
}
|
||||||
|
|
||||||
const title = body.query.title;
|
const title = body.query.title;
|
||||||
delete body.query.title;
|
delete body.query.title;
|
||||||
|
@ -47,7 +57,7 @@ export class PipelineController extends CrudController<PipelineService> {
|
||||||
|
|
||||||
@Post('/update', { summary: Constants.per.authOnly })
|
@Post('/update', { summary: Constants.per.authOnly })
|
||||||
async update(@Body(ALL) bean) {
|
async update(@Body(ALL) bean) {
|
||||||
await this.service.checkUserId(bean.id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), bean.id);
|
||||||
return super.update(bean);
|
return super.update(bean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +65,7 @@ export class PipelineController extends CrudController<PipelineService> {
|
||||||
async save(@Body(ALL) bean: PipelineEntity) {
|
async save(@Body(ALL) bean: PipelineEntity) {
|
||||||
bean.userId = this.ctx.user.id;
|
bean.userId = this.ctx.user.id;
|
||||||
if (bean.id > 0) {
|
if (bean.id > 0) {
|
||||||
await this.service.checkUserId(bean.id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), bean.id);
|
||||||
}
|
}
|
||||||
await this.service.save(bean);
|
await this.service.save(bean);
|
||||||
return this.ok(bean.id);
|
return this.ok(bean.id);
|
||||||
|
@ -63,28 +73,28 @@ export class PipelineController extends CrudController<PipelineService> {
|
||||||
|
|
||||||
@Post('/delete', { summary: Constants.per.authOnly })
|
@Post('/delete', { summary: Constants.per.authOnly })
|
||||||
async delete(@Query('id') id) {
|
async delete(@Query('id') id) {
|
||||||
await this.service.checkUserId(id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), id);
|
||||||
await this.service.delete(id);
|
await this.service.delete(id);
|
||||||
return this.ok({});
|
return this.ok({});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/detail', { summary: Constants.per.authOnly })
|
@Post('/detail', { summary: Constants.per.authOnly })
|
||||||
async detail(@Query('id') id) {
|
async detail(@Query('id') id) {
|
||||||
await this.service.checkUserId(id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), id);
|
||||||
const detail = await this.service.detail(id);
|
const detail = await this.service.detail(id);
|
||||||
return this.ok(detail);
|
return this.ok(detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/trigger', { summary: Constants.per.authOnly })
|
@Post('/trigger', { summary: Constants.per.authOnly })
|
||||||
async trigger(@Query('id') id) {
|
async trigger(@Query('id') id) {
|
||||||
await this.service.checkUserId(id, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.getService(), id);
|
||||||
await this.service.trigger(id);
|
await this.service.trigger(id);
|
||||||
return this.ok({});
|
return this.ok({});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/cancel', { summary: Constants.per.authOnly })
|
@Post('/cancel', { summary: Constants.per.authOnly })
|
||||||
async cancel(@Query('historyId') historyId) {
|
async cancel(@Query('historyId') historyId) {
|
||||||
await this.historyService.checkUserId(historyId, this.ctx.user.id);
|
await this.authService.checkEntityUserId(this.ctx, this.historyService, historyId);
|
||||||
await this.service.cancel(historyId);
|
await this.service.cancel(historyId);
|
||||||
return this.ok({});
|
return this.ok({});
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,4 +35,13 @@ export class HistoryEntity {
|
||||||
default: () => 'CURRENT_TIMESTAMP',
|
default: () => 'CURRENT_TIMESTAMP',
|
||||||
})
|
})
|
||||||
updateTime: Date;
|
updateTime: Date;
|
||||||
|
|
||||||
|
pipelineTitle: string;
|
||||||
|
|
||||||
|
fillPipelineTitle() {
|
||||||
|
if (this.pipeline) {
|
||||||
|
const pipeline = JSON.parse(this.pipeline);
|
||||||
|
this.pipelineTitle = pipeline.title;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { In, Repository } from 'typeorm';
|
||||||
import { BaseService } from '../../../basic/base-service.js';
|
import { BaseService } from '../../../basic/base-service.js';
|
||||||
import { HistoryLogEntity } from '../entity/history-log.js';
|
import { HistoryLogEntity } from '../entity/history-log.js';
|
||||||
|
|
||||||
|
@ -24,4 +24,11 @@ export class HistoryLogService extends BaseService<HistoryLogEntity> {
|
||||||
await this.add(bean);
|
await this.add(bean);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteByHistoryIds(numbers: number[]) {
|
||||||
|
if (numbers.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.repository.delete({ historyId: In(numbers) });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Config, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
import { Config, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { In, Repository } from 'typeorm';
|
||||||
import { BaseService } from '../../../basic/base-service.js';
|
import { BaseService } from '../../../basic/base-service.js';
|
||||||
import { HistoryEntity } from '../entity/history.js';
|
import { HistoryEntity } from '../entity/history.js';
|
||||||
import { PipelineEntity } from '../entity/pipeline.js';
|
import { PipelineEntity } from '../entity/pipeline.js';
|
||||||
|
@ -28,6 +28,14 @@ export class HistoryService extends BaseService<HistoryEntity> {
|
||||||
return this.repository;
|
return this.repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async page(query, page, sort, buildQuery) {
|
||||||
|
const res = await super.page(query, page, sort, buildQuery);
|
||||||
|
for (const item of res.records) {
|
||||||
|
item.fillPipelineTitle();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
async save(bean: HistoryEntity) {
|
async save(bean: HistoryEntity) {
|
||||||
if (bean.id > 0) {
|
if (bean.id > 0) {
|
||||||
await this.update(bean);
|
await this.update(bean);
|
||||||
|
@ -51,7 +59,7 @@ export class HistoryService extends BaseService<HistoryEntity> {
|
||||||
};
|
};
|
||||||
const { id } = await this.add(bean);
|
const { id } = await this.add(bean);
|
||||||
//清除大于pipeline.keepHistoryCount的历史记录
|
//清除大于pipeline.keepHistoryCount的历史记录
|
||||||
this.clear(pipeline.id, pipeline.keepHistoryCount);
|
await this.clear(pipeline.id, pipeline.keepHistoryCount);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +93,6 @@ export class HistoryService extends BaseService<HistoryEntity> {
|
||||||
skip: 0,
|
skip: 0,
|
||||||
take: deleteCountBatch,
|
take: deleteCountBatch,
|
||||||
});
|
});
|
||||||
await this.repository.remove(list);
|
|
||||||
|
|
||||||
for (const historyEntity of list) {
|
for (const historyEntity of list) {
|
||||||
const id = historyEntity.id;
|
const id = historyEntity.id;
|
||||||
|
@ -95,6 +102,9 @@ export class HistoryService extends BaseService<HistoryEntity> {
|
||||||
logger.error('删除文件失败', e);
|
logger.error('删除文件失败', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await this.repository.remove(list);
|
||||||
|
|
||||||
|
await this.logService.deleteByHistoryIds(list.map(item => item.id));
|
||||||
|
|
||||||
shouldDeleteCount -= deleteCountBatch;
|
shouldDeleteCount -= deleteCountBatch;
|
||||||
}
|
}
|
||||||
|
@ -124,4 +134,12 @@ export class HistoryService extends BaseService<HistoryEntity> {
|
||||||
});
|
});
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteByIds(ids: number[], userId: number) {
|
||||||
|
await this.repository.delete({
|
||||||
|
id: In(ids),
|
||||||
|
userId,
|
||||||
|
});
|
||||||
|
await this.logService.deleteByHistoryIds(ids);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,11 +100,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
await this.registerTriggerById(bean.id);
|
await this.registerTriggerById(bean.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async foreachPipeline(callback: (pipeline: PipelineEntity) => void) {
|
||||||
* 应用启动后初始加载记录
|
|
||||||
*/
|
|
||||||
async onStartup(immediateTriggerOnce: boolean) {
|
|
||||||
logger.info('加载定时trigger开始');
|
|
||||||
const idEntityList = await this.repository.find({
|
const idEntityList = await this.repository.find({
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
|
@ -135,14 +131,35 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const entity of list) {
|
for (const entity of list) {
|
||||||
|
await callback(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async stopOtherUserPipeline(userId: number) {
|
||||||
|
await this.foreachPipeline(async entity => {
|
||||||
|
if (entity.userId !== userId) {
|
||||||
|
await this.clearTriggers(entity.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用启动后初始加载记录
|
||||||
|
*/
|
||||||
|
async onStartup(immediateTriggerOnce: boolean, preview: boolean) {
|
||||||
|
logger.info('加载定时trigger开始');
|
||||||
|
await this.foreachPipeline(async entity => {
|
||||||
|
if (preview && entity.userId !== 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const pipeline = JSON.parse(entity.content ?? '{}');
|
const pipeline = JSON.parse(entity.content ?? '{}');
|
||||||
try {
|
try {
|
||||||
await this.registerTriggers(pipeline, immediateTriggerOnce);
|
await this.registerTriggers(pipeline, immediateTriggerOnce);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('加载定时trigger失败:', e);
|
logger.error('加载定时trigger失败:', e);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
|
||||||
logger.info('定时器数量:', this.cron.getTaskSize());
|
logger.info('定时器数量:', this.cron.getTaskSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { SysSettingsService } from '../service/sys-settings-service.js';
|
||||||
import { SysSettingsEntity } from '../entity/sys-settings.js';
|
import { SysSettingsEntity } from '../entity/sys-settings.js';
|
||||||
import { SysPublicSettings } from '../service/models.js';
|
import { SysPublicSettings } from '../service/models.js';
|
||||||
import * as _ from 'lodash-es';
|
import * as _ from 'lodash-es';
|
||||||
|
import { PipelineService } from '../../pipeline/service/pipeline-service.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
|
@ -12,6 +13,8 @@ import * as _ from 'lodash-es';
|
||||||
export class SysSettingsController extends CrudController<SysSettingsService> {
|
export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||||
@Inject()
|
@Inject()
|
||||||
service: SysSettingsService;
|
service: SysSettingsService;
|
||||||
|
@Inject()
|
||||||
|
pipelineService: PipelineService;
|
||||||
|
|
||||||
getService() {
|
getService() {
|
||||||
return this.service;
|
return this.service;
|
||||||
|
@ -73,4 +76,9 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||||
await this.service.savePublicSettings(setting);
|
await this.service.savePublicSettings(setting);
|
||||||
return this.ok({});
|
return this.ok({});
|
||||||
}
|
}
|
||||||
|
@Post('/stopOtherUserTimer', { summary: 'sys:settings:edit' })
|
||||||
|
async stopOtherUserTimer(@Body(ALL) body) {
|
||||||
|
await this.pipelineService.stopOtherUserPipeline(1);
|
||||||
|
return this.ok({});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ export class SysPublicSettings extends BaseSettings {
|
||||||
static __title__ = '系统公共设置';
|
static __title__ = '系统公共设置';
|
||||||
static __access__ = 'public';
|
static __access__ = 'public';
|
||||||
registerEnabled = false;
|
registerEnabled = false;
|
||||||
|
managerOtherUserPipeline = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SysPrivateSettings extends BaseSettings {
|
export class SysPrivateSettings extends BaseSettings {
|
||||||
|
|
Loading…
Reference in New Issue