Files
xuanzhi-service/web/.ai-transition/book-admin-menu-scripts/01-create-book-admin-menus.browser-console.js
wdh-home 392fbea7eb
Some checks failed
CI / init (pull_request) Has been cancelled
CI / Frontend node 18.16.0 (pull_request) Has been cancelled
CI / Backend go (1.22) (pull_request) Has been cancelled
CI / release-pr (pull_request) Has been cancelled
CI / devops-test (1.22, 18.16.0) (pull_request) Has been cancelled
CI / release-please (pull_request) Has been cancelled
CI / devops-prod (1.22, 18.x) (pull_request) Has been cancelled
CI / docker (pull_request) Has been cancelled
基础项目
2026-04-26 15:32:46 +08:00

242 lines
7.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 书籍后台管理菜单创建脚本
*
* 使用方式:
* 1. 登录后台管理前端。
* 2. 打开浏览器控制台。
* 3. 如前端接口代理不是 /api先执行
* window.__XUANZHI_BASE_API__ = 'http://127.0.0.1:8888'
* 4. 粘贴本文件全部内容并执行。
*
* 说明:
* - 脚本会先读取现有菜单树,已存在的菜单不会重复创建。
* - /menu/addBaseMenu 不返回新菜单 ID所以每次创建后会重新读取菜单树定位 ID。
*/
(async () => {
const BASE_API = window.__XUANZHI_BASE_API__ || '/api'
const TOKEN = window.__XUANZHI_TOKEN__ || localStorage.getItem('token') || getCookie('x-token')
let userId = window.__XUANZHI_USER_ID__ || localStorage.getItem('userId') || ''
const menus = [
{
key: 'bookRoot',
parentKey: null,
path: 'book',
name: 'book',
component: 'view/book/index.vue',
sort: 60,
hidden: false,
meta: {
title: '书籍管理',
icon: 'Reading',
keepAlive: false,
closeTab: false,
defaultMenu: false
}
},
{
key: 'bookManage',
parentKey: 'bookRoot',
path: 'bookManage',
name: 'bookManage',
component: 'view/book/book/index.vue',
sort: 10,
hidden: false,
meta: { title: '书籍管理', icon: 'Notebook', keepAlive: false, closeTab: false, defaultMenu: false }
},
{
key: 'bookChapterManage',
parentKey: 'bookRoot',
path: 'bookChapterManage',
name: 'bookChapterManage',
component: 'view/book/chapter/index.vue',
sort: 20,
hidden: false,
meta: { title: '章节管理', icon: 'Tickets', keepAlive: false, closeTab: false, defaultMenu: false }
},
{
key: 'bookAuthorManage',
parentKey: 'bookRoot',
path: 'bookAuthorManage',
name: 'bookAuthorManage',
component: 'view/book/author/index.vue',
sort: 30,
hidden: false,
meta: { title: '作者管理', icon: 'User', keepAlive: false, closeTab: false, defaultMenu: false }
},
{
key: 'bookSeriesManage',
parentKey: 'bookRoot',
path: 'bookSeriesManage',
name: 'bookSeriesManage',
component: 'view/book/series/index.vue',
sort: 40,
hidden: false,
meta: { title: '系列管理', icon: 'Collection', keepAlive: false, closeTab: false, defaultMenu: false }
},
{
key: 'bookCommentManage',
parentKey: 'bookRoot',
path: 'bookCommentManage',
name: 'bookCommentManage',
component: 'view/book/comment/index.vue',
sort: 50,
hidden: false,
meta: { title: '评论管理', icon: 'ChatLineSquare', keepAlive: false, closeTab: false, defaultMenu: false }
},
{
key: 'bookReadRecordManage',
parentKey: 'bookRoot',
path: 'bookReadRecordManage',
name: 'bookReadRecordManage',
component: 'view/book/readRecord/index.vue',
sort: 60,
hidden: false,
meta: { title: '阅读记录管理', icon: 'View', keepAlive: false, closeTab: false, defaultMenu: false }
},
{
key: 'bookFavoriteRecordManage',
parentKey: 'bookRoot',
path: 'bookFavoriteRecordManage',
name: 'bookFavoriteRecordManage',
component: 'view/book/favoriteRecord/index.vue',
sort: 70,
hidden: false,
meta: { title: '收藏记录管理', icon: 'Star', keepAlive: false, closeTab: false, defaultMenu: false }
},
{
key: 'bookCommentLikeRecordManage',
parentKey: 'bookRoot',
path: 'bookCommentLikeRecordManage',
name: 'bookCommentLikeRecordManage',
component: 'view/book/commentLikeRecord/index.vue',
sort: 80,
hidden: false,
meta: { title: '评论点赞记录管理', icon: 'Pointer', keepAlive: false, closeTab: false, defaultMenu: false }
}
]
if (!TOKEN) {
throw new Error('未找到 token请先登录后台或手动设置 window.__XUANZHI_TOKEN__')
}
userId = userId || await getCurrentUserId()
const createdOrFound = new Map()
for (const item of menus) {
const parentId = item.parentKey ? getMenuId(createdOrFound.get(item.parentKey)) : 0
const menu = await ensureMenu({ ...item, parentId })
createdOrFound.set(item.key, menu)
console.log(`[menu] ${item.meta.title} -> ID=${getMenuId(menu)} (${menu.component || item.component})`)
}
const result = Object.fromEntries(
[...createdOrFound.entries()].map(([key, menu]) => [key, getMenuId(menu)])
)
localStorage.setItem('xuanzhi-book-menu-ids', JSON.stringify(result))
console.log('书籍后台菜单创建/确认完成,菜单 ID 已写入 localStorage.xuanzhi-book-menu-ids', result)
console.log('下一步:执行 02-assign-book-admin-menus-to-roles.browser-console.js 给角色分配菜单。')
async function ensureMenu(menu) {
const existed = await findMenu(menu)
if (existed) return existed
const payload = {
path: menu.path,
name: menu.name,
hidden: menu.hidden,
parentId: menu.parentId,
component: menu.component,
sort: menu.sort,
meta: menu.meta,
parameters: [],
menuBtn: []
}
await apiPost('/menu/addBaseMenu', payload)
const created = await findMenu(menu)
if (!created) {
throw new Error(`菜单已提交但未在菜单树中找到:${menu.name} / ${menu.component}`)
}
return created
}
async function findMenu(menu) {
const tree = await getBaseMenuTree()
const flat = flattenMenus(tree)
return flat.find((item) =>
item.name === menu.name ||
item.path === menu.path ||
item.component === menu.component
)
}
async function getBaseMenuTree() {
const res = await apiPost('/menu/getBaseMenuTree', {})
return res.data?.menus || []
}
async function getCurrentUserId() {
try {
const res = await apiGet('/user/getUserInfo')
return res.data?.userInfo?.ID || res.data?.userInfo?.id || ''
} catch (error) {
console.warn('读取当前用户 ID 失败,将不带 x-user-id 调用菜单接口。必要时可手动设置 window.__XUANZHI_USER_ID__。', error)
return ''
}
}
async function apiGet(path) {
return apiRequest(path, { method: 'GET' })
}
async function apiPost(path, data) {
return apiRequest(path, {
method: 'POST',
body: JSON.stringify(data)
})
}
async function apiRequest(path, options = {}) {
const res = await fetch(`${BASE_API}${path}`, {
...options,
headers: {
'Content-Type': 'application/json',
'x-token': TOKEN,
'x-user-id': String(userId || ''),
...(options.headers || {})
}
})
const json = await res.json().catch(() => ({}))
if (!res.ok || json.code !== 0) {
throw new Error(`${path} 调用失败:${json.msg || res.statusText}`)
}
return json
}
function flattenMenus(list) {
const result = []
const walk = (items) => {
;(items || []).forEach((item) => {
result.push(item)
walk(item.children)
})
}
walk(list)
return result
}
function getMenuId(menu) {
return menu?.ID || menu?.id || menu?.menuId
}
function getCookie(name) {
return document.cookie
.split('; ')
.find((row) => row.startsWith(`${name}=`))
?.split('=')[1] || ''
}
})()