chore: project controller

This commit is contained in:
xiaojunnuo
2026-02-11 00:07:29 +08:00
parent 784bcb0aa5
commit 1e416b9f8a
33 changed files with 773 additions and 53 deletions

View File

@@ -7,7 +7,7 @@
],
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"editor.tabSize": 2,
"explorer.autoReveal": false,

View File

@@ -53,7 +53,7 @@
"prepublishOnly": "npm run build-docs",
"test": "mocha -t 60000 \"test/setup.js\" \"test/**/*.spec.js\"",
"pub": "npm publish",
"compile": "tsc --skipLibCheck --watch"
"compile": "echo '1'"
},
"repository": {
"type": "git",

View File

@@ -1,11 +1,17 @@
import { Inject } from '@midwayjs/core';
import { ApplicationContext, Inject } from '@midwayjs/core';
import type {IMidwayContainer} from '@midwayjs/core';
import * as koa from '@midwayjs/koa';
import { Constants } from './constants.js';
import { isEnterprise } from './mode.js';
export abstract class BaseController {
@Inject()
ctx: koa.Context;
@ApplicationContext()
applicationContext: IMidwayContainer;
/**
* 成功返回
* @param data 返回数据
@@ -55,4 +61,36 @@ export abstract class BaseController {
}
}
getProjectId(permission:string) {
if (!isEnterprise()) {
return null
}
const projectIdStr = this.ctx.headers["project-id"] as string;
if (!projectIdStr) {
throw new Error("projectId 不能为空")
}
const userId = this.getUserId()
const projectId = parseInt(projectIdStr)
this.checkProjectPermission(userId, projectId,permission)
return projectId;
}
getProjectUserId(permission:string){
let userId = this.getUserId()
const projectId = this.getProjectId(permission)
if(projectId){
userId = 0
}
return {
projectId,userId
}
}
async checkProjectPermission(userId: number, projectId: number,permission:string) {
const projectService:any = await this.applicationContext.getAsync("projectService");
await projectService.checkPermission({userId,projectId,permission})
}
}

View File

@@ -5,3 +5,4 @@ export * from './enum-item.js';
export * from './exception/index.js';
export * from './result.js';
export * from './base-service.js';
export * from "./mode.js"

View File

@@ -0,0 +1,12 @@
let adminMode = "saas"
export function setAdminMode(mode:string = "saas"){
adminMode = mode
}
export function getAdminMode(){
return adminMode
}
export function isEnterprise(){
return adminMode === "enterprise"
}

View File

@@ -7,9 +7,9 @@ import { BaseSettings, SysInstallInfo, SysPrivateSettings, SysPublicSettings, Sy
import { getAllSslProviderDomains, setSslProviderReverseProxies } from '@certd/acme-client';
import { cache, logger, mergeUtils, setGlobalProxy } from '@certd/basic';
import * as dns from 'node:dns';
import { BaseService } from '../../../basic/index.js';
import { BaseService, setAdminMode } from '../../../basic/index.js';
import { executorQueue } from '../../basic/service/executor-queue.js';
const {merge} = mergeUtils;
const { merge } = mergeUtils;
/**
* 设置
*/
@@ -117,6 +117,8 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
async savePublicSettings(bean: SysPublicSettings) {
await this.saveSetting(bean);
//让设置生效
await this.reloadPublicSettings();
}
async getPrivateSettings(): Promise<SysPrivateSettings> {
@@ -137,23 +139,33 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
await this.reloadPrivateSettings();
}
async reloadSettings() {
await this.reloadPrivateSettings()
await this.reloadPublicSettings()
}
async reloadPublicSettings() {
const publicSetting = await this.getPublicSettings()
setAdminMode(publicSetting.adminMode)
}
async reloadPrivateSettings() {
const bean = await this.getPrivateSettings();
const privateSetting = await this.getPrivateSettings();
const opts = {
httpProxy: bean.httpProxy,
httpsProxy: bean.httpsProxy,
httpProxy: privateSetting.httpProxy,
httpsProxy: privateSetting.httpsProxy,
};
setGlobalProxy(opts);
if (bean.dnsResultOrder) {
dns.setDefaultResultOrder(bean.dnsResultOrder as any);
if (privateSetting.dnsResultOrder) {
dns.setDefaultResultOrder(privateSetting.dnsResultOrder as any);
}
if (bean.pipelineMaxRunningCount){
executorQueue.setMaxRunningCount(bean.pipelineMaxRunningCount);
if (privateSetting.pipelineMaxRunningCount) {
executorQueue.setMaxRunningCount(privateSetting.pipelineMaxRunningCount);
}
setSslProviderReverseProxies(bean.reverseProxies);
setSslProviderReverseProxies(privateSetting.reverseProxies);
}
async updateByKey(key: string, setting: any) {

View File

@@ -3,6 +3,7 @@ import { get } from "lodash-es";
import { errorLog, errorCreate } from "./tools";
import { env } from "/src/utils/util.env";
import { useUserStore } from "/@/store/user";
import { useProjectStore } from "../store/project";
export class CodeError extends Error {
code: number;
@@ -138,11 +139,17 @@ function createRequestFunction(service: any) {
const configDefault = {
headers: {
"Content-Type": get(config, "headers.Content-Type", "application/json"),
},
} as any,
timeout: 30000,
baseURL: env.API,
data: {},
};
const projectStore = useProjectStore();
if (projectStore.isEnterprise && !config.url.startsWith("/sys")) {
configDefault.headers["project-id"] = projectStore.currentProjectId;
}
const userStore = useUserStore();
const token = userStore.getToken;
if (token != null) {

View File

@@ -10,7 +10,6 @@
:options="optionsRef"
:value="value"
v-bind="attrs"
:open="openProp"
@click="onClick"
@update:value="emit('update:value', $event)"
>

View File

@@ -7,9 +7,10 @@
</a-menu-item>
</a-menu>
</template>
<div class="rounded pl-2 pr-2 px-2 py-1 flex-center flex pointer bg-accent h-10 button-text">
<div class="rounded pl-3 pr-3 px-2 py-1 flex-center flex pointer items-center bg-accent h-10 button-text">
<fs-icon icon="ion:apps" class="mr-1"></fs-icon>
{{ projectStore.currentProject?.name || "..." }}
<DownOutlined class="ml-1" />
<fs-icon icon="ion:chevron-down-outline" class="ml-1"></fs-icon>
</div>
</a-dropdown>
</template>

View File

@@ -214,6 +214,8 @@ export default {
enterpriseSetting: "Enterprise Settings",
projectManager: "Project Management",
projectUserManager: "Project User Management",
myProjectManager: "My Projects",
myProjectDetail: "Project Detail",
},
certificateRepo: {
title: "Certificate Repository",

View File

@@ -220,6 +220,8 @@ export default {
projectManager: "项目管理",
projectDetail: "项目详情",
enterpriseSetting: "企业设置",
myProjectManager: "我的项目",
myProjectDetail: "项目详情",
},
certificateRepo: {
title: "证书仓库",

View File

@@ -14,6 +14,30 @@ export const certdResources = [
order: 0,
},
children: [
{
title: "certd.sysResources.myProjectManager",
name: "MyProjectManager",
path: "/certd/project",
component: "/certd/project/index.vue",
meta: {
show: true,
icon: "ion:apps",
permission: "sys:settings:edit",
keepAlive: true,
},
},
{
title: "certd.sysResources.myProjectDetail",
name: "MyProjectDetail",
path: "/certd/project/detail",
component: "/certd/project/detail/index.vue",
meta: {
isMenu: false,
show: true,
icon: "ion:apps",
permission: "sys:settings:edit",
},
},
{
title: "certd.pipeline",
name: "PipelineManager",

View File

@@ -76,6 +76,7 @@ export const useProjectStore = defineStore("app.project", () => {
projects,
myProjects,
currentProject,
currentProjectId,
isEnterprise,
getSearchForm,
loadMyProjects,

View File

@@ -4,7 +4,7 @@ import { getCommonColumnDefine } from "/@/views/certd/access/common";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { useI18n } from "/src/locales";
import { useProjectStore } from "/@/store/project";
import { projectDict } from "../../../dicts";
import { myProjectDict } from "../../../dicts";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { t } = useI18n();
@@ -150,7 +150,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
projectId: {
title: t("certd.fields.projectName"),
type: "dict-select",
dict: projectDict,
dict: myProjectDict,
},
},
},

View File

@@ -1,10 +1,10 @@
// @ts-ignore
import { useI18n } from "/src/locales";
import { ref } from "vue";
import { getCommonColumnDefine } from "/@/views/certd/access/common";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { projectDict } from "../dicts";
import { ref } from "vue";
import { myProjectDict } from "../dicts";
import { useProjectStore } from "/@/store/project";
import { getCommonColumnDefine } from "/@/views/certd/access/common";
import { useI18n } from "/src/locales";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { t } = useI18n();
@@ -126,7 +126,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
projectId: {
title: t("certd.fields.projectName"),
type: "dict-select",
dict: projectDict,
dict: myProjectDict,
},
},
},

View File

@@ -17,6 +17,16 @@ export const projectPermissionDict = dict({
],
});
export const projectDict = dict({
url: "/sys/enterprise/project/list",
export const myProjectDict = dict({
url: "/enterprise/project/list",
});
export const userDict = dict({
url: "/sys/authority/user/getSimpleUsers",
value: "id",
onReady: ({ dict }) => {
for (const item of dict.data) {
item.label = item.nickName || item.username || item.phoneCode + item.mobile;
}
},
});

View File

@@ -6,7 +6,7 @@ import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, Edi
import { useUserStore } from "/@/store/user";
import { useSettingStore } from "/@/store/settings";
import { statusUtil } from "/@/views/certd/pipeline/pipeline/utils/util.status";
import { projectDict } from "../dicts";
import { myProjectDict } from "../dicts";
import { useProjectStore } from "/@/store/project";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
@@ -205,7 +205,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
projectId: {
title: t("certd.fields.projectName"),
type: "dict-select",
dict: projectDict,
dict: myProjectDict,
},
updateTime: {
title: t("certd.fields.updateTime"),

View File

@@ -11,7 +11,7 @@ import CertView from "/@/views/certd/pipeline/cert-view.vue";
import { useCertUpload } from "/@/views/certd/pipeline/cert-upload/use";
import { useSettingStore } from "/@/store/settings";
import { useProjectStore } from "/@/store/project";
import { projectDict } from "../../dicts";
import { myProjectDict } from "../../dicts";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { t } = useI18n();
@@ -350,7 +350,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
projectId: {
title: t("certd.fields.projectName"),
type: "dict-select",
dict: projectDict,
dict: myProjectDict,
},
},
},

View File

@@ -14,7 +14,7 @@ import { ref } from "vue";
import GroupSelector from "../../basic/group/group-selector.vue";
import { createGroupDictRef } from "../../basic/group/api";
import { useProjectStore } from "/@/store/project";
import { projectDict } from "../../dicts";
import { myProjectDict } from "../../dicts";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { t } = useI18n();
const api = siteInfoApi;
@@ -812,7 +812,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
projectId: {
title: t("certd.fields.projectName"),
type: "dict-select",
dict: projectDict,
dict: myProjectDict,
},
},
},

View File

@@ -6,7 +6,7 @@ import { Modal } from "ant-design-vue";
import { mitter } from "/@/utils/util.mitt";
import { useI18n } from "/src/locales";
import { useProjectStore } from "/@/store/project";
import { projectDict } from "../dicts";
import { myProjectDict } from "../dicts";
export function notificationProvide(api: any) {
provide("notificationApi", api);
@@ -254,7 +254,7 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
projectId: {
title: t("certd.fields.projectName"),
type: "dict-select",
dict: projectDict,
dict: myProjectDict,
},
};
}

View File

@@ -4,7 +4,7 @@ import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, Edi
import { OPEN_API_DOC, openkeyApi } from "./api";
import { useModal } from "/@/use/use-modal";
import { useProjectStore } from "/@/store/project";
import { projectDict } from "../../dicts";
import { myProjectDict } from "../../dicts";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { t } = useI18n();
@@ -172,7 +172,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
projectId: {
title: t("certd.fields.projectName"),
type: "dict-select",
dict: projectDict,
dict: myProjectDict,
},
createTime: {
title: t("certd.fields.createTime"),

View File

@@ -14,7 +14,7 @@ import GroupSelector from "/@/views/certd/pipeline/group/group-selector.vue";
import { statusUtil } from "/@/views/certd/pipeline/pipeline/utils/util.status";
import { useCertViewer } from "/@/views/certd/pipeline/use";
import { useI18n } from "/src/locales";
import { projectDict } from "../dicts";
import { myProjectDict } from "../dicts";
import { useProjectStore } from "/@/store/project";
export default function ({ crudExpose, context: { selectedRowKeys, openCertApplyDialog } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
@@ -445,6 +445,7 @@ export default function ({ crudExpose, context: { selectedRowKeys, openCertApply
type: "dict-select",
search: {
show: true,
col: { span: 2 },
},
dict: dict({
data: statusUtil.getOptions(),
@@ -537,6 +538,7 @@ export default function ({ crudExpose, context: { selectedRowKeys, openCertApply
type: "dict-select",
search: {
show: true,
col: { span: 2 },
},
dict: dict({
data: [
@@ -637,7 +639,7 @@ export default function ({ crudExpose, context: { selectedRowKeys, openCertApply
projectId: {
title: t("certd.fields.projectName"),
type: "dict-select",
dict: projectDict,
dict: myProjectDict,
},
updateTime: {
title: t("certd.fields.updateTime"),

View File

@@ -2,7 +2,7 @@ import { useI18n } from "/src/locales";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { pipelineGroupApi } from "./api";
import { useProjectStore } from "/@/store/project";
import { projectDict } from "../../dicts";
import { myProjectDict } from "../../dicts";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { t } = useI18n();
@@ -139,7 +139,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
projectId: {
title: t("certd.fields.projectName"),
type: "dict-select",
dict: projectDict,
dict: myProjectDict,
},
},
},

View File

@@ -7,7 +7,7 @@ import * as pipelineApi from "../api";
import { useTemplate } from "/@/views/certd/pipeline/template/use";
import { useI18n } from "/@/locales";
import { useProjectStore } from "/@/store/project";
import { projectDict } from "../../dicts";
import { myProjectDict } from "../../dicts";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const api = templateApi;
const { t } = useI18n();
@@ -244,7 +244,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
projectId: {
title: t("certd.fields.projectName"),
type: "dict-select",
dict: projectDict,
dict: myProjectDict,
},
},
},

View File

@@ -0,0 +1,75 @@
import { request } from "/src/api/service";
const apiPrefix = "/enterprise/project";
export async function GetList(query: any) {
return await request({
url: apiPrefix + "/list",
method: "post",
data: query,
});
}
export async function GetPage(query: any) {
return await request({
url: apiPrefix + "/page",
method: "post",
data: query,
});
}
export async function AddObj(obj: any) {
return await request({
url: apiPrefix + "/add",
method: "post",
data: obj,
});
}
export async function UpdateObj(obj: any) {
return await request({
url: apiPrefix + "/update",
method: "post",
data: obj,
});
}
export async function DelObj(id: any) {
return await request({
url: apiPrefix + "/delete",
method: "post",
params: { id },
});
}
export async function GetObj(id: any) {
return await request({
url: apiPrefix + "/info",
method: "post",
params: { id },
});
}
export async function GetDetail(id: any) {
return await request({
url: apiPrefix + "/detail",
method: "post",
params: { id },
});
}
export async function DeleteBatch(ids: any[]) {
return await request({
url: apiPrefix + "/deleteByIds",
method: "post",
data: { ids },
});
}
export async function SetDisabled(id: any, disabled: boolean) {
return await request({
url: apiPrefix + "/setDisabled",
method: "post",
data: { id, disabled },
});
}

View File

@@ -0,0 +1,165 @@
import * as api from "./api";
import { useI18n } from "/src/locales";
import { computed, Ref, ref } from "vue";
import { useRouter } from "vue-router";
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes, utils } from "@fast-crud/fast-crud";
import { useUserStore } from "/@/store/user";
import { useSettingStore } from "/@/store/settings";
import { Modal } from "ant-design-vue";
import { userDict } from "../dicts";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const router = useRouter();
const { t } = useI18n();
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
const list = await api.GetList(query);
return {
records: list,
total: list.length,
offset: 0,
limit: 999,
};
};
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) => {
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,
},
rowHandle: {
minWidth: 200,
fixed: "right",
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
column: {
width: 100,
},
form: {
show: false,
},
},
name: {
title: t("certd.ent.projectName"),
type: "link",
search: {
show: true,
},
form: {
component: {},
rules: [{ required: true, message: t("certd.requiredField") }],
},
column: {
width: 200,
cellRender({ row }) {
return <router-link to={{ path: `/certd/project/detail`, query: { projectId: row.id } }}>{row.name}</router-link>;
},
},
},
disabled: {
title: t("certd.disabled"),
type: "dict-switch",
dict: dict({
data: [
{ label: t("certd.enabled"), value: false, color: "success" },
{ label: t("certd.disabledLabel"), value: true, color: "error" },
],
}),
form: {
value: false,
},
column: {
width: 100,
component: {
title: t("certd.clickToToggle"),
on: {
async click({ value, row }) {
Modal.confirm({
title: t("certd.prompt"),
content: t("certd.confirmToggleStatus", { action: !value ? t("certd.disable") : t("certd.enable") }),
onOk: async () => {
await api.SetDisabled(row.id, !value);
await crudExpose.doRefresh();
},
});
},
},
},
},
},
adminId: {
title: t("certd.fields.adminId"),
type: "dict-select",
dict: userDict,
column: {
width: 160,
},
},
createTime: {
title: t("certd.createTime"),
type: "datetime",
form: {
show: false,
},
column: {
sorter: true,
width: 160,
align: "center",
},
},
updateTime: {
title: t("certd.updateTime"),
type: "datetime",
form: {
show: false,
},
column: {
show: true,
width: 160,
},
},
},
},
};
}

View File

@@ -0,0 +1,67 @@
import { request } from "/src/api/service";
const apiPrefix = "/enterprise/myProjectMember";
const userApiPrefix = "/sys/authority/user";
export async function GetList(query: any) {
return await request({
url: apiPrefix + "/page",
method: "post",
data: query,
});
}
export async function AddObj(obj: any) {
return await request({
url: apiPrefix + "/add",
method: "post",
data: obj,
});
}
export async function UpdateObj(obj: any) {
return await request({
url: apiPrefix + "/update",
method: "post",
data: obj,
});
}
export async function DelObj(id: any) {
return await request({
url: apiPrefix + "/delete",
method: "post",
params: { id },
});
}
export async function GetObj(id: any) {
return await request({
url: apiPrefix + "/info",
method: "post",
params: { id },
});
}
export async function GetDetail(id: any) {
return await request({
url: apiPrefix + "/detail",
method: "post",
params: { id },
});
}
export async function DeleteBatch(ids: any[]) {
return await request({
url: apiPrefix + "/deleteByIds",
method: "post",
data: { ids },
});
}
export async function GetUserSimpleByIds(query: any) {
return await request({
url: userApiPrefix + "/getSimpleByIds",
method: "post",
data: query,
});
}

View File

@@ -0,0 +1,162 @@
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { Modal } from "ant-design-vue";
import { Ref, ref } from "vue";
import { useRouter } from "vue-router";
import * as api from "./api";
import { useSettingStore } from "/@/store/settings";
import { useUserStore } from "/@/store/user";
import { useI18n } from "/src/locales";
import { userDict } from "../../dicts";
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) => {
const res = await api.AddObj(form);
return res;
};
const projectId = context.projectId;
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,
},
rowHandle: {
minWidth: 200,
fixed: "right",
},
search: {
initialForm: {
projectId,
},
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
column: {
width: 100,
},
form: {
show: false,
},
},
projectId: {
title: "项目ID",
type: "text",
search: {
show: false,
},
form: {
value: projectId,
show: false,
},
editForm: {
show: false,
},
column: {
width: 200,
show: false,
},
},
userId: {
title: "用户",
type: "dict-select",
dict: userDict,
search: {
show: true,
},
form: {},
editForm: {
show: false,
},
column: {
width: 200,
},
},
permission: {
title: t("certd.ent.projectPermission"),
type: "dict-select",
dict: dict({
data: [
{ label: t("certd.ent.permission.read"), value: "read", color: "cyan" },
{ label: t("certd.ent.permission.write"), value: "write", color: "blue" },
{ label: t("certd.ent.permission.admin"), value: "admin", color: "green" },
],
}),
search: {
show: true,
},
form: {
show: true,
},
column: {
width: 200,
},
},
createTime: {
title: t("certd.createTime"),
type: "datetime",
form: {
show: false,
},
column: {
sorter: true,
width: 160,
align: "center",
},
},
updateTime: {
title: t("certd.updateTime"),
type: "datetime",
form: {
show: false,
},
column: {
show: true,
width: 160,
},
},
},
},
};
}

View File

@@ -0,0 +1,71 @@
<template>
<fs-page class="page-project-detail">
<template #header>
<div class="title">
{{ t("certd.ent.projectDetailManager") }}
<span class="sub">
{{ t("certd.ent.projectDetailDescription") }}
</span>
</div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding">
<template #pagination-left>
<a-tooltip :title="t('certd.batchDelete')">
<fs-button icon="DeleteOutlined" @click="handleBatchDelete"></fs-button>
</a-tooltip>
</template>
</fs-crud>
</fs-page>
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales";
import { useRoute } from "vue-router";
const { t } = useI18n();
defineOptions({
name: "ProjectDetail",
});
const route = useRoute();
const projectIdStr = route.query.projectId as string;
const projectId = Number(projectIdStr);
const context: any = {
projectId,
};
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
const selectedRowKeys = context.selectedRowKeys;
const handleBatchDelete = () => {
if (selectedRowKeys.value?.length > 0) {
Modal.confirm({
title: t("certd.confirmTitle"),
content: t("certd.confirmDeleteBatch", { count: selectedRowKeys.value.length }),
async onOk() {
await DeleteBatch(selectedRowKeys.value);
message.info(t("certd.deleteSuccess"));
crudExpose.doRefresh();
selectedRowKeys.value = [];
},
});
} else {
message.error(t("certd.selectRecordsFirst"));
}
};
// 页面打开后获取列表数据
onMounted(() => {
crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh();
});
</script>
<style lang="less"></style>

View File

@@ -0,0 +1,61 @@
<template>
<fs-page class="page-cert">
<template #header>
<div class="title">
{{ t("certd.sysResources.myProjectManager") }}
</div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding">
<!-- <div v-if="crudBinding.data" class="project-list">
<div v-for="item of crudBinding.data" :key="item.id" class="project-item">
<a-card style="width: 300px">
<p>{{ item.name }}</p>
</a-card>
</div>
</div> -->
</fs-crud>
</fs-page>
</template>
<script lang="ts" setup>
import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api";
import { useI18n } from "/src/locales";
const { t } = useI18n();
defineOptions({
name: "MyProjectManager",
});
const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions });
const selectedRowKeys = context.selectedRowKeys;
const handleBatchDelete = () => {
if (selectedRowKeys.value?.length > 0) {
Modal.confirm({
title: t("certd.confirmTitle"),
content: t("certd.confirmDeleteBatch", { count: selectedRowKeys.value.length }),
async onOk() {
await DeleteBatch(selectedRowKeys.value);
message.info(t("certd.deleteSuccess"));
crudExpose.doRefresh();
selectedRowKeys.value = [];
},
});
} else {
message.error(t("certd.selectRecordsFirst"));
}
};
// 页面打开后获取列表数据
onMounted(() => {
crudExpose.doRefresh();
});
onActivated(async () => {
await crudExpose.doRefresh();
});
</script>
<style lang="less"></style>

View File

@@ -1,11 +1,11 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { Constants, CrudController, SysSettingsService } from '@certd/lib-server';
import { PipelineService } from '../../../modules/pipeline/service/pipeline-service.js';
import { isPlus } from '@certd/plus-core';
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { SiteInfoService } from '../../../modules/monitor/index.js';
import { PipelineEntity } from '../../../modules/pipeline/entity/pipeline.js';
import { HistoryService } from '../../../modules/pipeline/service/history-service.js';
import { PipelineService } from '../../../modules/pipeline/service/pipeline-service.js';
import { AuthService } from '../../../modules/sys/authority/service/auth-service.js';
import { SiteInfoService } from '../../../modules/monitor/index.js';
import { isPlus } from '@certd/plus-core';
/**
* 证书
@@ -25,6 +25,7 @@ export class PipelineController extends CrudController<PipelineService> {
@Inject()
siteInfoService: SiteInfoService;
getService() {
return this.service;
}
@@ -34,6 +35,8 @@ export class PipelineController extends CrudController<PipelineService> {
const isAdmin = await this.authService.isAdmin(this.ctx);
const publicSettings = await this.sysSettingsService.getPublicSettings();
const {projectId,userId} = this.getProjectUserId("read")
body.query.projectId = projectId
let onlyOther = false
if (isAdmin) {
if (publicSettings.managerOtherUserPipeline) {
@@ -44,10 +47,10 @@ export class PipelineController extends CrudController<PipelineService> {
delete body.query.userId;
}
} else {
body.query.userId = this.getUserId();
body.query.userId = userId;
}
} else {
body.query.userId = this.getUserId();
body.query.userId = userId;
}
const title = body.query.title;
@@ -76,14 +79,17 @@ export class PipelineController extends CrudController<PipelineService> {
@Post('/getSimpleByIds', { summary: Constants.per.authOnly })
async getSimpleById(@Body(ALL) body) {
const ret = await this.getService().getSimplePipelines(body.ids, this.getUserId());
const {projectId,userId} = this.getProjectUserId("read")
const ret = await this.getService().getSimplePipelines(body.ids, userId,projectId);
return this.ok(ret);
}
@Post('/add', { summary: Constants.per.authOnly })
async add(@Body(ALL) bean: PipelineEntity) {
bean.userId = this.getUserId();
const {projectId,userId} = this.getProjectUserId("write")
bean.userId = userId
bean.projectId = projectId
return super.add(bean);
}

View File

@@ -51,7 +51,8 @@ export class AutoAInitSite {
//加载一次密钥
await this.sysSettingsService.getSecret();
await this.sysSettingsService.reloadPrivateSettings();
//加载设置
await this.sysSettingsService.reloadSettings();
// 授权许可
try {

View File

@@ -993,7 +993,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
return await this.repository.count({ where: { userId } });
}
async getSimplePipelines(pipelineIds: number[], userId?: number) {
async getSimplePipelines(pipelineIds: number[], userId?: number,projectId?:number) {
return await this.repository.find({
select: {
id: true,
@@ -1001,7 +1001,8 @@ export class PipelineService extends BaseService<PipelineEntity> {
},
where: {
id: In(pipelineIds),
userId
userId,
projectId
}
});
}