mirror of
https://github.com/hpd840321/craftlabs-authorization-sdk.git
synced 2026-06-09 10:00:30 +08:00
feat(i7): async webhook delivery queue, OPS RBAC, UI role routing; docs and runbook
- Architect: I7_DESIGN.md, I7_IMPLEMENTATION_REVIEW.md; parallel index + track B - Backend: @EnableMethodSecurity; OPS login; CallbackInbox PreAuthorize; IntegrationCatalog triple role - Webhook: V2 webhook_platform_delivery; planner + scheduler + single-shot forwarder; tests - Frontend: Pinia hasAnyRole; MainLayout/HomeView/router for OPS vs dev - Runbook §10.5 delivery config Made-with: Cursor
This commit is contained in:
@@ -6,28 +6,28 @@
|
||||
<el-menu-item index="/">
|
||||
<span>首页</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/customers">
|
||||
<el-menu-item v-if="auth.hasAnyRole(['SYS_ADMIN', 'DEVELOPER'])" index="/customers">
|
||||
<span>客户管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/projects">
|
||||
<el-menu-item v-if="auth.hasAnyRole(['SYS_ADMIN', 'DEVELOPER'])" index="/projects">
|
||||
<span>项目管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/contracts">
|
||||
<el-menu-item v-if="auth.hasAnyRole(['SYS_ADMIN', 'DEVELOPER'])" index="/contracts">
|
||||
<span>合同管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/deliveries">
|
||||
<el-menu-item v-if="auth.hasAnyRole(['SYS_ADMIN', 'DEVELOPER'])" index="/deliveries">
|
||||
<span>交付管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/licenses/sn">
|
||||
<el-menu-item v-if="auth.hasAnyRole(['SYS_ADMIN', 'DEVELOPER'])" index="/licenses/sn">
|
||||
<span>许可 SN</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/callbacks">
|
||||
<el-menu-item v-if="auth.hasAnyRole(['SYS_ADMIN', 'OPS'])" index="/callbacks">
|
||||
<span>Callback 收件箱</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/integration/environments">
|
||||
<el-menu-item v-if="auth.hasAnyRole(['SYS_ADMIN', 'DEVELOPER', 'OPS'])" index="/integration/environments">
|
||||
<span>集成环境</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/integration/product-lines">
|
||||
<el-menu-item v-if="auth.hasAnyRole(['SYS_ADMIN', 'DEVELOPER', 'OPS'])" index="/integration/product-lines">
|
||||
<span>产品线</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
|
||||
@@ -12,7 +12,7 @@ const routes = [
|
||||
path: "",
|
||||
name: "home",
|
||||
component: () => import("../views/HomeView.vue"),
|
||||
meta: { roles: ["SYS_ADMIN", "DEVELOPER"] },
|
||||
meta: { roles: ["SYS_ADMIN", "DEVELOPER", "OPS"] },
|
||||
},
|
||||
{
|
||||
path: "customers",
|
||||
@@ -66,25 +66,25 @@ const routes = [
|
||||
path: "integration/environments",
|
||||
name: "integration-environments",
|
||||
component: () => import("../views/IntegrationEnvironmentsView.vue"),
|
||||
meta: { roles: ["SYS_ADMIN", "DEVELOPER"], title: "集成环境" },
|
||||
meta: { roles: ["SYS_ADMIN", "DEVELOPER", "OPS"], title: "集成环境" },
|
||||
},
|
||||
{
|
||||
path: "integration/product-lines",
|
||||
name: "integration-product-lines",
|
||||
component: () => import("../views/IntegrationProductLinesView.vue"),
|
||||
meta: { roles: ["SYS_ADMIN", "DEVELOPER"], title: "产品线" },
|
||||
meta: { roles: ["SYS_ADMIN", "DEVELOPER", "OPS"], title: "产品线" },
|
||||
},
|
||||
{
|
||||
path: "callbacks/:id",
|
||||
name: "callback-inbox-detail",
|
||||
component: () => import("../views/CallbackInboxDetailView.vue"),
|
||||
meta: { roles: ["SYS_ADMIN", "DEVELOPER"], title: "Callback 详情" },
|
||||
meta: { roles: ["SYS_ADMIN", "OPS"], title: "Callback 详情" },
|
||||
},
|
||||
{
|
||||
path: "callbacks",
|
||||
name: "callback-inbox",
|
||||
component: () => import("../views/CallbackInboxView.vue"),
|
||||
meta: { roles: ["SYS_ADMIN", "DEVELOPER"], title: "Callback 收件箱" },
|
||||
meta: { roles: ["SYS_ADMIN", "OPS"], title: "Callback 收件箱" },
|
||||
},
|
||||
{
|
||||
path: "contracts/new",
|
||||
|
||||
@@ -9,6 +9,15 @@ export const useAuthStore = defineStore("auth", {
|
||||
displayName: "",
|
||||
roles: [],
|
||||
}),
|
||||
getters: {
|
||||
hasAnyRole: (state) => {
|
||||
return (roleList) => {
|
||||
const need = roleList || [];
|
||||
const have = state.roles || [];
|
||||
return need.some((r) => have.includes(r));
|
||||
};
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async login(username, password) {
|
||||
const { data } = await axios.post("/api/v1/auth/login", { username, password });
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
<div class="home">
|
||||
<el-card class="block">
|
||||
<el-alert
|
||||
title="交付平台(I6 UAT):以下为已实现模块的快速入口;登录态为 JWT Bearer"
|
||||
title="交付平台(I7):按角色展示入口;Callback 仅 OPS / SYS_ADMIN"
|
||||
type="info"
|
||||
show-icon
|
||||
:closable="false"
|
||||
/>
|
||||
<p class="meta">用户:{{ auth.displayName }},角色:{{ auth.roles.join(", ") || "—" }}</p>
|
||||
<div class="quick-links" aria-label="模块导航">
|
||||
<router-link v-for="l in moduleLinks" :key="l.to" class="ql" :to="l.to">
|
||||
<router-link v-for="l in visibleModuleLinks" :key="l.to" class="ql" :to="l.to">
|
||||
{{ l.label }}
|
||||
</router-link>
|
||||
</div>
|
||||
@@ -23,7 +23,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { ref, onMounted, computed } from "vue";
|
||||
import axios from "axios";
|
||||
import { useAuthStore } from "../stores/auth";
|
||||
|
||||
@@ -31,18 +31,20 @@ const auth = useAuthStore();
|
||||
const pingBody = ref("");
|
||||
const pingLoading = ref(false);
|
||||
|
||||
/** I6:全链路导航锚点,与 MainLayout 菜单一致 */
|
||||
const moduleLinks = [
|
||||
{ to: "/customers", label: "客户" },
|
||||
{ to: "/projects", label: "项目" },
|
||||
{ to: "/contracts", label: "合同" },
|
||||
{ to: "/deliveries", label: "交付" },
|
||||
{ to: "/licenses/sn", label: "许可 SN" },
|
||||
{ to: "/callbacks", label: "Callback 收件箱" },
|
||||
{ to: "/integration/environments", label: "集成环境" },
|
||||
{ to: "/integration/product-lines", label: "产品线" },
|
||||
/** I7:与 MainLayout / 路由 meta 一致 */
|
||||
const allModuleLinks = [
|
||||
{ to: "/customers", label: "客户", roles: ["SYS_ADMIN", "DEVELOPER"] },
|
||||
{ to: "/projects", label: "项目", roles: ["SYS_ADMIN", "DEVELOPER"] },
|
||||
{ to: "/contracts", label: "合同", roles: ["SYS_ADMIN", "DEVELOPER"] },
|
||||
{ to: "/deliveries", label: "交付", roles: ["SYS_ADMIN", "DEVELOPER"] },
|
||||
{ to: "/licenses/sn", label: "许可 SN", roles: ["SYS_ADMIN", "DEVELOPER"] },
|
||||
{ to: "/callbacks", label: "Callback 收件箱", roles: ["SYS_ADMIN", "OPS"] },
|
||||
{ to: "/integration/environments", label: "集成环境", roles: ["SYS_ADMIN", "DEVELOPER", "OPS"] },
|
||||
{ to: "/integration/product-lines", label: "产品线", roles: ["SYS_ADMIN", "DEVELOPER", "OPS"] },
|
||||
];
|
||||
|
||||
const visibleModuleLinks = computed(() => allModuleLinks.filter((l) => auth.hasAnyRole(l.roles)));
|
||||
|
||||
onMounted(() => auth.restoreAxiosAuth());
|
||||
|
||||
async function ping() {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</el-form-item>
|
||||
<el-button type="primary" native-type="submit" :loading="loading" block>登录</el-button>
|
||||
</el-form>
|
||||
<p class="hint">演示:admin / admin(SYS_ADMIN);dev / dev(DEVELOPER)</p>
|
||||
<p class="hint">演示:admin / admin(SYS_ADMIN);dev / dev(DEVELOPER);ops / ops(OPS,Callback 运营)</p>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user