386 lines
13 KiB
TypeScript
386 lines
13 KiB
TypeScript
import { getServerSession } from 'next-auth'
|
|
import type { Session } from 'next-auth'
|
|
import { NextResponse } from 'next/server'
|
|
import { authOptions } from '@/lib/auth'
|
|
import {
|
|
DINGTALK_PERFORMANCE_SESSION_HEADER,
|
|
verifyDingtalkPerformanceSessionToken,
|
|
} from '@/lib/dingtalk-performance-session'
|
|
import {
|
|
PerformanceSurveyApiError,
|
|
createPerformanceSurveyWorkItemFromRequest,
|
|
createPerformanceSurvey,
|
|
cancelPerformanceSurvey,
|
|
exportPerformanceSurveyCsv,
|
|
getPerformanceSurveyDashboard,
|
|
getPerformanceSurveyDashboardExport,
|
|
getPerformanceSurveyDashboardDetail,
|
|
getPerformanceSurveyAdminConfiguration,
|
|
getPerformanceSurveyDetail,
|
|
getPerformanceSurveyMe,
|
|
getPerformanceSurveyNotificationStatus,
|
|
getPerformanceSurveyResults,
|
|
getPerformanceSurveyTemplates,
|
|
getPerformanceSurveyPositionGroups,
|
|
listPerformanceSurveyDepartments,
|
|
listPerformanceSurveyNotifications,
|
|
listPerformanceSurveys,
|
|
retryPerformanceSurveyNotificationById,
|
|
runPerformanceSurveyNotificationMaintenance,
|
|
searchPerformanceSurveyEmployees,
|
|
submitPerformanceSurveyWorkItemScores,
|
|
submitPerformanceSurveyWorkItemScore,
|
|
submitPerformanceSurveyResponse,
|
|
previewPerformanceSurveyEmployeeProfiles,
|
|
syncPerformanceSurveyEmployeeProfiles,
|
|
updatePerformanceSurvey,
|
|
savePerformanceSurveyAdminPositionGroup,
|
|
publishPerformanceSurveyAdminPositionGroup,
|
|
savePerformanceSurveyAdminTemplate,
|
|
copyPerformanceSurveyAdminTemplateVersion,
|
|
publishPerformanceSurveyAdminTemplateVersion,
|
|
archivePerformanceSurveyAdminPositionAssignment,
|
|
copyPerformanceSurveyAdminPositionGroup,
|
|
createPerformanceSurveyAdminPositionAssignments,
|
|
createPerformanceSurveyAdminPositionGroup,
|
|
listPerformanceSurveyAdminConfigAuditLogs,
|
|
listPerformanceSurveyAdminPositionAssignments,
|
|
previewPerformanceSurveyAdminPositionGroup,
|
|
removePerformanceSurveyAdminPositionGroup,
|
|
removePerformanceSurveyAdminTemplate,
|
|
removePerformanceSurveyPublicDashboardAssessment,
|
|
updatePerformanceSurveyAdminPositionAssignment,
|
|
} from '@/lib/performance-survey-service'
|
|
|
|
export const runtime = 'nodejs'
|
|
export const dynamic = 'force-dynamic'
|
|
export const revalidate = 0
|
|
|
|
type RouteContext = {
|
|
params: {
|
|
path?: string[]
|
|
}
|
|
}
|
|
|
|
function ok(data: unknown, init?: ResponseInit) {
|
|
return NextResponse.json({ success: true, data }, init)
|
|
}
|
|
|
|
function errorResponse(error: unknown) {
|
|
if (error instanceof PerformanceSurveyApiError) {
|
|
return NextResponse.json({ success: false, error: error.message }, { status: error.status })
|
|
}
|
|
|
|
if (error && typeof error === 'object' && typeof (error as { status?: unknown }).status === 'number') {
|
|
return NextResponse.json(
|
|
{ success: false, error: error instanceof Error ? error.message : '请求失败' },
|
|
{ status: (error as { status: number }).status },
|
|
)
|
|
}
|
|
|
|
const message = error instanceof Error ? error.message : '服务器错误'
|
|
console.error('[performance-survey] API error:', error)
|
|
return NextResponse.json({ success: false, error: message }, { status: 500 })
|
|
}
|
|
|
|
function readDingtalkPerformanceToken(request: Request) {
|
|
const headerToken = request.headers.get(DINGTALK_PERFORMANCE_SESSION_HEADER)
|
|
if (headerToken) {
|
|
return headerToken
|
|
}
|
|
|
|
const authorization = request.headers.get('authorization') || ''
|
|
const match = authorization.match(/^Bearer\s+(.+)$/i)
|
|
return match?.[1]?.trim() || null
|
|
}
|
|
|
|
async function getSession(request: Request): Promise<Session | null> {
|
|
const session = await getServerSession(authOptions)
|
|
if ((session?.user as any)?.id) {
|
|
return session
|
|
}
|
|
|
|
const payload = verifyDingtalkPerformanceSessionToken(readDingtalkPerformanceToken(request))
|
|
if (!payload) {
|
|
return session
|
|
}
|
|
|
|
return {
|
|
user: {
|
|
id: payload.userId,
|
|
email: payload.email,
|
|
name: payload.name,
|
|
avatar: payload.avatar || null,
|
|
role: payload.role,
|
|
department: payload.department || '',
|
|
managedDepartment: payload.managedDepartment || null,
|
|
isSuperAdmin: payload.isSuperAdmin ?? false,
|
|
},
|
|
expires: new Date(payload.exp * 1000).toISOString(),
|
|
}
|
|
}
|
|
|
|
function getPath(context: RouteContext) {
|
|
return context.params.path || []
|
|
}
|
|
|
|
export async function GET(request: Request, context: RouteContext) {
|
|
try {
|
|
const session = await getSession(request)
|
|
const path = getPath(context)
|
|
const url = new URL(request.url)
|
|
|
|
if (path.length === 0 || path[0] === 'me') {
|
|
return ok(await getPerformanceSurveyMe(session))
|
|
}
|
|
|
|
if (path[0] === 'templates') {
|
|
return ok(await getPerformanceSurveyTemplates(session, url.searchParams))
|
|
}
|
|
|
|
if (path[0] === 'position-groups') {
|
|
return ok(await getPerformanceSurveyPositionGroups(session, url.searchParams))
|
|
}
|
|
|
|
if (path[0] === 'employees') {
|
|
return ok(await searchPerformanceSurveyEmployees(session, url.searchParams))
|
|
}
|
|
|
|
if (path[0] === 'departments') {
|
|
return ok(await listPerformanceSurveyDepartments(session, url.searchParams))
|
|
}
|
|
|
|
if (path[0] === 'dashboard' && path[1] === 'export') {
|
|
return ok(await getPerformanceSurveyDashboardExport(session, url.searchParams))
|
|
}
|
|
|
|
if (path[0] === 'dashboard' && path[1] === 'detail') {
|
|
return ok(await getPerformanceSurveyDashboardDetail(session, url.searchParams))
|
|
}
|
|
|
|
if (path[0] === 'dashboard') {
|
|
return ok(await getPerformanceSurveyDashboard(session, url.searchParams))
|
|
}
|
|
|
|
if (path[0] === 'surveys' && path.length === 1) {
|
|
return ok(await listPerformanceSurveys(session, url.searchParams))
|
|
}
|
|
|
|
if (path[0] === 'surveys' && path[1] && path.length === 2) {
|
|
return ok(await getPerformanceSurveyDetail(session, path[1]))
|
|
}
|
|
|
|
if (path[0] === 'surveys' && path[1] && path[2] === 'results') {
|
|
return ok(await getPerformanceSurveyResults(session, path[1], url.searchParams))
|
|
}
|
|
|
|
if (path[0] === 'results' && path[1]) {
|
|
return ok(await getPerformanceSurveyResults(session, path[1], url.searchParams))
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'notifications' && path[2] === 'status') {
|
|
return ok(await getPerformanceSurveyNotificationStatus(session))
|
|
}
|
|
|
|
if (
|
|
path[0] === 'admin'
|
|
&& path[1] === 'position-groups'
|
|
&& path[2]
|
|
&& path[3] === 'preview'
|
|
&& path.length === 4
|
|
) {
|
|
return ok(await previewPerformanceSurveyAdminPositionGroup(session, path[2], url.searchParams))
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'position-assignments' && path.length === 2) {
|
|
return ok(await listPerformanceSurveyAdminPositionAssignments(session, url.searchParams))
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'config-audit-logs' && path.length === 2) {
|
|
return ok(await listPerformanceSurveyAdminConfigAuditLogs(session, url.searchParams))
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'config') {
|
|
return ok(await getPerformanceSurveyAdminConfiguration(session, url.searchParams))
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'notifications') {
|
|
return ok(await listPerformanceSurveyNotifications(session, url.searchParams))
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'export') {
|
|
const csv = await exportPerformanceSurveyCsv(session)
|
|
return new NextResponse(csv, {
|
|
headers: {
|
|
'Content-Type': 'text/csv; charset=utf-8',
|
|
'Content-Disposition': 'attachment; filename="performance-survey-export.csv"',
|
|
},
|
|
})
|
|
}
|
|
|
|
return NextResponse.json({ success: false, error: '接口不存在' }, { status: 404 })
|
|
} catch (error) {
|
|
return errorResponse(error)
|
|
}
|
|
}
|
|
|
|
export async function POST(request: Request, context: RouteContext) {
|
|
try {
|
|
const session = await getSession(request)
|
|
const path = getPath(context)
|
|
|
|
if (path[0] === 'surveys' && path[1] && path[2] === 'work-items' && path.length === 3) {
|
|
return ok(await createPerformanceSurveyWorkItemFromRequest(session, path[1], request), { status: 201 })
|
|
}
|
|
|
|
const body = await request.json().catch(() => ({}))
|
|
|
|
if (path[0] === 'surveys' && path.length === 1) {
|
|
return ok(await createPerformanceSurvey(session, body), { status: 201 })
|
|
}
|
|
|
|
if (path[0] === 'surveys' && path[1] && path[2] === 'cancel' && path.length === 3) {
|
|
return ok(await cancelPerformanceSurvey(session, path[1], body))
|
|
}
|
|
|
|
if (path[0] === 'surveys' && path[1] && path[2] === 'responses') {
|
|
return ok(await submitPerformanceSurveyResponse(session, path[1], body))
|
|
}
|
|
|
|
if (path[0] === 'surveys' && path[1] && path[2] === 'work-item-scores' && path.length === 3) {
|
|
return ok(await submitPerformanceSurveyWorkItemScores(session, path[1], body))
|
|
}
|
|
|
|
if (path[0] === 'surveys' && path[1] && path[2] === 'work-items' && path[3] && path[4] === 'scores') {
|
|
return ok(await submitPerformanceSurveyWorkItemScore(session, path[1], path[3], body))
|
|
}
|
|
|
|
if (
|
|
path[0] === 'admin'
|
|
&& path[1] === 'sync-employees'
|
|
&& path[2] === 'preview'
|
|
&& path.length === 3
|
|
) {
|
|
return ok(await previewPerformanceSurveyEmployeeProfiles(session, body))
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'sync-employees' && path.length === 2) {
|
|
return ok(await syncPerformanceSurveyEmployeeProfiles(session, body))
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'position-groups' && path.length === 2) {
|
|
return ok(await createPerformanceSurveyAdminPositionGroup(session, body), { status: 201 })
|
|
}
|
|
|
|
if (
|
|
path[0] === 'admin'
|
|
&& path[1] === 'position-groups'
|
|
&& path[2]
|
|
&& path[3] === 'copy'
|
|
&& path.length === 4
|
|
) {
|
|
return ok(await copyPerformanceSurveyAdminPositionGroup(session, path[2], body), { status: 201 })
|
|
}
|
|
|
|
if (
|
|
path[0] === 'admin'
|
|
&& path[1] === 'position-groups'
|
|
&& path[2]
|
|
&& path[3] === 'publish'
|
|
&& path.length === 4
|
|
) {
|
|
return ok(await publishPerformanceSurveyAdminPositionGroup(session, path[2], body))
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'position-assignments' && path.length === 2) {
|
|
return ok(await createPerformanceSurveyAdminPositionAssignments(session, body), { status: 201 })
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'templates' && path.length === 2) {
|
|
return ok(await savePerformanceSurveyAdminTemplate(session, body), { status: 201 })
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'templates' && path[2] && path[3] === 'copy') {
|
|
return ok(await copyPerformanceSurveyAdminTemplateVersion(session, path[2]), { status: 201 })
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'templates' && path[2] && path[3] === 'publish') {
|
|
return ok(await publishPerformanceSurveyAdminTemplateVersion(session, path[2], body))
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'notifications' && path[2] === 'maintenance') {
|
|
return ok(await runPerformanceSurveyNotificationMaintenance(session))
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'notifications' && path[2] && path[3] === 'retry') {
|
|
return ok(await retryPerformanceSurveyNotificationById(session, path[2]))
|
|
}
|
|
|
|
return NextResponse.json({ success: false, error: '接口不存在' }, { status: 404 })
|
|
} catch (error) {
|
|
return errorResponse(error)
|
|
}
|
|
}
|
|
|
|
export async function PATCH(request: Request, context: RouteContext) {
|
|
try {
|
|
const session = await getSession(request)
|
|
const path = getPath(context)
|
|
const body = await request.json().catch(() => ({}))
|
|
|
|
if (path[0] === 'surveys' && path[1] && path.length === 2) {
|
|
return ok(await updatePerformanceSurvey(session, path[1], body))
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'position-groups' && path[2] && path.length === 3) {
|
|
return ok(await savePerformanceSurveyAdminPositionGroup(session, path[2], body))
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'templates' && path[2] && path.length === 3) {
|
|
return ok(await savePerformanceSurveyAdminTemplate(session, { ...body, versionId: path[2] }))
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'position-assignments' && path[2] && path.length === 3) {
|
|
return ok(await updatePerformanceSurveyAdminPositionAssignment(session, path[2], body))
|
|
}
|
|
|
|
return NextResponse.json({ success: false, error: '接口不存在' }, { status: 404 })
|
|
} catch (error) {
|
|
return errorResponse(error)
|
|
}
|
|
}
|
|
|
|
export async function DELETE(request: Request, context: RouteContext) {
|
|
try {
|
|
const session = await getSession(request)
|
|
const path = getPath(context)
|
|
const body = await request.json().catch(() => ({}))
|
|
|
|
if (path[0] === 'admin' && path[1] === 'position-groups' && path[2] && path.length === 3) {
|
|
return ok(await removePerformanceSurveyAdminPositionGroup(session, path[2], body))
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'templates' && path[2] && path.length === 3) {
|
|
return ok(await removePerformanceSurveyAdminTemplate(session, path[2], body))
|
|
}
|
|
|
|
if (path[0] === 'admin' && path[1] === 'position-assignments' && path[2] && path.length === 3) {
|
|
return ok(await archivePerformanceSurveyAdminPositionAssignment(session, path[2], body))
|
|
}
|
|
|
|
if (
|
|
path[0] === 'dashboard'
|
|
&& path[1] === 'public'
|
|
&& path[2] === 'assessments'
|
|
&& path[3]
|
|
&& path.length === 4
|
|
) {
|
|
return ok(await removePerformanceSurveyPublicDashboardAssessment(session, path[3], body))
|
|
}
|
|
|
|
return NextResponse.json({ success: false, error: '接口不存在' }, { status: 404 })
|
|
} catch (error) {
|
|
return errorResponse(error)
|
|
}
|
|
}
|