diff --git a/Build_God_Api/Build_God_Api/Services/CharacterService.cs b/Build_God_Api/Build_God_Api/Services/CharacterService.cs index d5a8a8e..d48f22f 100644 --- a/Build_God_Api/Build_God_Api/Services/CharacterService.cs +++ b/Build_God_Api/Build_God_Api/Services/CharacterService.cs @@ -213,7 +213,11 @@ namespace Build_God_Api.Services public async Task GetCharacterByAccountId(int accountId) { - return await db.Queryable().FirstAsync(x => x.AccountId == accountId && x.isLocked == false); + return await db.Queryable() + .Where(x => x.AccountId == accountId && x.isLocked == false) + .OrderBy(x => x.LastLogin, OrderByType.Desc) + .OrderBy(x => x.CreatedOn, OrderByType.Asc) + .FirstAsync(); } public async Task> GetCharactersByAccountId(int accountId) diff --git a/Build_God_Game/src/views/DailyMissionView.vue b/Build_God_Game/src/views/DailyMissionView.vue index d0f617d..cd46664 100644 --- a/Build_God_Game/src/views/DailyMissionView.vue +++ b/Build_God_Game/src/views/DailyMissionView.vue @@ -190,39 +190,60 @@ const MissionCardContent = defineComponent({ h('div', { class: 'card-header' }, [ h('div', { class: 'card-title-row' }, [ h('div', { class: 'card-icon', style: `filter: ${getMissionIconFilter(props.mission.missionType, props.mission.difficulty)}`, innerHTML: getMissionIcon(props.mission.missionType, props.mission.difficulty) }), - h('span', { class: 'card-title' }, props.mission.missionTitle), + h('div', { class: 'title-stack' }, [ + h('span', { class: 'card-title' }, props.mission.missionTitle), + h('span', { class: 'card-subtitle' }, props.mission.missionName), + ]), ]), h('span', { class: ['card-status', getStatusClass(props.mission.status)] }, getStatusText(props.mission.status)), ]), h('div', { class: 'card-desc' }, props.mission.missionDescription), - h('div', { class: 'card-difficulty' }, [ + h('div', { class: 'card-meta-row' }, [ h('span', { class: ['difficulty-badge', getDifficultyClass(props.mission.difficulty)] }, getDifficultyLabel(props.mission.difficulty)), + h('span', { class: 'time-badge' }, `预计 ${props.mission.spendTimeMinutes} 分钟`), ]), props.mission.progresses && props.mission.progresses.length > 0 - ? h('div', { class: 'card-progress' }, [ - h('span', { class: 'progress-label' }, '目标:'), - h('span', { class: 'progress-value' }, getProgressText(props.mission)), + ? h('div', { class: 'objective-panel' }, [ + h('span', { class: 'objective-label' }, '任务目标'), + h('span', { class: 'objective-value' }, getProgressText(props.mission)), ]) : null, - h('div', { class: 'card-rewards' }, [ - h('span', { class: 'reward-item exp-reward' }, `✨${props.mission.expReward}`), - h('span', { class: 'reward-item money-reward' }, `💰${props.mission.moneyReward}`), - ...props.mission.rewards.slice(0, 2).map((reward: any) => - h('span', { class: 'reward-item' }, `${getRewardIcon(reward.rewardType)}${reward.count}`) - ), - props.mission.rewards.length > 2 - ? h('span', { class: 'reward-more' }, `+${props.mission.rewards.length - 2}`) - : null, + h('div', { class: 'reward-section' }, [ + h('div', { class: 'section-label' }, '任务奖励'), + h('div', { class: 'card-rewards' }, [ + h('span', { class: 'reward-item exp-reward' }, `✨ ${props.mission.expReward}`), + h('span', { class: 'reward-item money-reward' }, `💰 ${props.mission.moneyReward}`), + ...props.mission.rewards.slice(0, 2).map((reward: any) => + h('span', { class: 'reward-item' }, `${getRewardIcon(reward.rewardType)} ${reward.count}`) + ), + props.mission.rewards.length > 2 + ? h('span', { class: 'reward-more' }, `+${props.mission.rewards.length - 2}`) + : null, + ]), ]), h('div', { class: 'card-actions' }, [ + !canAccept(props.mission) + ? h('span', { class: 'action-hint' }, canClaim(props.mission) + ? '任务已完成,领取奖励' + : props.mission.status === DailyMissionStatus.InProgress + ? '任务正在进行中' + : '奖励已领取' + ) + : null, canAccept(props.mission) - ? h('button', { class: 'card-btn accept-btn', onClick: () => emit('accept') }, '接取') + ? h('button', { class: 'card-btn accept-btn', type: 'button', onClick: () => emit('accept') }, [ + h('span', { class: 'btn-label' }, '准备好后即可接取'), + h('span', { class: 'btn-arrow' }, '›'), + ]) : canClaim(props.mission) - ? h('button', { class: 'card-btn claim-btn', onClick: () => emit('claim') }, '领取') + ? h('button', { class: 'card-btn claim-btn', type: 'button', onClick: () => emit('claim') }, [ + h('span', { class: 'btn-label' }, '领取奖励'), + h('span', { class: 'btn-arrow' }, '›'), + ]) : props.mission.status === DailyMissionStatus.InProgress - ? h('button', { class: 'card-btn disabled-btn', disabled: true }, '进行中') + ? h('button', { class: 'card-btn disabled-btn', type: 'button', disabled: true }, '进行中') : props.mission.status === DailyMissionStatus.Claimed - ? h('button', { class: 'card-btn disabled-btn', disabled: true }, '已完成') + ? h('button', { class: 'card-btn disabled-btn', type: 'button', disabled: true }, '已完成') : null, ]), ]) @@ -409,15 +430,18 @@ const MissionCardContent = defineComponent({ } .mission-card { - background: rgba(255, 255, 255, 0.02); + background: + radial-gradient(circle at top left, rgba(255, 136, 68, 0.08), transparent 34%), + rgba(255, 255, 255, 0.025); border: 1px solid; - border-radius: 12px; + border-radius: 18px; overflow: hidden; - transition: transform 0.2s ease, box-shadow 0.2s ease; + transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease; } .mission-card:hover { transform: translateY(-2px); + box-shadow: 0 18px 34px rgba(0, 0, 0, 0.28); } .purgatory-card { @@ -425,7 +449,7 @@ const MissionCardContent = defineComponent({ } .card-inner { - padding: 16px; + padding: 18px; } .mission-collection { @@ -447,14 +471,15 @@ const MissionCardContent = defineComponent({ .mission-card-content { display: flex; flex-direction: column; - gap: 10px; + gap: 12px; } .card-header { display: flex; justify-content: space-between; - align-items: center; - padding-bottom: 10px; + align-items: flex-start; + gap: 12px; + padding-bottom: 12px; border-bottom: 1px solid rgba(255, 255, 255, 0.08); } @@ -467,11 +492,16 @@ const MissionCardContent = defineComponent({ } .card-icon { - width: 24px; - height: 24px; + width: 34px; + height: 34px; + flex: 0 0 34px; display: flex; align-items: center; justify-content: center; + padding: 6px; + border-radius: 12px; + background: rgba(255, 255, 255, 0.06); + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08); } .card-icon :deep(svg) { @@ -479,39 +509,68 @@ const MissionCardContent = defineComponent({ height: 100%; } +.title-stack { + display: flex; + flex-direction: column; + gap: 3px; + min-width: 0; +} + .card-title { color: #ffffff; - font-size: 1rem; - font-weight: 600; + font-size: 1.05rem; + font-weight: 700; + letter-spacing: 0.02em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.card-subtitle { + color: #777777; + font-size: 0.72rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .card-status { - padding: 2px 8px; - border-radius: 8px; - font-size: 0.7rem; - font-weight: 500; + padding: 5px 10px; + border-radius: 999px; + font-size: 0.72rem; + font-weight: 700; white-space: nowrap; + letter-spacing: 0.04em; } .card-desc { - color: #888888; - font-size: 0.8rem; - line-height: 1.4; + color: #aaaaaa; + font-size: 0.84rem; + line-height: 1.55; } -.card-difficulty { +.card-meta-row { display: flex; align-items: center; + flex-wrap: wrap; + gap: 8px; } .difficulty-badge { - padding: 2px 8px; - border-radius: 4px; - font-size: 0.7rem; - font-weight: 500; + padding: 4px 10px; + border-radius: 999px; + font-size: 0.72rem; + font-weight: 700; +} + +.time-badge { + padding: 4px 10px; + border-radius: 999px; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.08); + color: #9ca3af; + font-size: 0.72rem; + font-weight: 600; } .difficulty-normal { @@ -529,39 +588,56 @@ const MissionCardContent = defineComponent({ color: #fca5a5; } -.card-progress { +.objective-panel { display: flex; - align-items: center; - gap: 6px; - background: rgba(255, 255, 255, 0.03); - padding: 8px 10px; - border-radius: 6px; + flex-direction: column; + gap: 5px; + background: linear-gradient(135deg, rgba(34, 197, 94, 0.12), rgba(255, 255, 255, 0.035)); + border: 1px solid rgba(34, 197, 94, 0.18); + padding: 11px 12px; + border-radius: 12px; } -.progress-label { - color: #666666; - font-size: 0.75rem; +.objective-label { + color: #86efac; + font-size: 0.72rem; + font-weight: 700; + letter-spacing: 0.08em; } -.progress-value { - color: #22c55e; - font-size: 0.8rem; - font-weight: 500; +.objective-value { + color: #ffffff; + font-size: 0.9rem; + font-weight: 700; +} + +.reward-section { + display: flex; + flex-direction: column; + gap: 8px; +} + +.section-label { + color: #777777; + font-size: 0.72rem; + font-weight: 700; + letter-spacing: 0.08em; } .card-rewards { display: flex; flex-wrap: wrap; - gap: 4px; + gap: 6px; } .reward-item { background: rgba(255, 136, 68, 0.1); border: 1px solid rgba(255, 136, 68, 0.2); color: #ff8844; - padding: 2px 6px; - border-radius: 4px; - font-size: 0.7rem; + padding: 5px 9px; + border-radius: 999px; + font-size: 0.74rem; + font-weight: 700; } .exp-reward { @@ -579,53 +655,111 @@ const MissionCardContent = defineComponent({ .reward-more { background: rgba(255, 255, 255, 0.1); color: #888888; - padding: 2px 6px; - border-radius: 4px; - font-size: 0.7rem; + padding: 5px 9px; + border-radius: 999px; + font-size: 0.74rem; + font-weight: 700; } -.card-actions { +:deep(.card-actions) { display: flex; - gap: 8px; - margin-top: 4px; + flex-direction: column; + gap: 9px; + margin-top: 6px; + padding-top: 14px; + border-top: 1px solid rgba(255, 255, 255, 0.08); } -.card-btn { - flex: 1; - padding: 8px 12px; - border-radius: 6px; - font-size: 0.8rem; - font-weight: 500; +:deep(.action-hint) { + color: #777777; + font-size: 0.75rem; + text-align: center; +} + +:deep(.card-btn) { + width: 100%; + min-height: 50px; + padding: 0 18px; + border-radius: 16px; + font-size: 0.95rem; + font-weight: 800; cursor: pointer; - transition: all 0.2s ease; - border: none; + transition: transform 0.18s ease, box-shadow 0.18s ease, filter 0.18s ease; + border: 1px solid transparent; + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + letter-spacing: 0.08em; +} + +:deep(.btn-label) { + display: inline-flex; + align-items: center; + justify-content: center; + line-height: 1; +} + +:deep(.card-btn:active:not(:disabled)) { + transform: scale(0.98); +} + +:deep(.btn-arrow) { + font-size: 1.3rem; + line-height: 1; + transform: translateY(-1px); } -.card-btn.accept-btn { - background: linear-gradient(135deg, #ff8844 0%, #ff6644 100%); +:deep(.card-btn.accept-btn) { + background: linear-gradient(135deg, #facc15 0%, #ff8844 45%, #ef4444 100%); + border-color: rgba(255, 214, 102, 0.55); + color: #ffffff; + box-shadow: + 0 10px 24px rgba(255, 136, 68, 0.26), + inset 0 1px 0 rgba(255, 255, 255, 0.22); + text-shadow: 0 1px 8px rgba(0, 0, 0, 0.35); +} + +:deep(.card-btn.accept-btn .btn-label) { + font-size: 1rem; + font-weight: 900; color: #ffffff; + letter-spacing: 0.1em; } -.card-btn.accept-btn:hover { - transform: scale(1.02); - box-shadow: 0 2px 10px rgba(255, 136, 68, 0.3); +:deep(.card-btn.accept-btn:hover) { + transform: translateY(-1px); + filter: brightness(1.08); + box-shadow: + 0 14px 30px rgba(255, 136, 68, 0.38), + 0 0 20px rgba(250, 204, 21, 0.22), + inset 0 1px 0 rgba(255, 255, 255, 0.26); } -.card-btn.claim-btn { +:deep(.card-btn.claim-btn) { background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%); + border-color: rgba(134, 239, 172, 0.4); color: #ffffff; + box-shadow: + 0 10px 24px rgba(34, 197, 94, 0.24), + inset 0 1px 0 rgba(255, 255, 255, 0.2); } -.card-btn.claim-btn:hover { - transform: scale(1.02); - box-shadow: 0 2px 10px rgba(34, 197, 94, 0.3); +:deep(.card-btn.claim-btn:hover) { + transform: translateY(-1px); + filter: brightness(1.08); + box-shadow: + 0 14px 30px rgba(34, 197, 94, 0.36), + 0 0 18px rgba(134, 239, 172, 0.18), + inset 0 1px 0 rgba(255, 255, 255, 0.24); } -.card-btn.disabled-btn { +:deep(.card-btn.disabled-btn) { background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.1); - color: #555555; + color: #6b7280; cursor: not-allowed; + box-shadow: none; } .status-pending {