Initial commit
This commit is contained in:
114
lib/hooks/use-auth.ts
Normal file
114
lib/hooks/use-auth.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
"use client"
|
||||
|
||||
import { useState, useEffect, createContext } from "react"
|
||||
|
||||
export interface User {
|
||||
id: string
|
||||
name: string
|
||||
email: string
|
||||
department: string
|
||||
role: "user" | "admin"
|
||||
createdAt: string
|
||||
}
|
||||
|
||||
interface AuthContextType {
|
||||
user: User | null
|
||||
login: (email: string, password: string) => Promise<boolean>
|
||||
register: (userData: Omit<User, "id" | "createdAt"> & { password: string }) => Promise<boolean>
|
||||
logout: () => void
|
||||
isLoading: boolean
|
||||
}
|
||||
|
||||
const AuthContext = createContext<AuthContextType | undefined>(undefined)
|
||||
|
||||
// 預設用戶數據
|
||||
const defaultUsers = [
|
||||
{
|
||||
id: "admin-1",
|
||||
name: "系統管理員",
|
||||
email: "admin@company.com",
|
||||
password: "admin123",
|
||||
department: "人力資源部",
|
||||
role: "admin" as const,
|
||||
createdAt: new Date().toISOString(),
|
||||
},
|
||||
{
|
||||
id: "user-1",
|
||||
name: "張小明",
|
||||
email: "user@company.com",
|
||||
password: "user123",
|
||||
department: "資訊技術部",
|
||||
role: "user" as const,
|
||||
createdAt: new Date().toISOString(),
|
||||
},
|
||||
]
|
||||
|
||||
export function useAuth() {
|
||||
const [user, setUser] = useState<User | null>(null)
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
// 初始化預設用戶數據
|
||||
const existingUsers = localStorage.getItem("hr_users")
|
||||
if (!existingUsers) {
|
||||
localStorage.setItem("hr_users", JSON.stringify(defaultUsers))
|
||||
}
|
||||
|
||||
// 檢查是否有已登入的用戶
|
||||
const currentUser = localStorage.getItem("hr_current_user")
|
||||
if (currentUser) {
|
||||
setUser(JSON.parse(currentUser))
|
||||
}
|
||||
setIsLoading(false)
|
||||
}, [])
|
||||
|
||||
const login = async (email: string, password: string): Promise<boolean> => {
|
||||
const users = JSON.parse(localStorage.getItem("hr_users") || "[]")
|
||||
const user = users.find((u: any) => u.email === email && u.password === password)
|
||||
|
||||
if (user) {
|
||||
const { password: _, ...userWithoutPassword } = user
|
||||
setUser(userWithoutPassword)
|
||||
localStorage.setItem("hr_current_user", JSON.stringify(userWithoutPassword))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const register = async (userData: Omit<User, "id" | "createdAt"> & { password: string }): Promise<boolean> => {
|
||||
const users = JSON.parse(localStorage.getItem("hr_users") || "[]")
|
||||
|
||||
// 檢查電子郵件是否已存在
|
||||
if (users.some((u: any) => u.email === userData.email)) {
|
||||
return false
|
||||
}
|
||||
|
||||
const newUser = {
|
||||
...userData,
|
||||
id: `user-${Date.now()}`,
|
||||
createdAt: new Date().toISOString(),
|
||||
}
|
||||
|
||||
users.push(newUser)
|
||||
localStorage.setItem("hr_users", JSON.stringify(users))
|
||||
|
||||
const { password: _, ...userWithoutPassword } = newUser
|
||||
setUser(userWithoutPassword)
|
||||
localStorage.setItem("hr_current_user", JSON.stringify(userWithoutPassword))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
const logout = () => {
|
||||
setUser(null)
|
||||
localStorage.removeItem("hr_current_user")
|
||||
}
|
||||
|
||||
return {
|
||||
user,
|
||||
login,
|
||||
register,
|
||||
logout,
|
||||
isLoading,
|
||||
}
|
||||
}
|
114
lib/questions/creative-questions.ts
Normal file
114
lib/questions/creative-questions.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
export interface CreativeQuestion {
|
||||
id: number
|
||||
statement: string
|
||||
isReverse?: boolean // 是否為反向計分題
|
||||
category: "innovation" | "imagination" | "flexibility" | "originality"
|
||||
}
|
||||
|
||||
export const creativeQuestions: CreativeQuestion[] = [
|
||||
{
|
||||
id: 1,
|
||||
statement: "我經常能想出別人想不到的解決方案",
|
||||
category: "innovation",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
statement: "我喜歡嘗試新的做事方法,即使可能會失敗",
|
||||
category: "innovation",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
statement: "我更喜歡按照既定的規則和程序工作",
|
||||
isReverse: true,
|
||||
category: "flexibility",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
statement: "我能夠從不同的角度看待同一個問題",
|
||||
category: "flexibility",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
statement: "我經常會有一些奇思妙想",
|
||||
category: "imagination",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
statement: "我喜歡參與腦力激盪活動",
|
||||
category: "innovation",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
statement: "我認為傳統的方法通常是最好的",
|
||||
isReverse: true,
|
||||
category: "originality",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
statement: "我能夠將看似無關的概念聯繫起來",
|
||||
category: "imagination",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
statement: "我喜歡挑戰現有的做事方式",
|
||||
category: "originality",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
statement: "我在面對問題時,通常能想出多種解決方案",
|
||||
category: "flexibility",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
statement: "我避免做那些結果不確定的事情",
|
||||
isReverse: true,
|
||||
category: "innovation",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
statement: "我經常會想像一些不存在的情景或故事",
|
||||
category: "imagination",
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
statement: "我喜歡創造性的工作任務",
|
||||
category: "originality",
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
statement: "我能夠快速適應新的工作環境和要求",
|
||||
category: "flexibility",
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
statement: "我更願意改進現有的方法而不是創造全新的方法",
|
||||
isReverse: true,
|
||||
category: "originality",
|
||||
},
|
||||
{
|
||||
id: 16,
|
||||
statement: "我經常會想到一些獨特的想法",
|
||||
category: "imagination",
|
||||
},
|
||||
{
|
||||
id: 17,
|
||||
statement: "我喜歡探索未知的領域",
|
||||
category: "innovation",
|
||||
},
|
||||
{
|
||||
id: 18,
|
||||
statement: "我認為穩定性比創新性更重要",
|
||||
isReverse: true,
|
||||
category: "innovation",
|
||||
},
|
||||
{
|
||||
id: 19,
|
||||
statement: "我能夠在限制條件下找到創造性的解決方案",
|
||||
category: "flexibility",
|
||||
},
|
||||
{
|
||||
id: 20,
|
||||
statement: "我經常會提出與眾不同的觀點",
|
||||
category: "originality",
|
||||
},
|
||||
]
|
138
lib/questions/logic-questions.ts
Normal file
138
lib/questions/logic-questions.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
export interface LogicQuestion {
|
||||
id: number
|
||||
question: string
|
||||
options: {
|
||||
value: string
|
||||
text: string
|
||||
}[]
|
||||
correctAnswer: string
|
||||
explanation?: string
|
||||
}
|
||||
|
||||
export const logicQuestions: LogicQuestion[] = [
|
||||
{
|
||||
id: 1,
|
||||
question: "如果所有的玫瑰都是花,所有的花都需要水,那麼可以得出什麼結論?",
|
||||
options: [
|
||||
{ value: "A", text: "所有的玫瑰都需要水" },
|
||||
{ value: "B", text: "所有需要水的都是玫瑰" },
|
||||
{ value: "C", text: "有些花不是玫瑰" },
|
||||
{ value: "D", text: "玫瑰不需要土壤" },
|
||||
],
|
||||
correctAnswer: "A",
|
||||
explanation: "根據三段論推理,所有玫瑰都是花,所有花都需要水,因此所有玫瑰都需要水。",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
question: "在一個序列中:2, 6, 12, 20, 30, ?。下一個數字是什麼?",
|
||||
options: [
|
||||
{ value: "A", text: "40" },
|
||||
{ value: "B", text: "42" },
|
||||
{ value: "C", text: "44" },
|
||||
{ value: "D", text: "48" },
|
||||
],
|
||||
correctAnswer: "B",
|
||||
explanation: "序列規律:n×(n+1),即1×2=2, 2×3=6, 3×4=12, 4×5=20, 5×6=30, 6×7=42",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
question:
|
||||
"五個人坐成一排,張三不坐兩端,李四不坐中間,王五必須坐在張三的右邊。如果趙六坐在最左邊,那麼誰坐在最右邊?",
|
||||
options: [
|
||||
{ value: "A", text: "張三" },
|
||||
{ value: "B", text: "李四" },
|
||||
{ value: "C", text: "王五" },
|
||||
{ value: "D", text: "錢七" },
|
||||
],
|
||||
correctAnswer: "C",
|
||||
explanation: "根據約束條件推理,趙六在最左邊,張三不坐兩端且王五在其右邊,李四不坐中間,最終王五坐在最右邊。",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
question: "如果今天是星期三,那麼100天後是星期幾?",
|
||||
options: [
|
||||
{ value: "A", text: "星期一" },
|
||||
{ value: "B", text: "星期二" },
|
||||
{ value: "C", text: "星期三" },
|
||||
{ value: "D", text: "星期五" },
|
||||
],
|
||||
correctAnswer: "D",
|
||||
explanation: "100÷7=14餘2,所以100天後是星期三往後推2天,即星期五。",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
question:
|
||||
"在一個班級中,會游泳的學生有15人,會騎自行車的學生有18人,兩樣都會的學生有8人,兩樣都不會的學生有5人。這個班級總共有多少學生?",
|
||||
options: [
|
||||
{ value: "A", text: "28人" },
|
||||
{ value: "B", text: "30人" },
|
||||
{ value: "C", text: "32人" },
|
||||
{ value: "D", text: "35人" },
|
||||
],
|
||||
correctAnswer: "B",
|
||||
explanation: "使用集合論:總人數 = 會游泳 + 會騎車 - 兩樣都會 + 兩樣都不會 = 15 + 18 - 8 + 5 = 30人",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
question: "一個立方體的每個面都塗上不同的顏色,然後切成27個小立方體。問有多少個小立方體恰好有兩個面被塗色?",
|
||||
options: [
|
||||
{ value: "A", text: "8個" },
|
||||
{ value: "B", text: "12個" },
|
||||
{ value: "C", text: "16個" },
|
||||
{ value: "D", text: "20個" },
|
||||
],
|
||||
correctAnswer: "B",
|
||||
explanation: "3×3×3立方體中,恰好有兩個面塗色的小立方體位於大立方體的12條邊上(除去8個角),共12個。",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
question: "如果A>B,B>C,C>D,那麼下列哪個結論一定正確?",
|
||||
options: [
|
||||
{ value: "A", text: "A>D" },
|
||||
{ value: "B", text: "A=D" },
|
||||
{ value: "C", text: "B=C" },
|
||||
{ value: "D", text: "C<A" },
|
||||
],
|
||||
correctAnswer: "A",
|
||||
explanation: "根據傳遞性,A>B>C>D,因此A>D一定成立。",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
question: "一個時鐘在6點整時,時針和分針的夾角是多少度?",
|
||||
options: [
|
||||
{ value: "A", text: "180度" },
|
||||
{ value: "B", text: "90度" },
|
||||
{ value: "C", text: "120度" },
|
||||
{ value: "D", text: "150度" },
|
||||
],
|
||||
correctAnswer: "A",
|
||||
explanation: "6點整時,時針指向6,分針指向12,它們之間相隔6個小時刻度,每個刻度30度,所以夾角是6×30=180度。",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
question:
|
||||
"在一次考試中,小明的成績比小紅高,小紅的成績比小李高,小李的成績比小王高。如果小王得了80分,小明得了92分,那麼小紅可能得了多少分?",
|
||||
options: [
|
||||
{ value: "A", text: "78分" },
|
||||
{ value: "B", text: "85分" },
|
||||
{ value: "C", text: "94分" },
|
||||
{ value: "D", text: "79分" },
|
||||
],
|
||||
correctAnswer: "B",
|
||||
explanation: "根據排序:小明(92)>小紅>小李>小王(80),所以小紅的分數在80-92之間,只有85分符合條件。",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
question:
|
||||
"有三個盒子,每個盒子裡都有一些球。第一個盒子裡的球數是第二個盒子的2倍,第二個盒子裡的球數是第三個盒子的3倍。如果總共有66個球,那麼第二個盒子裡有多少個球?",
|
||||
options: [
|
||||
{ value: "A", text: "18個" },
|
||||
{ value: "B", text: "12個" },
|
||||
{ value: "C", text: "15個" },
|
||||
{ value: "D", text: "21個" },
|
||||
],
|
||||
correctAnswer: "A",
|
||||
explanation:
|
||||
"設第三個盒子有x個球,則第二個盒子有3x個球,第一個盒子有6x個球。總和:x+3x+6x=10x=66,所以x=6.6,第二個盒子有3×6=18個球。",
|
||||
},
|
||||
]
|
6
lib/utils.ts
Normal file
6
lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
180
lib/utils/excel-parser.ts
Normal file
180
lib/utils/excel-parser.ts
Normal file
@@ -0,0 +1,180 @@
|
||||
import * as XLSX from "xlsx"
|
||||
|
||||
export interface LogicQuestionImport {
|
||||
id: number
|
||||
question: string
|
||||
optionA: string
|
||||
optionB: string
|
||||
optionC: string
|
||||
optionD: string
|
||||
correctAnswer: string
|
||||
explanation?: string
|
||||
}
|
||||
|
||||
export interface CreativeQuestionImport {
|
||||
id: number
|
||||
statement: string
|
||||
category: "innovation" | "imagination" | "flexibility" | "originality"
|
||||
isReverse: boolean
|
||||
}
|
||||
|
||||
export interface ImportResult {
|
||||
success: boolean
|
||||
message: string
|
||||
data?: LogicQuestionImport[] | CreativeQuestionImport[]
|
||||
errors?: string[]
|
||||
}
|
||||
|
||||
export function parseExcelFile(file: File, type: "logic" | "creative"): Promise<ImportResult> {
|
||||
return new Promise((resolve) => {
|
||||
const reader = new FileReader()
|
||||
|
||||
reader.onload = (e) => {
|
||||
try {
|
||||
const data = new Uint8Array(e.target?.result as ArrayBuffer)
|
||||
const workbook = XLSX.read(data, { type: "array" })
|
||||
const sheetName = workbook.SheetNames[0]
|
||||
const worksheet = workbook.Sheets[sheetName]
|
||||
const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 })
|
||||
|
||||
if (type === "logic") {
|
||||
const result = parseLogicQuestions(jsonData as any[][])
|
||||
resolve(result)
|
||||
} else {
|
||||
const result = parseCreativeQuestions(jsonData as any[][])
|
||||
resolve(result)
|
||||
}
|
||||
} catch (error) {
|
||||
resolve({
|
||||
success: false,
|
||||
message: "檔案解析失敗,請檢查檔案格式",
|
||||
errors: [error instanceof Error ? error.message : "未知錯誤"],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
reader.onerror = () => {
|
||||
resolve({
|
||||
success: false,
|
||||
message: "檔案讀取失敗",
|
||||
errors: ["無法讀取檔案"],
|
||||
})
|
||||
}
|
||||
|
||||
reader.readAsArrayBuffer(file)
|
||||
})
|
||||
}
|
||||
|
||||
function parseLogicQuestions(data: any[][]): ImportResult {
|
||||
const errors: string[] = []
|
||||
const questions: LogicQuestionImport[] = []
|
||||
|
||||
// 跳過標題行
|
||||
for (let i = 1; i < data.length; i++) {
|
||||
const row = data[i]
|
||||
if (!row || row.length < 7) continue
|
||||
|
||||
try {
|
||||
const question: LogicQuestionImport = {
|
||||
id: Number.parseInt(row[0]) || i,
|
||||
question: row[1]?.toString() || "",
|
||||
optionA: row[2]?.toString() || "",
|
||||
optionB: row[3]?.toString() || "",
|
||||
optionC: row[4]?.toString() || "",
|
||||
optionD: row[5]?.toString() || "",
|
||||
correctAnswer: row[6]?.toString() || "",
|
||||
explanation: row[7]?.toString() || "",
|
||||
}
|
||||
|
||||
// 驗證必填欄位
|
||||
if (
|
||||
!question.question ||
|
||||
!question.optionA ||
|
||||
!question.optionB ||
|
||||
!question.optionC ||
|
||||
!question.optionD ||
|
||||
!question.correctAnswer
|
||||
) {
|
||||
errors.push(`第 ${i + 1} 行:缺少必填欄位`)
|
||||
continue
|
||||
}
|
||||
|
||||
// 驗證正確答案格式
|
||||
if (!["A", "B", "C", "D"].includes(question.correctAnswer.toUpperCase())) {
|
||||
errors.push(`第 ${i + 1} 行:正確答案必須是 A、B、C 或 D`)
|
||||
continue
|
||||
}
|
||||
|
||||
questions.push(question)
|
||||
} catch (error) {
|
||||
errors.push(`第 ${i + 1} 行:資料格式錯誤`)
|
||||
}
|
||||
}
|
||||
|
||||
if (questions.length === 0) {
|
||||
return {
|
||||
success: false,
|
||||
message: "沒有找到有效的題目資料",
|
||||
errors,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `成功解析 ${questions.length} 道題目`,
|
||||
data: questions,
|
||||
errors: errors.length > 0 ? errors : undefined,
|
||||
}
|
||||
}
|
||||
|
||||
function parseCreativeQuestions(data: any[][]): ImportResult {
|
||||
const errors: string[] = []
|
||||
const questions: CreativeQuestionImport[] = []
|
||||
|
||||
// 跳過標題行
|
||||
for (let i = 1; i < data.length; i++) {
|
||||
const row = data[i]
|
||||
if (!row || row.length < 4) continue
|
||||
|
||||
try {
|
||||
const question: CreativeQuestionImport = {
|
||||
id: Number.parseInt(row[0]) || i,
|
||||
statement: row[1]?.toString() || "",
|
||||
category: (row[2]?.toString().toLowerCase() as any) || "innovation",
|
||||
isReverse: row[3]?.toString().toLowerCase() === "是" || row[3]?.toString().toLowerCase() === "true",
|
||||
}
|
||||
|
||||
// 驗證必填欄位
|
||||
if (!question.statement) {
|
||||
errors.push(`第 ${i + 1} 行:缺少陳述內容`)
|
||||
continue
|
||||
}
|
||||
|
||||
// 驗證類別
|
||||
const validCategories = ["innovation", "imagination", "flexibility", "originality"]
|
||||
if (!validCategories.includes(question.category)) {
|
||||
errors.push(`第 ${i + 1} 行:類別必須是 innovation、imagination、flexibility 或 originality`)
|
||||
continue
|
||||
}
|
||||
|
||||
questions.push(question)
|
||||
} catch (error) {
|
||||
errors.push(`第 ${i + 1} 行:資料格式錯誤`)
|
||||
}
|
||||
}
|
||||
|
||||
if (questions.length === 0) {
|
||||
return {
|
||||
success: false,
|
||||
message: "沒有找到有效的題目資料",
|
||||
errors,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `成功解析 ${questions.length} 道題目`,
|
||||
data: questions,
|
||||
errors: errors.length > 0 ? errors : undefined,
|
||||
}
|
||||
}
|
54
lib/utils/permissions.ts
Normal file
54
lib/utils/permissions.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import type { User } from "@/lib/hooks/use-auth"
|
||||
|
||||
export type Permission =
|
||||
| "view_own_results"
|
||||
| "view_all_results"
|
||||
| "manage_users"
|
||||
| "view_analytics"
|
||||
| "take_tests"
|
||||
| "export_data"
|
||||
| "manage_questions" // 新增題目管理權限
|
||||
|
||||
export const rolePermissions: Record<User["role"], Permission[]> = {
|
||||
user: ["view_own_results", "take_tests"],
|
||||
admin: [
|
||||
"view_own_results",
|
||||
"view_all_results",
|
||||
"manage_users",
|
||||
"view_analytics",
|
||||
"take_tests",
|
||||
"export_data",
|
||||
"manage_questions",
|
||||
], // 為管理員新增題目管理權限
|
||||
}
|
||||
|
||||
export function hasPermission(user: User | null, permission: Permission): boolean {
|
||||
if (!user) return false
|
||||
return rolePermissions[user.role].includes(permission)
|
||||
}
|
||||
|
||||
export function requirePermission(user: User | null, permission: Permission): void {
|
||||
if (!hasPermission(user, permission)) {
|
||||
throw new Error(`權限不足:需要 ${permission} 權限`)
|
||||
}
|
||||
}
|
||||
|
||||
export function canAccessRoute(user: User | null, route: string): boolean {
|
||||
if (!user) return false
|
||||
|
||||
// 公開路由
|
||||
const publicRoutes = ["/", "/login", "/register"]
|
||||
if (publicRoutes.includes(route)) return true
|
||||
|
||||
// 用戶路由
|
||||
const userRoutes = ["/dashboard", "/tests", "/results", "/settings"]
|
||||
if (userRoutes.some((r) => route.startsWith(r))) return true
|
||||
|
||||
// 管理員路由
|
||||
const adminRoutes = ["/admin"]
|
||||
if (adminRoutes.some((r) => route.startsWith(r))) {
|
||||
return user.role === "admin"
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
188
lib/utils/score-calculator.ts
Normal file
188
lib/utils/score-calculator.ts
Normal file
@@ -0,0 +1,188 @@
|
||||
export interface TestScore {
|
||||
score: number
|
||||
level: string
|
||||
description: string
|
||||
color: string
|
||||
}
|
||||
|
||||
export function calculateLogicScore(correctAnswers: number, totalQuestions: number): TestScore {
|
||||
const score = Math.round((correctAnswers / totalQuestions) * 100)
|
||||
|
||||
if (score >= 90) {
|
||||
return {
|
||||
score,
|
||||
level: "优秀",
|
||||
color: "bg-green-500",
|
||||
description: "逻辑思维能力出色,具备卓越的分析和推理能力",
|
||||
}
|
||||
}
|
||||
if (score >= 80) {
|
||||
return {
|
||||
score,
|
||||
level: "良好",
|
||||
color: "bg-blue-500",
|
||||
description: "逻辑思维能力较强,能够有效分析和解决问题",
|
||||
}
|
||||
}
|
||||
if (score >= 70) {
|
||||
return {
|
||||
score,
|
||||
level: "中等",
|
||||
color: "bg-yellow-500",
|
||||
description: "逻辑思维能力一般,有一定的分析能力",
|
||||
}
|
||||
}
|
||||
if (score >= 60) {
|
||||
return {
|
||||
score,
|
||||
level: "及格",
|
||||
color: "bg-orange-500",
|
||||
description: "逻辑思维能力需要提升,建议加强训练",
|
||||
}
|
||||
}
|
||||
return {
|
||||
score,
|
||||
level: "不及格",
|
||||
color: "bg-red-500",
|
||||
description: "逻辑思维能力有待加强,需要系统性训练",
|
||||
}
|
||||
}
|
||||
|
||||
export function calculateCreativityScore(totalScore: number, maxScore: number): TestScore {
|
||||
const score = Math.round((totalScore / maxScore) * 100)
|
||||
|
||||
if (score >= 85) {
|
||||
return {
|
||||
score,
|
||||
level: "极具创意",
|
||||
color: "bg-purple-500",
|
||||
description: "拥有卓越的创新思维和想象力,能够产生独特的解决方案",
|
||||
}
|
||||
}
|
||||
if (score >= 75) {
|
||||
return {
|
||||
score,
|
||||
level: "很有创意",
|
||||
color: "bg-blue-500",
|
||||
description: "具备较强的创造性思维能力,善于创新",
|
||||
}
|
||||
}
|
||||
if (score >= 65) {
|
||||
return {
|
||||
score,
|
||||
level: "有一定创意",
|
||||
color: "bg-green-500",
|
||||
description: "具有一定的创新潜力,可以进一步培养",
|
||||
}
|
||||
}
|
||||
if (score >= 50) {
|
||||
return {
|
||||
score,
|
||||
level: "创意一般",
|
||||
color: "bg-yellow-500",
|
||||
description: "创造性思维有待提升,建议多参与创新活动",
|
||||
}
|
||||
}
|
||||
return {
|
||||
score,
|
||||
level: "缺乏创意",
|
||||
color: "bg-red-500",
|
||||
description: "需要培养创新思维能力,建议接受创意思维训练",
|
||||
}
|
||||
}
|
||||
|
||||
export function calculateCombinedScore(
|
||||
logicScore: number,
|
||||
creativityScore: number,
|
||||
): {
|
||||
overallScore: number
|
||||
level: string
|
||||
description: string
|
||||
color: string
|
||||
breakdown: {
|
||||
logic: number
|
||||
creativity: number
|
||||
balance: number
|
||||
}
|
||||
} {
|
||||
// 综合分数:逻辑40% + 创意40% + 平衡性20%
|
||||
const logicWeight = 0.4
|
||||
const creativityWeight = 0.4
|
||||
const balanceWeight = 0.2
|
||||
|
||||
// 计算平衡性分数(两项分数越接近,平衡性越高)
|
||||
const scoreDiff = Math.abs(logicScore - creativityScore)
|
||||
const balanceScore = Math.max(0, 100 - scoreDiff * 2)
|
||||
|
||||
const overallScore = Math.round(
|
||||
logicScore * logicWeight + creativityScore * creativityWeight + balanceScore * balanceWeight,
|
||||
)
|
||||
|
||||
let level: string
|
||||
let description: string
|
||||
let color: string
|
||||
|
||||
if (overallScore >= 90) {
|
||||
level = "卓越"
|
||||
color = "bg-gradient-to-r from-purple-500 to-blue-500"
|
||||
description = "综合能力卓越,逻辑思维与创意能力并重,是理想的复合型人才"
|
||||
} else if (overallScore >= 80) {
|
||||
level = "优秀"
|
||||
color = "bg-gradient-to-r from-blue-500 to-green-500"
|
||||
description = "综合能力优秀,在逻辑思维和创意能力方面都有良好表现"
|
||||
} else if (overallScore >= 70) {
|
||||
level = "良好"
|
||||
color = "bg-gradient-to-r from-green-500 to-yellow-500"
|
||||
description = "综合能力良好,具备一定的逻辑思维和创意能力"
|
||||
} else if (overallScore >= 60) {
|
||||
level = "中等"
|
||||
color = "bg-gradient-to-r from-yellow-500 to-orange-500"
|
||||
description = "综合能力中等,建议针对性提升薄弱环节"
|
||||
} else {
|
||||
level = "待提升"
|
||||
color = "bg-gradient-to-r from-orange-500 to-red-500"
|
||||
description = "综合能力有待提升,建议系统性训练逻辑思维和创意能力"
|
||||
}
|
||||
|
||||
return {
|
||||
overallScore,
|
||||
level,
|
||||
description,
|
||||
color,
|
||||
breakdown: {
|
||||
logic: logicScore,
|
||||
creativity: creativityScore,
|
||||
balance: Math.round(balanceScore),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function getRecommendations(logicScore: number, creativityScore: number): string[] {
|
||||
const recommendations: string[] = []
|
||||
|
||||
if (logicScore < 70) {
|
||||
recommendations.push("建议加强逻辑思维训练,多做推理题和数学题")
|
||||
recommendations.push("学习系统性思维方法,如思维导图、流程图等")
|
||||
}
|
||||
|
||||
if (creativityScore < 70) {
|
||||
recommendations.push("建议参与更多创意活动,如头脑风暴、设计思维工作坊")
|
||||
recommendations.push("培养好奇心,多接触不同领域的知识和经验")
|
||||
}
|
||||
|
||||
const scoreDiff = Math.abs(logicScore - creativityScore)
|
||||
if (scoreDiff > 20) {
|
||||
if (logicScore > creativityScore) {
|
||||
recommendations.push("您的逻辑思维较强,建议平衡发展创意能力")
|
||||
} else {
|
||||
recommendations.push("您的创意能力较强,建议平衡发展逻辑思维")
|
||||
}
|
||||
}
|
||||
|
||||
if (logicScore >= 80 && creativityScore >= 80) {
|
||||
recommendations.push("您具备优秀的综合能力,建议承担更多挑战性工作")
|
||||
recommendations.push("可以考虑担任需要创新和分析并重的领导角色")
|
||||
}
|
||||
|
||||
return recommendations
|
||||
}
|
Reference in New Issue
Block a user