fix(web): 适配后端 ID 字符串化(雪花 id 不能过 Number)
后端 J1 起所有 Long id 以字符串下发,审计出 4 处把 id 当数字用的地方: - utils/creatorImpersonation.ts:代看创作者 id 曾 Number(raw) 存 localStorage, 19 位 id 会被四舍五入导致 X-Creator-Id 头带错 id;改为全程字符串 - contentManagement/EpisodeManagementView.vue:Number(route.query.drama) 与 item.id 比较, 从短剧管理带 ?drama= 跳过来会选不中;改为字符串比较 - creator-center/composables/useDramaEdit.js:Number(route.params.id) 同上,作品编辑打不开 - permission/composables/useMenuManagement.js:顶级菜单哨兵 0 与接口的 "0" 类型不一致, 下拉回显会变裸 0;统一成字符串 '0' 核过不需要改:分页 total 后端保持数字;role.id === selectedRoleId 等两侧都来自接口; formatCount 内部 Number() 吃字符串;全局无 id 算术/下标/a.id-b.id。
This commit is contained in:
1 parent
db313f4aa6
commit
3ec9ea6717
4 files changed
+22
-13
No files matched your search
@@ -11,17 +11,22 @@ import { ref } from 'vue'
|
|||||||
*/
|
*/
|
||||||
const STORAGE_KEY = 'creator-center:impersonate-id'
|
const STORAGE_KEY = 'creator-center:impersonate-id'
|
||||||
|
|
||||||
function readStored(): number | null {
|
/**
|
||||||
|
* 代看目标按**字符串**存:创作者 id 是雪花 id(19 位),
|
||||||
|
* 用 Number 过一遍会被 JS 四舍五入,请求头就会带一个不存在的 id(见 api-phase1.md §0)。
|
||||||
|
*/
|
||||||
|
function readStored(): string | null {
|
||||||
const raw = localStorage.getItem(STORAGE_KEY)
|
const raw = localStorage.getItem(STORAGE_KEY)
|
||||||
const value = raw ? Number(raw) : NaN
|
const value = (raw || '').trim()
|
||||||
return Number.isFinite(value) && value > 0 ? value : null
|
return value && value !== '0' ? value : null
|
||||||
}
|
}
|
||||||
|
|
||||||
export const impersonateCreatorId = ref<number | null>(readStored())
|
export const impersonateCreatorId = ref<string | null>(readStored())
|
||||||
|
|
||||||
export function setImpersonateCreatorId(id: number | null) {
|
export function setImpersonateCreatorId(id: string | number | null) {
|
||||||
impersonateCreatorId.value = id
|
const value = id === null || id === undefined || id === '' ? null : String(id)
|
||||||
if (id) localStorage.setItem(STORAGE_KEY, String(id))
|
impersonateCreatorId.value = value
|
||||||
|
if (value) localStorage.setItem(STORAGE_KEY, value)
|
||||||
else localStorage.removeItem(STORAGE_KEY)
|
else localStorage.removeItem(STORAGE_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ const selectedDrama = computed(() => dramas.value.find((item) => item.id === sel
|
|||||||
async function loadDramas() {
|
async function loadDramas() {
|
||||||
const res = await pageDramasApi({ pageIndex: 1, pageSize: 200 })
|
const res = await pageDramasApi({ pageIndex: 1, pageSize: 200 })
|
||||||
dramas.value = res.data?.list || []
|
dramas.value = res.data?.list || []
|
||||||
const fromQuery = Number(route.query.drama)
|
// 剧 id 是字符串(雪花 id 过 Number 会被四舍五入),这里按字符串比较
|
||||||
|
const fromQuery = route.query.drama ? String(route.query.drama) : ''
|
||||||
if (fromQuery && dramas.value.some((item) => item.id === fromQuery)) {
|
if (fromQuery && dramas.value.some((item) => item.id === fromQuery)) {
|
||||||
selectedDramaId.value = fromQuery
|
selectedDramaId.value = fromQuery
|
||||||
} else if (!selectedDramaId.value && dramas.value.length) {
|
} else if (!selectedDramaId.value && dramas.value.length) {
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ function writeSession(key, value) {
|
|||||||
export function useDramaEdit() {
|
export function useDramaEdit() {
|
||||||
const { ensureAccess, impersonating } = useCreatorAccess()
|
const { ensureAccess, impersonating } = useCreatorAccess()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const dramaId = Number(route.params.id)
|
// 作品 id 是字符串(雪花 id 过 Number 会被四舍五入),按字符串比对
|
||||||
|
const dramaId = route.params.id ? String(route.params.id) : ''
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const drama = ref(null)
|
const drama = ref(null)
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ export function useMenuManagement() {
|
|||||||
const treeData = computed(() => mapNodes(menuTree.value))
|
const treeData = computed(() => mapNodes(menuTree.value))
|
||||||
|
|
||||||
const parentOptions = computed(() => {
|
const parentOptions = computed(() => {
|
||||||
const options = [{ id: 0, label: '顶级菜单' }]
|
// 顶级菜单哨兵跟接口的 parentId 一样用字符串 "0":菜单 id 是字符串,
|
||||||
|
// 数字 0 会在下拉里对不上、回显成裸 "0"
|
||||||
|
const options = [{ id: '0', label: '顶级菜单' }]
|
||||||
const walk = (nodes, depth) => {
|
const walk = (nodes, depth) => {
|
||||||
;(nodes || []).forEach((node) => {
|
;(nodes || []).forEach((node) => {
|
||||||
if (node.type !== 'BUTTON') {
|
if (node.type !== 'BUTTON') {
|
||||||
@@ -73,7 +75,7 @@ export function useMenuManagement() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetForm(parentId = 0) {
|
function resetForm(parentId = '0') {
|
||||||
Object.assign(form, {
|
Object.assign(form, {
|
||||||
id: null,
|
id: null,
|
||||||
parentId,
|
parentId,
|
||||||
@@ -94,7 +96,7 @@ export function useMenuManagement() {
|
|||||||
const raw = node.raw || {}
|
const raw = node.raw || {}
|
||||||
Object.assign(form, {
|
Object.assign(form, {
|
||||||
id: raw.id,
|
id: raw.id,
|
||||||
parentId: raw.parentId ?? 0,
|
parentId: raw.parentId ?? '0',
|
||||||
title: raw.meta?.title || '',
|
title: raw.meta?.title || '',
|
||||||
routePath: raw.path || '',
|
routePath: raw.path || '',
|
||||||
routeName: raw.name || '',
|
routeName: raw.name || '',
|
||||||
@@ -114,7 +116,7 @@ export function useMenuManagement() {
|
|||||||
return ElMessage.warning('请填写对应路由')
|
return ElMessage.warning('请填写对应路由')
|
||||||
}
|
}
|
||||||
const payload = {
|
const payload = {
|
||||||
parentId: form.parentId || 0,
|
parentId: form.parentId || '0',
|
||||||
title: form.title.trim(),
|
title: form.title.trim(),
|
||||||
routePath: form.routePath.trim(),
|
routePath: form.routePath.trim(),
|
||||||
routeName: form.routeName.trim(),
|
routeName: form.routeName.trim(),
|
||||||
|
|||||||
Reference in new issue
Block a user