chore: 支持上传图片及sass语法
This commit is contained in:
@@ -358,6 +358,53 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 冠军Logo配置 -->
|
||||
<div v-if="currentTab === 'champion'" class="champion-config-content">
|
||||
<h2 class="game-subtitle">🏆 冠军Logo配置</h2>
|
||||
|
||||
<div class="config-section">
|
||||
<h3 class="text-gold">🎯 战区冠军Logo</h3>
|
||||
<div class="logo-upload-section">
|
||||
<div class="logo-preview">
|
||||
<div v-if="championLogos.teamChampionLogo" class="logo-image-container">
|
||||
<img :src="championLogos.teamChampionLogo" alt="战区冠军Logo" class="logo-preview-image">
|
||||
</div>
|
||||
<div v-else class="logo-placeholder">
|
||||
<span>未上传Logo</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="upload-controls">
|
||||
<input type="file" accept="image/*" @change="(e) => handleChampionLogoUpload(e, 'teamChampion')" class="logo-input">
|
||||
<button v-if="championLogos.teamChampionLogo" @click="clearChampionLogo('teamChampion')" class="btn-clear">
|
||||
清除Logo
|
||||
</button>
|
||||
</div>
|
||||
<p class="upload-hint">支持JPG、PNG、GIF格式,建议尺寸200x200像素,文件大小不超过5MB</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="config-section">
|
||||
<h3 class="text-gold">👤 英雄冠军Logo</h3>
|
||||
<div class="logo-upload-section">
|
||||
<div class="logo-preview">
|
||||
<div v-if="championLogos.individualChampionLogo" class="logo-image-container">
|
||||
<img :src="championLogos.individualChampionLogo" alt="英雄冠军Logo" class="logo-preview-image">
|
||||
</div>
|
||||
<div v-else class="logo-placeholder">
|
||||
<span>未上传Logo</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="upload-controls">
|
||||
<input type="file" accept="image/*" @change="(e) => handleChampionLogoUpload(e, 'individualChampion')" class="logo-input">
|
||||
<button v-if="championLogos.individualChampionLogo" @click="clearChampionLogo('individualChampion')" class="btn-clear">
|
||||
清除Logo
|
||||
</button>
|
||||
</div>
|
||||
<p class="upload-hint">支持JPG、PNG、GIF格式,建议尺寸200x200像素,文件大小不超过5MB</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 战鼓配置 -->
|
||||
<div v-if="currentTab === 'drum'" class="drum-config-content">
|
||||
<h2 class="game-subtitle">🥁 战鼓配置管理</h2>
|
||||
@@ -640,6 +687,30 @@
|
||||
<option value="B">B</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>头像:</label>
|
||||
<div class="avatar-upload">
|
||||
<div v-if="individualForm.avatar && individualForm.avatar.startsWith('/')" class="avatar-preview">
|
||||
<img :src="individualForm.avatar" alt="头像预览" style="width: 80px; height: 80px; object-fit: cover; border-radius: 50%;">
|
||||
</div>
|
||||
<div v-else class="avatar-emoji-preview">
|
||||
{{ individualForm.avatar }}
|
||||
</div>
|
||||
<input type="file" accept="image/*" @change="handleAvatarUpload" class="avatar-input">
|
||||
<label for="emoji-select">或选择表情:</label>
|
||||
<select v-model="individualForm.avatar" id="emoji-select" class="form-input" v-if="!individualForm.avatar.startsWith('/')">
|
||||
<option value="👑">👑 皇冠</option>
|
||||
<option value="🥇">🥇 金牌</option>
|
||||
<option value="🥈">🥈 银牌</option>
|
||||
<option value="🥉">🥉 铜牌</option>
|
||||
<option value="⭐">⭐ 星星</option>
|
||||
<option value="🔥">🔥 火焰</option>
|
||||
<option value="⚡">⚡ 闪电</option>
|
||||
<option value="🎯">🎯 靶心</option>
|
||||
</select>
|
||||
<button v-if="individualForm.avatar.startsWith('/')" @click="clearAvatar" class="btn-clear">清除头像</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>部门:</label>
|
||||
<input v-model="individualForm.department" type="text" required class="form-input">
|
||||
@@ -742,10 +813,96 @@ const tabs = [
|
||||
{ key: 'team', label: '战队排名' },
|
||||
{ key: 'bonus', label: '奖金设置' },
|
||||
{ key: 'config', label: '显示配置' },
|
||||
{ key: 'champion', label: '冠军Logo配置' },
|
||||
{ key: 'endTime', label: '结束时间设置' },
|
||||
{ key: 'drum', label: '战鼓配置' }
|
||||
];
|
||||
|
||||
// 冠军Logo配置
|
||||
const championLogos = ref({
|
||||
teamChampionLogo: '',
|
||||
individualChampionLogo: ''
|
||||
});
|
||||
|
||||
// 组件挂载时初始化冠军Logo配置
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await initializeData();
|
||||
// 重新加载本地数据副本
|
||||
localIndividualRankings.value = [...individualRankings];
|
||||
localTeamRankings.value = [...teamRankings];
|
||||
localBonusRules.value = [...bonusRules];
|
||||
localDisplayConfig.value = {...displayConfig};
|
||||
localBattleEndTime.value = {...battleEndTime};
|
||||
localDrumConfig.value = {...drumConfig};
|
||||
|
||||
// 初始化冠军Logo配置
|
||||
if (displayConfig.championLogos) {
|
||||
championLogos.value = {...displayConfig.championLogos};
|
||||
}
|
||||
|
||||
// 重新处理强拍位置
|
||||
if (localDrumConfig.value.pattern && localDrumConfig.value.pattern.strongBeats) {
|
||||
localDrumConfig.value.pattern.strongBeatsStr =
|
||||
localDrumConfig.value.pattern.strongBeats.join(',') || '1,4';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('初始化数据失败:', error);
|
||||
}
|
||||
});
|
||||
|
||||
// 处理冠军Logo上传
|
||||
const handleChampionLogoUpload = async (event, type) => {
|
||||
const file = event.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('image', file);
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/upload', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
// 删除旧的图片
|
||||
if (championLogos.value[`${type}Logo`] && championLogos.value[`${type}Logo`].startsWith('/uploads/')) {
|
||||
const oldFilename = championLogos.value[`${type}Logo`].split('/').pop();
|
||||
fetch(`/api/upload/${oldFilename}`, {
|
||||
method: 'DELETE'
|
||||
}).catch(error => {
|
||||
console.error('删除旧文件失败:', error);
|
||||
});
|
||||
}
|
||||
|
||||
championLogos.value[`${type}Logo`] = result.filePath;
|
||||
} else {
|
||||
alert('上传失败: ' + result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('上传失败:', error);
|
||||
alert('上传失败,请重试');
|
||||
}
|
||||
|
||||
// 清空文件输入
|
||||
event.target.value = '';
|
||||
};
|
||||
|
||||
// 清除冠军Logo
|
||||
const clearChampionLogo = (type) => {
|
||||
if (championLogos.value[`${type}Logo`] && championLogos.value[`${type}Logo`].startsWith('/uploads/')) {
|
||||
const filename = championLogos.value[`${type}Logo`].split('/').pop();
|
||||
fetch(`/api/upload/${filename}`, {
|
||||
method: 'DELETE'
|
||||
}).catch(error => {
|
||||
console.error('删除文件失败:', error);
|
||||
});
|
||||
}
|
||||
championLogos.value[`${type}Logo`] = '';
|
||||
};
|
||||
|
||||
// 刷新数据
|
||||
const handleRefreshData = () => {
|
||||
try {
|
||||
@@ -855,6 +1012,49 @@ const individualForm = reactive({
|
||||
team: ''
|
||||
});
|
||||
|
||||
// 处理头像上传
|
||||
const handleAvatarUpload = async (event) => {
|
||||
const file = event.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('image', file);
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/upload', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
individualForm.avatar = result.filePath;
|
||||
} else {
|
||||
alert('上传失败: ' + result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('上传失败:', error);
|
||||
alert('上传失败,请重试');
|
||||
}
|
||||
|
||||
// 清空文件输入,允许重新选择相同文件
|
||||
event.target.value = '';
|
||||
};
|
||||
|
||||
// 清除头像
|
||||
const clearAvatar = () => {
|
||||
// 如果是图片,尝试删除服务器上的文件
|
||||
if (individualForm.avatar.startsWith('/uploads/')) {
|
||||
const filename = individualForm.avatar.split('/').pop();
|
||||
fetch(`/api/upload/${filename}`, {
|
||||
method: 'DELETE'
|
||||
}).catch(error => {
|
||||
console.error('删除文件失败:', error);
|
||||
});
|
||||
}
|
||||
individualForm.avatar = '⭐';
|
||||
};
|
||||
|
||||
const teamForm = reactive({
|
||||
id: null,
|
||||
name: '',
|
||||
@@ -918,6 +1118,8 @@ const saveData = async () => {
|
||||
currentConfig.teamRankings = localTeamRankings.value;
|
||||
currentConfig.bonusRules = localBonusRules.value;
|
||||
currentConfig.displayConfig = localDisplayConfig.value;
|
||||
// 保存冠军Logo配置
|
||||
currentConfig.displayConfig.championLogos = championLogos.value;
|
||||
currentConfig.battleEndTime = localBattleEndTime.value;
|
||||
currentConfig.drumConfig = configToSave;
|
||||
|
||||
@@ -1467,6 +1669,109 @@ const deleteBonusRule = (index) => {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 头像上传样式 */
|
||||
.avatar-upload {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.avatar-preview, .avatar-emoji-preview {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background-color: #f0f0f0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.avatar-emoji-preview {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.avatar-input {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.btn-clear {
|
||||
padding: 5px 10px;
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.btn-clear:hover {
|
||||
background-color: #c82333;
|
||||
}
|
||||
|
||||
/* Logo上传样式 */
|
||||
.logo-upload-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.logo-preview {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.logo-image-container {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2px dashed #ccc;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.logo-preview-image {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.logo-placeholder {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2px dashed #ccc;
|
||||
border-radius: 10px;
|
||||
background-color: #f8f9fa;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.upload-controls {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.logo-input {
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 5px;
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.upload-hint {
|
||||
font-size: 0.9rem;
|
||||
color: #6c757d;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* 操作按钮 */
|
||||
.action-col {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user