chore: project finished

This commit is contained in:
xiaojunnuo
2026-03-03 23:31:42 +08:00
parent a853fc2026
commit 6c546b5290
17 changed files with 87 additions and 29 deletions

View File

@@ -69,10 +69,8 @@ export abstract class BaseController {
if (!projectIdStr){
projectIdStr = this.ctx.request.query["projectId"] as string;
}
if (!projectIdStr){
return null
}
if (!projectIdStr) {
//这里必须抛异常,否则可能会有权限问题
throw new Error("projectId 不能为空")
}
const userId = this.getUserId()

View File

@@ -24,6 +24,9 @@ export class AccessEntity {
@Column({ name: 'project_id', comment: '项目id' })
projectId: number;
@Column({ comment: '权限等级', length: 100 })
level: string; // user common system
@Column({
name: 'create_time',
comment: '创建时间',

View File

@@ -155,7 +155,7 @@ function createRequestFunction(service: any) {
}
Object.assign(configDefault, config);
if (projectStore.isEnterprise && !config.url.startsWith("/sys") && !config.url.startsWith("http")) {
if (!configDefault.params.projectId && projectStore.isEnterprise && !config.url.startsWith("/sys") && !config.url.startsWith("http")) {
configDefault.params.projectId = projectStore.currentProject?.id;
}
return service(configDefault);

View File

@@ -838,6 +838,7 @@ export default {
leaveFailed: "Leave project failed, please try again later",
applyJoinConfirm: "Are you sure you want to apply to join this project?",
leaveConfirm: "Are you sure you want to leave this project?",
viewDetail: "View Detail",
},
addonSelector: {
select: "Select",

View File

@@ -854,5 +854,6 @@ export default {
leaveFailed: "退出项目失败,请稍后重试",
applyJoinConfirm: "确认加入项目?",
leaveConfirm: "确认退出项目?",
viewDetail: "查看详情",
},
};

View File

@@ -10,7 +10,9 @@ import { usePermissionStore } from "/@/plugin/permission/store.permission";
import util from "/@/plugin/permission/util.permission";
import { useUserStore } from "/@/store/user";
import { useProjectStore } from "../store/project";
export const PROJECT_JOIN_PATH = "/certd/project/join";
export const PROJECT_PATH_PREFIX = "/certd/project";
export const SYS_PATH_PREFIX = "/sys";
function buildAccessedMenus(menus: any) {
if (menus == null) {
return;
@@ -131,10 +133,10 @@ function setupAccessGuard(router: Router) {
if (projectStore.isEnterprise) {
//加载我的项目
await projectStore.init();
if (!projectStore.currentProject && to.path !== PROJECT_JOIN_PATH) {
if (!projectStore.currentProject && !to.path.startsWith(PROJECT_PATH_PREFIX) && !to.path.startsWith(SYS_PATH_PREFIX)) {
//没有项目
return {
path: PROJECT_JOIN_PATH,
path: `${PROJECT_PATH_PREFIX}/join`,
replace: true,
};
}

View File

@@ -109,7 +109,10 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
search: {
show: true,
},
form: {},
form: {
show: true,
rules: [{ required: true, message: "请选择用户" }],
},
editForm: {
show: false,
},
@@ -126,6 +129,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
},
form: {
show: true,
rules: [{ required: true, message: "请选择权限" }],
},
column: {
width: 200,
@@ -140,6 +144,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
},
form: {
show: true,
rules: [{ required: true, message: "请选择状态" }],
},
column: {
width: 200,
@@ -156,6 +161,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
id: row.id,
permission: row.permission,
onSubmit: async (form: any) => {
form.userId = row.userId;
await api.ApproveJoin(form);
crudExpose.doRefresh();
},

View File

@@ -97,6 +97,10 @@ const handleBatchDelete = () => {
// 页面打开后获取列表数据
onMounted(async () => {
if (!projectId) {
message.error("您还未选择项目");
return;
}
await loadProjectDetail();
crudExpose.doRefresh();
});

View File

@@ -5,6 +5,10 @@
{{ t("certd.sysResources.projectJoin") }}
<span v-if="projectStore.projects.length === 0" class="sub">{{ t("certd.project.noProjectJoined") }}</span>
</div>
<div class="more">
<a-button v-if="userStore.isAdmin" @click="goProjectManager">{{ t("certd.project.projectManager") }}</a-button>
</div>
</template>
<div class="project-container">
<h3 class="text-lg font-medium mb-4">{{ t("certd.project.projectList") }}</h3>
@@ -13,20 +17,20 @@
<a-card :bordered="true" class="project-card">
<div class="project-card-content">
<div class="project-info">
<h3 class="text-md font-bold title">{{ project.name }}</h3>
<p class="text-gray-500 text-sm">{{ formatDate(project.createTime) }}</p>
<div class="text-md font-bold title">{{ project.name }}</div>
<div class="flex items-center justify-start">管理员 <fs-values-format :model-value="project.adminId" :dict="userDict" color="green"></fs-values-format></div>
<p class="text-gray-500 text-sm">创建时间{{ formatDate(project.createTime) }}</p>
</div>
<div class="flex-col items-center">
<div>管理员 <fs-values-format :model-value="project.adminId" :dict="userDict"></fs-values-format></div>
<div class="flex items-center mt-2">
<div v-if="project.status">
<fs-values-format :model-value="project.status" :dict="projectMemberStatusDict"></fs-values-format>
</div>
<div v-if="project.permission"><fs-values-format :model-value="project.permission" :dict="projectPermissionDict"></fs-values-format></div>
</div>
<div class="flex-col items-start">
<div v-if="project.status" class="mt-1 flex items-center justify-start">状态:<fs-values-format :model-value="project.status" :dict="projectMemberStatusDict"></fs-values-format></div>
<div v-if="project.permission" class="mt-1 flex items-center justify-start">权限:<fs-values-format :model-value="project.permission" :dict="projectPermissionDict"></fs-values-format></div>
</div>
</div>
<template #actions>
<span v-if="project.status === 'approved'" class="flex-inline items-center text-blue-500" :title="t('certd.project.viewDetail')" @click="goProjectDetail(project.id)">
<fs-icon class="fs-18 mr-2" icon="mdi:eye-outline"></fs-icon>
{{ t("certd.project.viewDetail") }}
</span>
<span v-if="!project.status || project.status === 'rejected'" class="flex-inline items-center text-blue-500" :title="t('certd.project.applyJoin')" @click="applyToJoin(project.id)">
<fs-icon class="fs-18 mr-2" icon="mdi:checkbox-marked-circle-outline"></fs-icon>
{{ t("certd.project.applyJoin") }}
@@ -51,6 +55,8 @@ import { request } from "/src/api/service";
import { useProjectStore } from "/@/store/project";
import dayjs from "dayjs";
import { useDicts } from "../dicts";
import { useRouter } from "vue-router";
import { useUserStore } from "/@/store/user";
defineOptions({
name: "ProjectJoin",
@@ -62,6 +68,17 @@ const { projectMemberStatusDict, projectPermissionDict, userDict } = useDicts();
const projects = ref<any[]>([]);
const projectStore = useProjectStore();
const userStore = useUserStore();
function goProjectManager() {
// 假设这里调用跳转到项目管理页的API
router.push(`/sys/enterprise/project`);
}
const router = useRouter();
function goProjectDetail(projectId: number) {
// 假设这里调用跳转到项目详情页的API
router.push(`/certd/project/detail?projectId=${projectId}`);
}
const getSystemProjects = async () => {
try {
@@ -147,7 +164,6 @@ async function leaveProject(projectId: number) {
.title {
font-size: 16px;
font-weight: bold;
margin-bottom: 8px;
}
}
}

View File

@@ -108,7 +108,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
search: {
show: true,
},
form: {},
form: {
rules: [{ required: true, message: "请选择用户" }],
},
editForm: {
show: false,
},
@@ -131,6 +133,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
},
form: {
show: true,
rules: [{ required: true, message: "请选择权限" }],
},
column: {
width: 200,
@@ -145,6 +148,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
},
form: {
show: true,
rules: [{ required: true, message: "请选择状态" }],
},
column: {
width: 200,

View File

@@ -5,8 +5,8 @@
<h2 class="intro-title text-xl font-bold">{{ title || "管理模式介绍" }}</h2>
<div class="mt-8 image-block">
<div class="flex gap-8">
<div class="intro-desc flex-1">SaaS模式每个用户管理自己的流水线和授权资源独立使用</div>
<div class="intro-desc flex-1">企业模式企业内部员工使用通过项目合作管理流水线证书和授权资源</div>
<div class="intro-desc flex-1">SaaS模式每个用户管理自己的流水线和授权资源每个用户独立使用</div>
<div class="intro-desc flex-1">企业模式通过项目合作管理流水线证书和授权资源所有用户视为企业内部员工</div>
</div>
<div class="image-intro">
<img :src="src" alt="" />

View File

@@ -6,8 +6,10 @@
<fs-dict-radio v-model:value="formState.public.adminMode" :disabled="!settingsStore.isPlus" :dict="adminModeDict" />
<vip-button class="ml-5" mode="button"></vip-button>
</div>
<div class="helper">建议在开始使用时选择合适的模式之后就不要随意切换了</div>
<div><a @click="adminModeIntroOpen = true"> 管理模式介绍</a></div>
<div class="helper">SaaS模式每个用户管理自己的流水线和授权资源独立使用</div>
<div class="helper">企业模式通过项目合作管理流水线证书和授权资源所有用户视为企业内部员工</div>
<div class="helper text-red-500">建议在开始使用时固定一个合适的模式之后就不要随意切换了</div>
<div><a @click="adminModeIntroOpen = true"> 更多管理模式介绍</a></div>
</a-form-item>
<a-form-item label=" " :colon="false" :wrapper-col="{ span: 8 }">

View File

@@ -1,5 +1,5 @@
import { AccessService } from "@certd/lib-server";
import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core";
import { AccessService, Constants } from "@certd/lib-server";
import { AccessController } from "../../user/pipeline/access-controller.js";
/**
@@ -15,6 +15,12 @@ export class SysAccessController extends AccessController {
return this.service2;
}
async getProjectUserId(permission:string){
return {
projectId:null,userId:0
}
}
getUserId() {
// checkComm();
return 0;
@@ -54,7 +60,7 @@ export class SysAccessController extends AccessController {
return await super.define(type);
}
@Post('/getSecretPlain', { summary: Constants.per.authOnly })
@Post('/getSecretPlain', { summary: 'sys:settings:view' })
async getSecretPlain(@Body(ALL) body: { id: number; key: string }) {
const value = await this.service.getById(body.id, 0);
return this.ok(value[body.key]);
@@ -69,4 +75,9 @@ export class SysAccessController extends AccessController {
async simpleInfo(@Query('id') id: number) {
return await super.simpleInfo(id);
}
@Post('/getDictByIds', { summary: 'sys:settings:view' })
async getDictByIds(@Body('ids') ids: number[]) {
return await super.getDictByIds(ids);
}
}

View File

@@ -12,6 +12,11 @@ export class SysAddonController extends AddonController {
return this.service2;
}
async getProjectUserId(permission:string){
return {
projectId:null,userId:0
}
}
getUserId() {
// checkComm();
return 0;

View File

@@ -60,10 +60,12 @@ export class SysProjectMemberController extends CrudController<ProjectMemberEnti
userId: this.getUserId(),
projectId: projectId,
});
return super.update({
const res =await this.service.update({
id: bean.id,
permission: bean.permission,
status: bean.status,
});
return this.ok(res);
}
@Post("/info", { summary: "sys:settings:view" })

View File

@@ -64,10 +64,13 @@ export class ProjectMemberController extends CrudController<ProjectMemberEntity>
userId: this.getUserId(),
projectId: projectId,
});
return super.update({
const res = await this.service.update({
id: bean.id,
permission: bean.permission,
status: bean.status,
});
return this.ok(res);
}
@Post("/info", { summary: Constants.per.authOnly })

View File

@@ -111,7 +111,7 @@ export class AccessController extends CrudController<AccessService> {
@Post('/simpleInfo', { summary: Constants.per.authOnly })
async simpleInfo(@Query('id') id: number) {
// await this.authService.checkUserIdButAllowAdmin(this.ctx, this.service, id);
await this.checkOwner(this.getService(), id, "read",true);
// await this.checkOwner(this.getService(), id, "read",true);
const res = await this.service.getSimpleInfo(id);
return this.ok(res);
}