优化客服权限-增加兑换截图和关闭任务
This commit is contained in:
@@ -198,7 +198,7 @@ router.post('/tasks/:taskId/support-redeem', requireAdminRoles(['admin', 'operat
|
||||
},
|
||||
))
|
||||
|
||||
router.post('/tasks/:taskId/close', requireAdminRoles(['admin', 'operator']), createJsonHandler(
|
||||
router.post('/tasks/:taskId/close', requireAdminRoles(['admin', 'operator', 'support']), createJsonHandler(
|
||||
(req) => closeAdminTask((/** @type {AdminTaskRouteParams} */ (req.params)).taskId),
|
||||
{
|
||||
successMessage: '任务已关闭',
|
||||
|
||||
@@ -14,6 +14,7 @@ import { formatFenToAmount, normalizeFen } from '../../utils/money.js'
|
||||
import { getTencentBrowserSessionReviewScreenshotPath } from '../session/session.js'
|
||||
import { normalizeDateQuery, normalizePage, normalizePageSize, safeParseJson } from './admin-query-utils.js'
|
||||
import {
|
||||
canViewerCloseTask,
|
||||
canRegenerateClaimLinkForViewer,
|
||||
canViewerConfirmAssistedRole,
|
||||
canViewerRedeemAssistedTask,
|
||||
@@ -281,7 +282,7 @@ export async function getAdminTaskDetail(taskId, session = null) {
|
||||
&& ['retry_pending', 'manual_review', 'waiting_inventory'].includes(task.task_status),
|
||||
canReleaseInventory: mappedInventoryBindings.some((binding) => binding.canRelease),
|
||||
canRegenerateClaimLink: canRegenerateClaimLinkForViewer(task, viewerContext),
|
||||
canClose: viewerContext.canManageTaskLifecycle && !['redeemed', 'closed'].includes(task.task_status),
|
||||
canClose: canViewerCloseTask(task, viewerContext),
|
||||
canMarkManualReview: viewerContext.canManageTaskLifecycle && !['redeemed', 'closed', 'manual_review'].includes(task.task_status),
|
||||
canCompleteManualDispatch: viewerContext.canManageTaskLifecycle && isManualDispatchTask(task) && !['redeemed', 'closed'].includes(task.task_status),
|
||||
canSupportConfirmRole: canViewerConfirmAssistedRole(task, viewerContext),
|
||||
@@ -295,18 +296,6 @@ export async function getAdminTaskDetail(taskId, session = null) {
|
||||
/** @param {AdminViewerSessionInput | null} [session] */
|
||||
export async function getAdminTaskScreenshotPath(taskId, session = null) {
|
||||
const task = await getRequiredTask(taskId)
|
||||
const viewerContext = createAdminViewerContext(session)
|
||||
|
||||
if (viewerContext.role === 'support') {
|
||||
if (!task.browser_session_id) {
|
||||
throw createHttpError('当前任务还没有客服复核截图', {
|
||||
statusCode: 404,
|
||||
errorCode: 'admin_task_review_screenshot_not_found',
|
||||
})
|
||||
}
|
||||
|
||||
return getTencentBrowserSessionReviewScreenshotPath(task.browser_session_id)
|
||||
}
|
||||
|
||||
if (task.screenshot_path) {
|
||||
return task.screenshot_path
|
||||
@@ -316,7 +305,7 @@ export async function getAdminTaskScreenshotPath(taskId, session = null) {
|
||||
return getTencentBrowserSessionReviewScreenshotPath(task.browser_session_id)
|
||||
}
|
||||
|
||||
throw createHttpError('当前任务还没有截图', {
|
||||
throw createHttpError('当前任务还没有可查看截图', {
|
||||
statusCode: 404,
|
||||
errorCode: 'admin_task_screenshot_not_found',
|
||||
})
|
||||
|
||||
@@ -68,10 +68,6 @@ export function createAdminViewerContext(session = null) {
|
||||
}
|
||||
|
||||
export async function resolveAdminTaskScreenshotUrl(task, viewerContext) {
|
||||
if (viewerContext.role === 'support') {
|
||||
return task.browser_session_id ? `/api/v1/admin/tasks/${task.id}/screenshot` : ''
|
||||
}
|
||||
|
||||
if (task.screenshot_path || task.browser_session_id) {
|
||||
return `/api/v1/admin/tasks/${task.id}/screenshot`
|
||||
}
|
||||
@@ -79,6 +75,14 @@ export async function resolveAdminTaskScreenshotUrl(task, viewerContext) {
|
||||
return ''
|
||||
}
|
||||
|
||||
export function canViewerCloseTask(task, viewerContext) {
|
||||
if (!['admin', 'operator', 'support'].includes(viewerContext.role)) {
|
||||
return false
|
||||
}
|
||||
|
||||
return !['redeemed', 'closed'].includes(String(task?.task_status || '').trim())
|
||||
}
|
||||
|
||||
export function resolveDisplayShopName(provider, shopId, shopName) {
|
||||
const normalizedShopName = String(shopName || '').trim()
|
||||
if (normalizedShopName) {
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
|
||||
import {
|
||||
canViewerCloseTask,
|
||||
createAdminViewerContext,
|
||||
resolveAdminTaskScreenshotUrl,
|
||||
} from './admin-read-shared-helpers.js'
|
||||
|
||||
test('resolveAdminTaskScreenshotUrl lets support view final redeemed screenshot', async () => {
|
||||
const task = {
|
||||
id: 12,
|
||||
screenshot_path: '/tmp/redeemed-12.png',
|
||||
browser_session_id: '',
|
||||
}
|
||||
|
||||
const screenshotUrl = await resolveAdminTaskScreenshotUrl(task, createAdminViewerContext({ role: 'support' }))
|
||||
|
||||
assert.equal(screenshotUrl, '/api/v1/admin/tasks/12/screenshot')
|
||||
})
|
||||
|
||||
test('resolveAdminTaskScreenshotUrl falls back to review screenshot when only browser session exists', async () => {
|
||||
const task = {
|
||||
id: 13,
|
||||
screenshot_path: '',
|
||||
browser_session_id: 'browser-session-13',
|
||||
}
|
||||
|
||||
const screenshotUrl = await resolveAdminTaskScreenshotUrl(task, createAdminViewerContext({ role: 'support' }))
|
||||
|
||||
assert.equal(screenshotUrl, '/api/v1/admin/tasks/13/screenshot')
|
||||
})
|
||||
|
||||
test('canViewerCloseTask allows support to close active task but not redeemed task', () => {
|
||||
const viewerContext = createAdminViewerContext({ role: 'support' })
|
||||
|
||||
assert.equal(canViewerCloseTask({ task_status: 'link_generated' }, viewerContext), true)
|
||||
assert.equal(canViewerCloseTask({ task_status: 'redeemed' }, viewerContext), false)
|
||||
})
|
||||
Reference in New Issue
Block a user