chore: 基本服务器版本完成
This commit is contained in:
@@ -1,450 +1,155 @@
|
||||
// 模拟数据 - 个人排名
|
||||
export const individualRankings = [
|
||||
{
|
||||
id: 1,
|
||||
name: '张三',
|
||||
score: 985,
|
||||
level: 'SSS',
|
||||
avatar: '👑',
|
||||
department: '销售部',
|
||||
completedTasks: 48,
|
||||
bonus: 5000
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '李四',
|
||||
score: 972,
|
||||
level: 'SSS',
|
||||
avatar: '🥇',
|
||||
department: '技术部',
|
||||
completedTasks: 45,
|
||||
bonus: 3000
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '王五',
|
||||
score: 958,
|
||||
level: 'SS',
|
||||
avatar: '🥈',
|
||||
department: '市场部',
|
||||
completedTasks: 42,
|
||||
bonus: 2000
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '赵六',
|
||||
score: 923,
|
||||
level: 'SS',
|
||||
avatar: '🥉',
|
||||
department: '财务部',
|
||||
completedTasks: 40,
|
||||
bonus: 1500
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: '钱七',
|
||||
score: 897,
|
||||
level: 'S',
|
||||
avatar: '⭐',
|
||||
department: '人力资源部',
|
||||
completedTasks: 38,
|
||||
bonus: 1000
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: '孙八',
|
||||
score: 876,
|
||||
level: 'S',
|
||||
avatar: '⭐',
|
||||
department: '销售部',
|
||||
completedTasks: 36,
|
||||
bonus: 1000
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: '周九',
|
||||
score: 854,
|
||||
level: 'A',
|
||||
avatar: '🔥',
|
||||
department: '技术部',
|
||||
completedTasks: 34,
|
||||
bonus: 800
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: '吴十',
|
||||
score: 832,
|
||||
level: 'A',
|
||||
avatar: '🔥',
|
||||
department: '市场部',
|
||||
completedTasks: 32,
|
||||
bonus: 800
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: '郑十一',
|
||||
score: 810,
|
||||
level: 'B',
|
||||
avatar: '⚡',
|
||||
department: '财务部',
|
||||
completedTasks: 30,
|
||||
bonus: 500
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: '王十二',
|
||||
score: 795,
|
||||
level: 'B',
|
||||
avatar: '⚡',
|
||||
department: '人力资源部',
|
||||
completedTasks: 28,
|
||||
bonus: 500
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: '李十三',
|
||||
score: 782,
|
||||
level: 'B',
|
||||
avatar: '⚡',
|
||||
department: '销售部',
|
||||
completedTasks: 26,
|
||||
bonus: 500
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: '张十四',
|
||||
score: 765,
|
||||
level: 'B',
|
||||
avatar: '⚡',
|
||||
department: '技术部',
|
||||
completedTasks: 24,
|
||||
bonus: 500
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
name: '王十五',
|
||||
score: 748,
|
||||
level: 'B',
|
||||
avatar: '⚡',
|
||||
department: '市场部',
|
||||
completedTasks: 22,
|
||||
bonus: 500
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
name: '赵十六',
|
||||
score: 732,
|
||||
level: 'C',
|
||||
avatar: '🎯',
|
||||
department: '财务部',
|
||||
completedTasks: 20,
|
||||
bonus: 300
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
name: '钱十七',
|
||||
score: 715,
|
||||
level: 'C',
|
||||
avatar: '🎯',
|
||||
department: '人力资源部',
|
||||
completedTasks: 18,
|
||||
bonus: 300
|
||||
}
|
||||
import {
|
||||
getIndividualRankings,
|
||||
saveIndividualRankings as saveIndividualRankingsToConfig,
|
||||
getTeamRankings,
|
||||
saveTeamRankings as saveTeamRankingsToConfig,
|
||||
getSystemUsers,
|
||||
saveSystemUsers as saveSystemUsersToConfig,
|
||||
addSystemUser as addSystemUserToConfig,
|
||||
deleteSystemUser as deleteSystemUserToConfig,
|
||||
updateSystemUser as updateSystemUserToConfig,
|
||||
getDisplayConfig,
|
||||
saveDisplayConfig as saveDisplayConfigToConfig,
|
||||
getBattleEndTime,
|
||||
saveBattleEndTime as saveBattleEndTimeToConfig,
|
||||
getDrumConfig,
|
||||
saveDrumConfig as saveDrumConfigToConfig,
|
||||
getBonusRules,
|
||||
saveBonusRules as saveBonusRulesToConfig
|
||||
} from '../services/configService';
|
||||
|
||||
// 初始化数据
|
||||
export let individualRankings = getIndividualRankings();
|
||||
export let teamRankings = getTeamRankings();
|
||||
export let bonusRules = getBonusRules() || [
|
||||
{ rank: '1-3', description: '前三名', individualBonus: '¥10000, ¥8000, ¥5000', teamBonus: '¥50000, ¥30000, ¥20000' },
|
||||
{ rank: '4-10', description: '四至十名', individualBonus: '¥3000/人', teamBonus: '¥10000/队' },
|
||||
{ rank: '11-20', description: '十一至二十名', individualBonus: '¥1000/人', teamBonus: '¥5000/队' }
|
||||
];
|
||||
|
||||
// 模拟数据 - 战队排名
|
||||
export const teamRankings = [
|
||||
{
|
||||
id: 1,
|
||||
name: '王者之师',
|
||||
totalScore: 4850,
|
||||
memberCount: 5,
|
||||
level: 'SSS',
|
||||
leader: '张三',
|
||||
completedTasks: 210,
|
||||
bonus: 15000
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '战无不胜',
|
||||
totalScore: 4680,
|
||||
memberCount: 5,
|
||||
level: 'SS',
|
||||
leader: '李四',
|
||||
completedTasks: 198,
|
||||
bonus: 10000
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '超越极限',
|
||||
totalScore: 4520,
|
||||
memberCount: 5,
|
||||
level: 'SS',
|
||||
leader: '王五',
|
||||
completedTasks: 185,
|
||||
bonus: 8000
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '精英战队',
|
||||
totalScore: 4280,
|
||||
memberCount: 5,
|
||||
level: 'S',
|
||||
leader: '赵六',
|
||||
completedTasks: 172,
|
||||
bonus: 6000
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: '梦想之巅',
|
||||
totalScore: 4150,
|
||||
memberCount: 5,
|
||||
level: 'S',
|
||||
leader: '钱七',
|
||||
completedTasks: 165,
|
||||
bonus: 6000
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: '无敌战队',
|
||||
totalScore: 3980,
|
||||
memberCount: 5,
|
||||
level: 'A',
|
||||
leader: '孙八',
|
||||
completedTasks: 155,
|
||||
bonus: 4000
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: '冲锋陷阵',
|
||||
totalScore: 3850,
|
||||
memberCount: 5,
|
||||
level: 'A',
|
||||
leader: '周九',
|
||||
completedTasks: 148,
|
||||
bonus: 4000
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: '锐不可当',
|
||||
totalScore: 3720,
|
||||
memberCount: 5,
|
||||
level: 'A',
|
||||
leader: '吴十',
|
||||
completedTasks: 142,
|
||||
bonus: 4000
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: '同心协力',
|
||||
totalScore: 3600,
|
||||
memberCount: 5,
|
||||
level: 'B',
|
||||
leader: '郑十一',
|
||||
completedTasks: 135,
|
||||
bonus: 2000
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: '众志成城',
|
||||
totalScore: 3480,
|
||||
memberCount: 5,
|
||||
level: 'B',
|
||||
leader: '王十二',
|
||||
completedTasks: 128,
|
||||
bonus: 2000
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: '气势如虹',
|
||||
totalScore: 3350,
|
||||
memberCount: 5,
|
||||
level: 'B',
|
||||
leader: '李十三',
|
||||
completedTasks: 122,
|
||||
bonus: 2000
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: '披荆斩棘',
|
||||
totalScore: 3220,
|
||||
memberCount: 5,
|
||||
level: 'B',
|
||||
leader: '张十四',
|
||||
completedTasks: 115,
|
||||
bonus: 2000
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
name: '勇攀高峰',
|
||||
totalScore: 3100,
|
||||
memberCount: 5,
|
||||
level: 'C',
|
||||
leader: '王十五',
|
||||
completedTasks: 108,
|
||||
bonus: 1000
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
name: '力争上游',
|
||||
totalScore: 2980,
|
||||
memberCount: 5,
|
||||
level: 'C',
|
||||
leader: '赵十六',
|
||||
completedTasks: 102,
|
||||
bonus: 1000
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
name: '蓄势待发',
|
||||
totalScore: 2850,
|
||||
memberCount: 5,
|
||||
level: 'C',
|
||||
leader: '钱十七',
|
||||
completedTasks: 95,
|
||||
bonus: 1000
|
||||
}
|
||||
];
|
||||
|
||||
// 奖金设置说明
|
||||
export const bonusRules = [
|
||||
{
|
||||
rank: '1-3',
|
||||
individualBonus: '5000元, 3000元, 2000元',
|
||||
teamBonus: '15000元, 10000元, 8000元',
|
||||
description: '顶尖表现,高额奖励'
|
||||
},
|
||||
{
|
||||
rank: '4-6',
|
||||
individualBonus: '1500元, 1000元, 1000元',
|
||||
teamBonus: '6000元, 6000元',
|
||||
description: '优秀表现,丰厚激励'
|
||||
},
|
||||
{
|
||||
rank: '7-10',
|
||||
individualBonus: '800元, 800元, 500元, 500元',
|
||||
teamBonus: '无',
|
||||
description: '良好表现,基础奖励'
|
||||
}
|
||||
];
|
||||
|
||||
// 系统用户(用于后台登录)
|
||||
export const systemUsers = [
|
||||
{
|
||||
username: 'admin',
|
||||
password: 'admin123',
|
||||
role: 'admin'
|
||||
},
|
||||
{
|
||||
username: 'manager',
|
||||
password: 'manager123',
|
||||
role: 'manager'
|
||||
}
|
||||
];
|
||||
|
||||
// 显示配置
|
||||
export const displayConfig = {
|
||||
// 个人排名显示配置
|
||||
individual: {
|
||||
showLevel: false, // 显示等级列
|
||||
showDepartment: false, // 显示部门列
|
||||
scoreColumn: {
|
||||
displayName: '签单金额', // 列显示名称
|
||||
displayStyle: 'amount' // 显示样式: 'amount'(金额) 或 'number'(普通数字)
|
||||
},
|
||||
columnWidths: {
|
||||
rank: 60, // 排名列宽度
|
||||
avatar: 60, // 头像列宽度
|
||||
name: 1, // 姓名列宽度(1表示自动填充)
|
||||
score: 80, // 分数列宽度
|
||||
level: 80, // 等级列宽度
|
||||
department: 1, // 部门列宽度(1表示自动填充)
|
||||
bonus: 80 // 奖金列宽度
|
||||
}
|
||||
},
|
||||
// 战队排名显示配置
|
||||
team: {
|
||||
showMemberCount: false, // 显示人数列
|
||||
showLeader: false, // 显示队长列
|
||||
totalScoreColumn: {
|
||||
displayName: '签单金额', // 列显示名称
|
||||
displayStyle: 'amount' // 显示样式: 'amount'(金额) 或 'number'(普通数字)
|
||||
},
|
||||
columnWidths: {
|
||||
rank: 60, // 排名列宽度
|
||||
name: 1, // 战队名列宽度(1表示自动填充)
|
||||
score: 80, // 分数列宽度
|
||||
memberCount: 60, // 人数列宽度
|
||||
leader: 1, // 队长列宽度(1表示自动填充)
|
||||
bonus: 80 // 奖金列宽度
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 结束时间配置(精确到秒)
|
||||
export let battleEndTime = {
|
||||
date: '2026-02-01',
|
||||
time: '23:59:59'
|
||||
};
|
||||
|
||||
// 战鼓参数配置
|
||||
export let drumConfig = {
|
||||
// 音效参数
|
||||
sound: {
|
||||
volume: 1.0, // 音量 0-1
|
||||
frequency1: 150, // 第一个音调频率
|
||||
frequency2: 100, // 第二个音调频率
|
||||
attackTime: 0.01, // 起音时间
|
||||
decayTime: 0.3, // 衰减时间
|
||||
type1: 'sine', // 第一个振荡器类型
|
||||
type2: 'triangle' // 第二个振荡器类型
|
||||
},
|
||||
// 动画参数
|
||||
animation: {
|
||||
beatInterval: 200, // 节拍间隔(毫秒)
|
||||
beatScale: 1.3, // 跳动缩放比例
|
||||
beatTranslateY: -15, // 跳动上下位移
|
||||
beatRotate: 5, // 跳动旋转角度
|
||||
idlePulseDuration: 2, // 闲置脉动持续时间
|
||||
beatDuration: 100 // 单次跳动持续时间
|
||||
},
|
||||
// 节拍模式
|
||||
pattern: {
|
||||
strongBeats: [1, 4], // 强拍位置(1-4拍)
|
||||
totalBeats: 4 // 每小节总拍数
|
||||
}
|
||||
};
|
||||
export let systemUsers = getSystemUsers();
|
||||
export let displayConfig = getDisplayConfig();
|
||||
export let battleEndTime = getBattleEndTime();
|
||||
export let drumConfig = getDrumConfig();
|
||||
|
||||
// 保存结束时间
|
||||
export const saveBattleEndTime = (endTime) => {
|
||||
battleEndTime = endTime;
|
||||
export const saveBattleEndTime = async (endTime) => {
|
||||
battleEndTime = { ...endTime };
|
||||
console.log('保存结束时间:', battleEndTime);
|
||||
return await saveBattleEndTimeToConfig(endTime);
|
||||
};
|
||||
|
||||
// 保存数据的方法(模拟本地存储)
|
||||
export const saveIndividualRankings = (data) => {
|
||||
// 这里只是模拟,实际项目中可以考虑使用localStorage或后端API
|
||||
// 保存个人排名数据
|
||||
export const saveIndividualRankings = async (data) => {
|
||||
individualRankings = [...data];
|
||||
console.log('保存个人排名数据:', data);
|
||||
// 在真实环境中,可以调用API保存数据
|
||||
return await saveIndividualRankingsToConfig(data);
|
||||
};
|
||||
|
||||
export const saveTeamRankings = (data) => {
|
||||
// 这里只是模拟,实际项目中可以考虑使用localStorage或后端API
|
||||
// 保存战队排名数据
|
||||
export const saveTeamRankings = async (data) => {
|
||||
teamRankings = [...data];
|
||||
console.log('保存战队排名数据:', data);
|
||||
// 在真实环境中,可以调用API保存数据
|
||||
return await saveTeamRankingsToConfig(data);
|
||||
};
|
||||
|
||||
// 保存显示配置
|
||||
export const saveDisplayConfig = (config) => {
|
||||
// 这里只是模拟,实际项目中可以考虑使用localStorage或后端API
|
||||
export const saveDisplayConfig = async (config) => {
|
||||
displayConfig = { ...config };
|
||||
console.log('保存显示配置:', config);
|
||||
// 在真实环境中,可以调用API保存数据
|
||||
return await saveDisplayConfigToConfig(config);
|
||||
};
|
||||
|
||||
// 保存战鼓配置
|
||||
export const saveDrumConfig = (config) => {
|
||||
// 这里只是模拟,实际项目中可以考虑使用localStorage或后端API
|
||||
export const saveDrumConfig = async (config) => {
|
||||
console.log('保存战鼓配置:', config);
|
||||
drumConfig = { ...drumConfig, ...config };
|
||||
// 在真实环境中,可以调用API保存数据
|
||||
return await saveDrumConfigToConfig(drumConfig);
|
||||
};
|
||||
|
||||
// 保存奖金规则
|
||||
export const saveBonusRules = async (rules) => {
|
||||
bonusRules = [...rules];
|
||||
console.log('保存奖金规则:', rules);
|
||||
return await saveBonusRulesToConfig(rules);
|
||||
};
|
||||
|
||||
// 验证用户登录
|
||||
export const validateUser = (username, password) => {
|
||||
return systemUsers.find(user => user.username === username && user.password === password);
|
||||
};
|
||||
|
||||
// 初始化数据(异步版本,用于应用启动时加载数据)
|
||||
export const initializeData = async () => {
|
||||
try {
|
||||
await refreshData();
|
||||
console.log('数据初始化成功');
|
||||
} catch (error) {
|
||||
console.error('数据初始化失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 刷新数据
|
||||
export const refreshData = async () => {
|
||||
try {
|
||||
individualRankings = await getIndividualRankings();
|
||||
teamRankings = await getTeamRankings();
|
||||
bonusRules = await getBonusRules() || [
|
||||
{ rank: '1-3', description: '前三名', individualBonus: '¥10000, ¥8000, ¥5000', teamBonus: '¥50000, ¥30000, ¥20000' },
|
||||
{ rank: '4-10', description: '四至十名', individualBonus: '¥3000/人', teamBonus: '¥10000/队' },
|
||||
{ rank: '11-20', description: '十一至二十名', individualBonus: '¥1000/人', teamBonus: '¥5000/队' }
|
||||
];
|
||||
systemUsers = await getSystemUsers();
|
||||
displayConfig = await getDisplayConfig();
|
||||
battleEndTime = await getBattleEndTime();
|
||||
drumConfig = await getDrumConfig();
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('刷新数据失败:', error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 添加系统用户
|
||||
export const addSystemUser = async (user) => {
|
||||
try {
|
||||
const result = await addSystemUserToConfig(user);
|
||||
if (result) {
|
||||
// 刷新用户列表
|
||||
systemUsers = await getSystemUsers();
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('添加用户失败:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// 删除系统用户
|
||||
export const deleteSystemUser = async (userId) => {
|
||||
try {
|
||||
const result = await deleteSystemUserToConfig(userId);
|
||||
if (result) {
|
||||
// 刷新用户列表
|
||||
systemUsers = await getSystemUsers();
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('删除用户失败:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// 更新系统用户
|
||||
export const updateSystemUser = async (userId, updatedData) => {
|
||||
try {
|
||||
const result = await updateSystemUserToConfig(userId, updatedData);
|
||||
if (result) {
|
||||
// 刷新用户列表
|
||||
systemUsers = await getSystemUsers();
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('更新用户失败:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
325
src/services/configService.js
Normal file
325
src/services/configService.js
Normal file
@@ -0,0 +1,325 @@
|
||||
// 配置文件API路径
|
||||
const CONFIG_API_URL = '/api/config';
|
||||
|
||||
/**
|
||||
* 读取配置文件
|
||||
* @returns {Object} 配置数据
|
||||
*/
|
||||
export const readConfig = async () => {
|
||||
try {
|
||||
const response = await fetch(CONFIG_API_URL);
|
||||
if (response.ok) {
|
||||
return await response.json();
|
||||
} else if (response.status === 404) {
|
||||
// 配置文件不存在,使用默认配置
|
||||
console.log('配置文件不存在,使用默认配置');
|
||||
return getDefaultConfig();
|
||||
}
|
||||
throw new Error(`获取配置失败: ${response.status}`);
|
||||
} catch (error) {
|
||||
console.error('读取配置失败:', error);
|
||||
return getDefaultConfig();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 写入配置文件
|
||||
* @param {Object} config 新的配置数据
|
||||
* @returns {boolean} 是否写入成功
|
||||
*/
|
||||
export const writeConfig = async (config) => {
|
||||
try {
|
||||
const response = await fetch(CONFIG_API_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(config)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const result = await response.json();
|
||||
return result.success;
|
||||
}
|
||||
|
||||
throw new Error(`保存配置失败: ${response.status}`);
|
||||
} catch (error) {
|
||||
console.error('写入配置失败:', error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 同步版本的readConfig(用于向后兼容)
|
||||
export const getConfig = async () => {
|
||||
return await readConfig();
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取默认配置(用于兜底)
|
||||
* @returns {Object} 默认配置
|
||||
*/
|
||||
const getDefaultConfig = () => ({
|
||||
individualRankings: [],
|
||||
teamRankings: [],
|
||||
bonusRules: [],
|
||||
systemUsers: [],
|
||||
displayConfig: {
|
||||
individual: {
|
||||
showLevel: false,
|
||||
showDepartment: false,
|
||||
scoreColumn: {
|
||||
displayName: '分数',
|
||||
displayStyle: 'number'
|
||||
},
|
||||
columnWidths: {}
|
||||
},
|
||||
team: {
|
||||
showMemberCount: false,
|
||||
showLeader: false,
|
||||
totalScoreColumn: {
|
||||
displayName: '总分',
|
||||
displayStyle: 'number'
|
||||
},
|
||||
columnWidths: {}
|
||||
}
|
||||
},
|
||||
battleEndTime: {
|
||||
date: new Date().toISOString().split('T')[0],
|
||||
time: '23:59:59'
|
||||
},
|
||||
drumConfig: {
|
||||
sound: {
|
||||
volume: 1.0,
|
||||
enabled: false
|
||||
},
|
||||
animation: {
|
||||
enabled: false
|
||||
},
|
||||
pattern: {
|
||||
strongBeats: [1],
|
||||
totalBeats: 4
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取个人排名数据
|
||||
* @returns {Array} 个人排名数组
|
||||
*/
|
||||
export const getIndividualRankings = async () => {
|
||||
const config = await readConfig();
|
||||
return config.individualRankings || [];
|
||||
};
|
||||
|
||||
/**
|
||||
* 保存个人排名数据
|
||||
* @param {Array} rankings 个人排名数组
|
||||
* @returns {boolean} 是否保存成功
|
||||
*/
|
||||
export const saveIndividualRankings = async (rankings) => {
|
||||
const config = await readConfig();
|
||||
config.individualRankings = rankings;
|
||||
return await writeConfig(config);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取战队排名数据
|
||||
* @returns {Array} 战队排名数组
|
||||
*/
|
||||
export const getTeamRankings = async () => {
|
||||
const config = await readConfig();
|
||||
return config.teamRankings || [];
|
||||
};
|
||||
|
||||
/**
|
||||
* 保存战队排名数据
|
||||
* @param {Array} rankings 战队排名数组
|
||||
* @returns {boolean} 是否保存成功
|
||||
*/
|
||||
export const saveTeamRankings = async (rankings) => {
|
||||
const config = await readConfig();
|
||||
config.teamRankings = rankings;
|
||||
return await writeConfig(config);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取奖金规则
|
||||
* @returns {Array} 奖金规则数组
|
||||
*/
|
||||
export const getBonusRules = async () => {
|
||||
const config = await readConfig();
|
||||
return config.bonusRules || [];
|
||||
};
|
||||
|
||||
/**
|
||||
* 保存奖金规则
|
||||
* @param {Array} rules 奖金规则数组
|
||||
* @returns {boolean} 是否保存成功
|
||||
*/
|
||||
export const saveBonusRules = async (rules) => {
|
||||
const config = await readConfig();
|
||||
config.bonusRules = rules;
|
||||
return await writeConfig(config);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取系统用户
|
||||
* @returns {Array} 系统用户数组
|
||||
*/
|
||||
export const getSystemUsers = async () => {
|
||||
const config = await readConfig();
|
||||
return config.systemUsers || [];
|
||||
};
|
||||
|
||||
/**
|
||||
* 保存系统用户
|
||||
* @param {Array} users 系统用户数组
|
||||
* @returns {boolean} 是否保存成功
|
||||
*/
|
||||
export const saveSystemUsers = async (users) => {
|
||||
const config = await readConfig();
|
||||
config.systemUsers = users;
|
||||
return await writeConfig(config);
|
||||
};
|
||||
|
||||
/**
|
||||
* 添加用户
|
||||
* @param {Object} user 用户信息
|
||||
* @returns {boolean} 是否添加成功
|
||||
*/
|
||||
export const addSystemUser = async (user) => {
|
||||
try {
|
||||
const users = await getSystemUsers();
|
||||
// 检查用户名是否已存在
|
||||
const existingUser = users.find(u => u.username === user.username);
|
||||
if (existingUser) {
|
||||
throw new Error('用户名已存在');
|
||||
}
|
||||
|
||||
users.push({
|
||||
id: Date.now(),
|
||||
...user
|
||||
});
|
||||
|
||||
return await saveSystemUsers(users);
|
||||
} catch (error) {
|
||||
console.error('添加用户失败:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
* @param {number} userId 用户ID
|
||||
* @returns {boolean} 是否删除成功
|
||||
*/
|
||||
export const deleteSystemUser = async (userId) => {
|
||||
try {
|
||||
let users = await getSystemUsers();
|
||||
// 确保至少保留一个管理员用户
|
||||
if (users.length <= 1) {
|
||||
throw new Error('系统至少需要保留一个管理员用户');
|
||||
}
|
||||
|
||||
users = users.filter(u => u.id !== userId);
|
||||
return await saveSystemUsers(users);
|
||||
} catch (error) {
|
||||
console.error('删除用户失败:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新用户信息
|
||||
* @param {number} userId 用户ID
|
||||
* @param {Object} updatedData 更新的数据
|
||||
* @returns {boolean} 是否更新成功
|
||||
*/
|
||||
export const updateSystemUser = async (userId, updatedData) => {
|
||||
try {
|
||||
const users = await getSystemUsers();
|
||||
const userIndex = users.findIndex(u => u.id === userId);
|
||||
|
||||
if (userIndex === -1) {
|
||||
throw new Error('用户不存在');
|
||||
}
|
||||
|
||||
// 如果要更新用户名,检查是否与其他用户冲突
|
||||
if (updatedData.username && updatedData.username !== users[userIndex].username) {
|
||||
const existingUser = users.find(u => u.id !== userId && u.username === updatedData.username);
|
||||
if (existingUser) {
|
||||
throw new Error('用户名已存在');
|
||||
}
|
||||
}
|
||||
|
||||
users[userIndex] = {
|
||||
...users[userIndex],
|
||||
...updatedData
|
||||
};
|
||||
|
||||
return await saveSystemUsers(users);
|
||||
} catch (error) {
|
||||
console.error('更新用户失败:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取显示配置
|
||||
* @returns {Object} 显示配置
|
||||
*/
|
||||
export const getDisplayConfig = async () => {
|
||||
const config = await readConfig();
|
||||
return config.displayConfig || {};
|
||||
};
|
||||
|
||||
/**
|
||||
* 保存显示配置
|
||||
* @param {Object} displayConfig 显示配置
|
||||
* @returns {boolean} 是否保存成功
|
||||
*/
|
||||
export const saveDisplayConfig = async (displayConfig) => {
|
||||
const config = await readConfig();
|
||||
config.displayConfig = displayConfig;
|
||||
return await writeConfig(config);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取战斗结束时间
|
||||
* @returns {Object} 结束时间配置
|
||||
*/
|
||||
export const getBattleEndTime = async () => {
|
||||
const config = await readConfig();
|
||||
return config.battleEndTime || {};
|
||||
};
|
||||
|
||||
/**
|
||||
* 保存战斗结束时间
|
||||
* @param {Object} endTime 结束时间配置
|
||||
* @returns {boolean} 是否保存成功
|
||||
*/
|
||||
export const saveBattleEndTime = async (endTime) => {
|
||||
const config = await readConfig();
|
||||
config.battleEndTime = endTime;
|
||||
return await writeConfig(config);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取战鼓配置
|
||||
* @returns {Object} 战鼓配置
|
||||
*/
|
||||
export const getDrumConfig = async () => {
|
||||
const config = await readConfig();
|
||||
return config.drumConfig || {};
|
||||
};
|
||||
|
||||
/**
|
||||
* 保存战鼓配置
|
||||
* @param {Object} drumConfig 战鼓配置
|
||||
* @returns {boolean} 是否保存成功
|
||||
*/
|
||||
export const saveDrumConfig = async (drumConfig) => {
|
||||
const config = await readConfig();
|
||||
config.drumConfig = drumConfig;
|
||||
return await writeConfig(config);
|
||||
};
|
||||
47
src/services/testConfig.js
Normal file
47
src/services/testConfig.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import { getConfig, writeConfig } from './configService.js';
|
||||
|
||||
// 测试配置服务功能
|
||||
const testConfigService = async () => {
|
||||
try {
|
||||
console.log('开始测试配置服务...');
|
||||
|
||||
// 读取配置
|
||||
const config = await getConfig();
|
||||
console.log('成功读取配置:', {
|
||||
hasIndividualRankings: config.individualRankings?.length > 0,
|
||||
hasTeamRankings: config.teamRankings?.length > 0,
|
||||
hasSystemUsers: config.systemUsers?.length > 0,
|
||||
hasDisplayConfig: !!config.displayConfig,
|
||||
hasBattleEndTime: !!config.battleEndTime,
|
||||
hasDrumConfig: !!config.drumConfig
|
||||
});
|
||||
|
||||
// 写入配置(添加一个小的修改然后恢复)
|
||||
const testKey = 'test_timestamp';
|
||||
const originalValue = config[testKey];
|
||||
|
||||
config[testKey] = Date.now();
|
||||
await writeConfig(config);
|
||||
console.log('成功写入配置修改');
|
||||
|
||||
// 验证修改已保存
|
||||
const updatedConfig = await getConfig();
|
||||
console.log('修改验证成功:', updatedConfig[testKey] === config[testKey]);
|
||||
|
||||
// 恢复原始状态
|
||||
if (originalValue === undefined) {
|
||||
delete updatedConfig[testKey];
|
||||
} else {
|
||||
updatedConfig[testKey] = originalValue;
|
||||
}
|
||||
await writeConfig(updatedConfig);
|
||||
console.log('成功恢复原始配置');
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('配置服务测试失败:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
};
|
||||
|
||||
export default testConfigService;
|
||||
@@ -35,9 +35,10 @@
|
||||
<div class="top-nav">
|
||||
<h1 class="nav-title">📊 百人大战管理系统</h1>
|
||||
<div class="nav-actions">
|
||||
<span class="welcome-text">欢迎您,{{ currentUser.username }}!</span>
|
||||
<button @click="logout" class="logout-btn">退出登录</button>
|
||||
</div>
|
||||
<span class="welcome-text">欢迎您,{{ currentUser.username }}!</span>
|
||||
<button @click="handleRefreshData" class="refresh-btn" style="margin-right: 10px;">刷新数据</button>
|
||||
<button @click="logout" class="logout-btn">退出登录</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 功能选项卡 -->
|
||||
@@ -319,6 +320,44 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 奖金设置 -->
|
||||
<div v-if="currentTab === 'bonus'" class="bonus-config-content">
|
||||
<h2 class="config-title">🎯 奖金设置</h2>
|
||||
<div class="config-section">
|
||||
<h3>🏆 奖金规则配置</h3>
|
||||
<div class="bonus-rules-list">
|
||||
<div
|
||||
v-for="(rule, index) in localBonusRules"
|
||||
:key="index"
|
||||
class="bonus-rule-item"
|
||||
>
|
||||
<div class="rule-form">
|
||||
<div class="form-group">
|
||||
<label>名次范围:</label>
|
||||
<input v-model="rule.rank" type="text" class="form-input" placeholder="如: 1-3">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>规则描述:</label>
|
||||
<input v-model="rule.description" type="text" class="form-input" placeholder="如: 前三名">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>个人奖励:</label>
|
||||
<input v-model="rule.individualBonus" type="text" class="form-input" placeholder="如: ¥10000, ¥8000, ¥5000">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>团队奖励:</label>
|
||||
<input v-model="rule.teamBonus" type="text" class="form-input" placeholder="如: ¥50000, ¥30000, ¥20000">
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button @click="deleteBonusRule(index)" class="delete-btn">🗑️ 删除</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button @click="addBonusRule" class="add-btn" style="margin-top: 20px;">➕ 添加奖金规则</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 战鼓配置 -->
|
||||
<div v-if="currentTab === 'drum'" class="drum-config-content">
|
||||
<h2 class="config-title">🥁 战鼓配置管理</h2>
|
||||
@@ -652,20 +691,24 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import {
|
||||
individualRankings,
|
||||
teamRankings,
|
||||
systemUsers,
|
||||
saveIndividualRankings,
|
||||
import {
|
||||
individualRankings,
|
||||
teamRankings,
|
||||
systemUsers,
|
||||
bonusRules,
|
||||
saveIndividualRankings,
|
||||
saveTeamRankings,
|
||||
saveBonusRules,
|
||||
displayConfig,
|
||||
saveDisplayConfig,
|
||||
battleEndTime,
|
||||
saveBattleEndTime,
|
||||
drumConfig,
|
||||
saveDrumConfig
|
||||
saveDrumConfig,
|
||||
refreshData,
|
||||
initializeData
|
||||
} from '../data/mockData.js';
|
||||
|
||||
const router = useRouter();
|
||||
@@ -688,21 +731,80 @@ const currentUser = ref({});
|
||||
const tabs = [
|
||||
{ key: 'individual', label: '个人排名' },
|
||||
{ key: 'team', label: '战队排名' },
|
||||
{ key: 'bonus', label: '奖金设置' },
|
||||
{ key: 'config', label: '显示配置' },
|
||||
{ key: 'endTime', label: '结束时间设置' },
|
||||
{ key: 'drum', label: '战鼓配置' }
|
||||
];
|
||||
|
||||
// 刷新数据
|
||||
const handleRefreshData = () => {
|
||||
try {
|
||||
const success = refreshData();
|
||||
// 重新加载本地数据副本
|
||||
localIndividualRankings.value = [...individualRankings];
|
||||
localTeamRankings.value = [...teamRankings];
|
||||
localBonusRules.value = [...bonusRules];
|
||||
localDisplayConfig.value = {...displayConfig};
|
||||
localBattleEndTime.value = {...battleEndTime};
|
||||
localDrumConfig.value = {...drumConfig};
|
||||
|
||||
// 重新处理强拍位置
|
||||
if (localDrumConfig.value.pattern && localDrumConfig.value.pattern.strongBeats) {
|
||||
localDrumConfig.value.pattern.strongBeatsStr =
|
||||
localDrumConfig.value.pattern.strongBeats.join(',') || '1,4';
|
||||
}
|
||||
|
||||
if (success) {
|
||||
alert('数据刷新成功!');
|
||||
} else {
|
||||
alert('数据刷新失败,请重试。');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('数据刷新失败:', error);
|
||||
alert('数据刷新失败,请重试。');
|
||||
}
|
||||
};
|
||||
const currentTab = ref('individual');
|
||||
|
||||
// 本地数据副本
|
||||
const localIndividualRankings = ref([...individualRankings]);
|
||||
const localTeamRankings = ref([...teamRankings]);
|
||||
const localBonusRules = ref([...bonusRules]);
|
||||
const localDisplayConfig = ref({...displayConfig});
|
||||
const localBattleEndTime = ref({...battleEndTime});
|
||||
// 初始化本地战鼓配置副本
|
||||
const localDrumConfig = ref({...drumConfig});
|
||||
// 添加强拍位置的字符串表示,用于输入框
|
||||
localDrumConfig.value.pattern.strongBeatsStr = localDrumConfig.value.pattern.strongBeats?.join(',') || '1,4';
|
||||
if (localDrumConfig.value.pattern && localDrumConfig.value.pattern.strongBeats) {
|
||||
localDrumConfig.value.pattern.strongBeatsStr = localDrumConfig.value.pattern.strongBeats.join(',') || '1,4';
|
||||
} else {
|
||||
localDrumConfig.value.pattern = localDrumConfig.value.pattern || {};
|
||||
localDrumConfig.value.pattern.strongBeats = [1, 4];
|
||||
localDrumConfig.value.pattern.strongBeatsStr = '1,4';
|
||||
}
|
||||
|
||||
// 组件挂载时初始化数据
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await initializeData();
|
||||
// 重新加载本地数据副本
|
||||
localIndividualRankings.value = [...individualRankings];
|
||||
localTeamRankings.value = [...teamRankings];
|
||||
localBonusRules.value = [...bonusRules];
|
||||
localDisplayConfig.value = {...displayConfig};
|
||||
localBattleEndTime.value = {...battleEndTime};
|
||||
localDrumConfig.value = {...drumConfig};
|
||||
|
||||
// 重新处理强拍位置
|
||||
if (localDrumConfig.value.pattern && localDrumConfig.value.pattern.strongBeats) {
|
||||
localDrumConfig.value.pattern.strongBeatsStr =
|
||||
localDrumConfig.value.pattern.strongBeats.join(',') || '1,4';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('初始化数据失败:', error);
|
||||
}
|
||||
});
|
||||
|
||||
// 更新强拍位置数组
|
||||
const updateStrongBeats = () => {
|
||||
@@ -783,24 +885,45 @@ const goBack = () => {
|
||||
};
|
||||
|
||||
// 保存数据
|
||||
const saveData = () => {
|
||||
// 按分数重新排序
|
||||
localIndividualRankings.value.sort((a, b) => b.score - a.score);
|
||||
localTeamRankings.value.sort((a, b) => b.totalScore - a.totalScore);
|
||||
|
||||
// 调用保存方法
|
||||
saveIndividualRankings(localIndividualRankings.value);
|
||||
saveTeamRankings(localTeamRankings.value);
|
||||
saveDisplayConfig(localDisplayConfig.value);
|
||||
saveBattleEndTime(localBattleEndTime.value);
|
||||
// 保存战鼓配置前,确保强拍位置数组是最新的
|
||||
updateStrongBeats();
|
||||
// 移除临时的字符串表示,避免保存到配置中
|
||||
const configToSave = {...localDrumConfig.value};
|
||||
delete configToSave.pattern.strongBeatsStr;
|
||||
saveDrumConfig(configToSave);
|
||||
|
||||
alert('数据保存成功!');
|
||||
const saveData = async () => {
|
||||
try {
|
||||
// 按分数重新排序
|
||||
localIndividualRankings.value.sort((a, b) => b.score - a.score);
|
||||
localTeamRankings.value.sort((a, b) => b.totalScore - a.totalScore);
|
||||
|
||||
// 保存战鼓配置前,确保强拍位置数组是最新的
|
||||
updateStrongBeats();
|
||||
// 移除临时的字符串表示,避免保存到配置中
|
||||
const configToSave = {...localDrumConfig.value};
|
||||
delete configToSave.pattern.strongBeatsStr;
|
||||
|
||||
// 导入必要的配置服务函数
|
||||
const { readConfig, writeConfig } = await import('../services/configService');
|
||||
|
||||
// 一次性读取、修改并保存所有配置,避免竞态条件
|
||||
const currentConfig = await readConfig();
|
||||
|
||||
// 更新所有配置项
|
||||
currentConfig.individualRankings = localIndividualRankings.value;
|
||||
currentConfig.teamRankings = localTeamRankings.value;
|
||||
currentConfig.bonusRules = localBonusRules.value;
|
||||
currentConfig.displayConfig = localDisplayConfig.value;
|
||||
currentConfig.battleEndTime = localBattleEndTime.value;
|
||||
currentConfig.drumConfig = configToSave;
|
||||
|
||||
// 一次性保存所有配置
|
||||
const result = await writeConfig(currentConfig);
|
||||
|
||||
// 检查保存是否成功
|
||||
if (result) {
|
||||
alert('数据保存成功!');
|
||||
} else {
|
||||
alert('数据保存失败,请检查网络连接后重试。');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存数据时发生错误:', error);
|
||||
alert('保存数据失败,请重试。');
|
||||
}
|
||||
};
|
||||
|
||||
// 添加/编辑个人
|
||||
@@ -904,6 +1027,23 @@ const deleteTeam = (id) => {
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// 添加奖金规则
|
||||
const addBonusRule = () => {
|
||||
localBonusRules.value.push({
|
||||
rank: '',
|
||||
description: '',
|
||||
individualBonus: '',
|
||||
teamBonus: ''
|
||||
});
|
||||
};
|
||||
|
||||
// 删除奖金规则
|
||||
const deleteBonusRule = (index) => {
|
||||
if (confirm('确定要删除这条奖金规则吗?')) {
|
||||
localBonusRules.value.splice(index, 1);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<h2>🎯 奖金设置</h2>
|
||||
<div class="bonus-rules-row">
|
||||
<div
|
||||
v-for="(rule, index) in bonusRules"
|
||||
v-for="(rule, index) in displayBonusRules"
|
||||
:key="index"
|
||||
class="bonus-rule-item"
|
||||
>
|
||||
@@ -69,9 +69,9 @@
|
||||
<span class="rank-col">排名</span>
|
||||
<span class="avatar-col">头像</span>
|
||||
<span class="name-col">姓名</span>
|
||||
<span class="score-col">{{ displayConfig.individual.scoreColumn.displayName }}</span>
|
||||
<span v-if="displayConfig.individual.showLevel" class="level-col">等级</span>
|
||||
<span v-if="displayConfig.individual.showDepartment" class="dept-col">部门</span>
|
||||
<span class="score-col">{{ localDisplayConfig.individual?.scoreColumn?.displayName || '得分' }}</span>
|
||||
<span v-if="localDisplayConfig.individual?.showLevel" class="level-col">等级</span>
|
||||
<span v-if="localDisplayConfig.individual?.showDepartment" class="dept-col">部门</span>
|
||||
<span class="bonus-col">奖金</span>
|
||||
</div>
|
||||
<div
|
||||
@@ -87,9 +87,9 @@
|
||||
<span class="rank-col">{{ index + 1 }}</span>
|
||||
<span class="avatar-col">{{ item.avatar }}</span>
|
||||
<span class="name-col">{{ item.name }}</span>
|
||||
<span class="score-col">{{ displayConfig.individual.scoreColumn.displayStyle === 'amount' ? '¥' + item.score : item.score }}</span>
|
||||
<span v-if="displayConfig.individual.showLevel" class="level-col" :class="`level-${item.level}`">{{ item.level }}</span>
|
||||
<span v-if="displayConfig.individual.showDepartment" class="dept-col">{{ item.department }}</span>
|
||||
<span class="score-col">{{ localDisplayConfig.individual?.scoreColumn?.displayStyle === 'amount' ? '¥' + item.score : item.score }}</span>
|
||||
<span v-if="localDisplayConfig.individual?.showLevel" class="level-col" :class="`level-${item.level}`">{{ item.level }}</span>
|
||||
<span v-if="localDisplayConfig.individual?.showDepartment" class="dept-col">{{ item.department }}</span>
|
||||
<span class="bonus-col">¥{{ item.bonus }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -102,9 +102,9 @@
|
||||
<div class="table-header" :style="{ 'grid-template-columns': teamGridTemplate }">
|
||||
<span class="rank-col">排名</span>
|
||||
<span class="name-col">战队名称</span>
|
||||
<span class="score-col">{{ displayConfig.team.totalScoreColumn.displayName }}</span>
|
||||
<span v-if="displayConfig.team.showMemberCount" class="member-col">人数</span>
|
||||
<span v-if="displayConfig.team.showLeader" class="leader-col">队长</span>
|
||||
<span class="score-col">{{ localDisplayConfig.team?.totalScoreColumn?.displayName || '总分' }}</span>
|
||||
<span v-if="localDisplayConfig.team?.showMemberCount" class="member-col">人数</span>
|
||||
<span v-if="localDisplayConfig.team?.showLeader" class="leader-col">队长</span>
|
||||
<span class="bonus-col">奖金</span>
|
||||
</div>
|
||||
<div
|
||||
@@ -119,9 +119,9 @@
|
||||
>
|
||||
<span class="rank-col">{{ index + 1 }}</span>
|
||||
<span class="name-col">{{ item.name }}</span>
|
||||
<span class="score-col">{{ displayConfig.team.totalScoreColumn.displayStyle === 'amount' ? '¥' + item.totalScore : item.totalScore }}</span>
|
||||
<span v-if="displayConfig.team.showMemberCount" class="member-col">{{ item.memberCount }}人</span>
|
||||
<span v-if="displayConfig.team.showLeader" class="leader-col">{{ item.leader }}</span>
|
||||
<span class="score-col">{{ localDisplayConfig.team?.totalScoreColumn?.displayStyle === 'amount' ? '¥' + item.totalScore : item.totalScore }}</span>
|
||||
<span v-if="localDisplayConfig.team?.showMemberCount" class="member-col">{{ item.memberCount }}人</span>
|
||||
<span v-if="localDisplayConfig.team?.showLeader" class="leader-col">{{ item.leader }}</span>
|
||||
<span class="bonus-col">¥{{ item.bonus }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -141,17 +141,55 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted, watch, computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import {
|
||||
individualRankings,
|
||||
teamRankings,
|
||||
import {
|
||||
individualRankings,
|
||||
teamRankings,
|
||||
bonusRules,
|
||||
displayConfig,
|
||||
battleEndTime,
|
||||
drumConfig
|
||||
drumConfig,
|
||||
initializeData
|
||||
} from '../data/mockData.js';
|
||||
|
||||
// 创建本地显示配置的副本,确保深拷贝
|
||||
const localDisplayConfig = ref(JSON.parse(JSON.stringify(displayConfig)));
|
||||
// 创建本地显示配置的副本,确保深拷贝并提供默认值
|
||||
const createDefaultDisplayConfig = () => ({
|
||||
individual: {
|
||||
scoreColumn: {
|
||||
displayName: '得分',
|
||||
displayStyle: 'number'
|
||||
},
|
||||
showLevel: true,
|
||||
showDepartment: true,
|
||||
columnWidths: {}
|
||||
},
|
||||
team: {
|
||||
totalScoreColumn: {
|
||||
displayName: '总分',
|
||||
displayStyle: 'number'
|
||||
},
|
||||
showMemberCount: true,
|
||||
showLeader: true,
|
||||
columnWidths: {}
|
||||
}
|
||||
});
|
||||
|
||||
// 创建默认奖金规则
|
||||
const createDefaultBonusRules = () => [
|
||||
{ rank: '1-3', description: '前三名', individualBonus: '¥10000, ¥8000, ¥5000', teamBonus: '¥50000, ¥30000, ¥20000' },
|
||||
{ rank: '4-10', description: '四至十名', individualBonus: '¥3000/人', teamBonus: '¥10000/队' },
|
||||
{ rank: '11-20', description: '十一至二十名', individualBonus: '¥1000/人', teamBonus: '¥5000/队' }
|
||||
];
|
||||
|
||||
const localDisplayConfig = ref(
|
||||
displayConfig ? JSON.parse(JSON.stringify(displayConfig)) : createDefaultDisplayConfig()
|
||||
);
|
||||
|
||||
// 确保奖金规则有默认值
|
||||
const displayBonusRules = computed(() => {
|
||||
return Array.isArray(bonusRules) && bonusRules.length > 0
|
||||
? bonusRules
|
||||
: createDefaultBonusRules();
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
@@ -438,16 +476,6 @@ const goToAdmin = () => {
|
||||
router.push('/admin');
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
calculateCountdown();
|
||||
countdownInterval = setInterval(calculateCountdown, 1000);
|
||||
// 延迟初始化音频上下文,避免浏览器自动播放限制
|
||||
setTimeout(() => {
|
||||
// 不自动初始化音频,等待用户交互后再初始化
|
||||
}, 1000);
|
||||
startDrumAnimation();
|
||||
});
|
||||
|
||||
// 监听窗口点击事件,用于用户交互后初始化音频上下文
|
||||
document.addEventListener('click', initAudioContext, { once: true });
|
||||
document.addEventListener('touchstart', initAudioContext, { once: true });
|
||||
@@ -465,7 +493,18 @@ const handleResize = () => {
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
try {
|
||||
// 异步初始化数据
|
||||
await initializeData();
|
||||
// 更新本地显示配置
|
||||
localDisplayConfig.value = displayConfig ? JSON.parse(JSON.stringify(displayConfig)) : createDefaultDisplayConfig();
|
||||
} catch (error) {
|
||||
console.error('初始化数据失败:', error);
|
||||
// 使用默认配置
|
||||
localDisplayConfig.value = createDefaultDisplayConfig();
|
||||
}
|
||||
|
||||
calculateCountdown();
|
||||
countdownInterval = setInterval(calculateCountdown, 10); // 改为10ms更新一次以显示毫秒
|
||||
startDrumAnimation();
|
||||
|
||||
Reference in New Issue
Block a user