669 lines
15 KiB
Vue
669 lines
15 KiB
Vue
|
|
<template>
|
|||
|
|
<view class="crafting-drawer">
|
|||
|
|
<view class="drawer-header">
|
|||
|
|
<view class="header-left">
|
|||
|
|
<text class="drawer-title">🔨 制造</text>
|
|||
|
|
<text class="drawer-subtitle">{{ getSelectedCategoryName() }}</text>
|
|||
|
|
</view>
|
|||
|
|
<text class="drawer-close" @click="close">×</text>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 技能信息显示 -->
|
|||
|
|
<view class="crafting-skill-info">
|
|||
|
|
<text class="skill-info__label">制造技能等级:</text>
|
|||
|
|
<text class="skill-info__level">{{ getCraftingSkillLevel() }}</text>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 分类标签 -->
|
|||
|
|
<FilterTabs
|
|||
|
|
:tabs="categories"
|
|||
|
|
:modelValue="selectedCategory"
|
|||
|
|
@update:modelValue="selectedCategory = $event"
|
|||
|
|
/>
|
|||
|
|
|
|||
|
|
<!-- 配方列表 -->
|
|||
|
|
<scroll-view class="recipe-list" scroll-y>
|
|||
|
|
<view
|
|||
|
|
v-for="recipe in filteredRecipes"
|
|||
|
|
:key="recipe.id"
|
|||
|
|
class="recipe-item"
|
|||
|
|
:class="{ 'recipe-item--disabled': !recipe.canCraftNow }"
|
|||
|
|
@click="selectRecipe(recipe)"
|
|||
|
|
>
|
|||
|
|
<view class="recipe-item__main">
|
|||
|
|
<text class="recipe-item__icon">{{ recipe.displayIcon || '📦' }}</text>
|
|||
|
|
<view class="recipe-item__info">
|
|||
|
|
<text class="recipe-item__name">{{ recipe.displayName }}</text>
|
|||
|
|
<text class="recipe-item__desc">{{ getRecipeDescription(recipe) }}</text>
|
|||
|
|
<!-- 材料需求 -->
|
|||
|
|
<view class="recipe-materials">
|
|||
|
|
<text
|
|||
|
|
v-for="mat in recipe.materials"
|
|||
|
|
:key="mat.itemId"
|
|||
|
|
class="material-tag"
|
|||
|
|
:class="{ 'material-tag--missing': isMaterialMissing(recipe, mat.itemId) }"
|
|||
|
|
>
|
|||
|
|
{{ getMaterialIcon(mat.itemId) }} {{ getMaterialName(mat.itemId) }} x{{ mat.count }}
|
|||
|
|
</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
<view class="recipe-item__right">
|
|||
|
|
<text class="recipe-time">{{ getCraftingTimeDisplay(recipe) }}</text>
|
|||
|
|
<text class="recipe-success-rate" :class="getSuccessRateClass(recipe)">
|
|||
|
|
{{ getSuccessRateDisplay(recipe) }}
|
|||
|
|
</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
<view v-if="filteredRecipes.length === 0" class="recipe-empty">
|
|||
|
|
<text class="recipe-empty__text">此分类下没有可制作的配方</text>
|
|||
|
|
</view>
|
|||
|
|
</scroll-view>
|
|||
|
|
|
|||
|
|
<!-- 当前制造进度 -->
|
|||
|
|
<view v-if="activeCraftingTask" class="crafting-progress">
|
|||
|
|
<view class="progress-header">
|
|||
|
|
<text class="progress-title">正在制造...</text>
|
|||
|
|
<text class="progress-percent">{{ getCraftingProgress() }}%</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="progress-bar">
|
|||
|
|
<view class="progress-bar__fill" :style="{ width: getCraftingProgress() + '%' }"></view>
|
|||
|
|
</view>
|
|||
|
|
<text class="progress-item">{{ getCraftingItemName() }}</text>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 配方详情弹窗 -->
|
|||
|
|
<view v-if="selectedRecipe" class="recipe-detail-popup" @click="selectedRecipe = null">
|
|||
|
|
<view class="recipe-detail" @click.stop>
|
|||
|
|
<view class="recipe-detail__header">
|
|||
|
|
<text class="recipe-detail__icon">{{ selectedRecipe.displayIcon || '📦' }}</text>
|
|||
|
|
<text class="recipe-detail__name">{{ selectedRecipe.displayName }}</text>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 配方属性 -->
|
|||
|
|
<view class="recipe-detail__stats">
|
|||
|
|
<view class="stat-row">
|
|||
|
|
<text class="stat-label">制造时间:</text>
|
|||
|
|
<text class="stat-value">{{ getCraftingTimeDisplay(selectedRecipe) }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="stat-row">
|
|||
|
|
<text class="stat-label">成功率:</text>
|
|||
|
|
<text class="stat-value" :class="getSuccessRateClass(selectedRecipe)">
|
|||
|
|
{{ getSuccessRateDisplay(selectedRecipe) }}
|
|||
|
|
</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="stat-row">
|
|||
|
|
<text class="stat-label">所需技能:</text>
|
|||
|
|
<text class="stat-value">{{ getRequiredSkillDisplay(selectedRecipe) }}</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 材料列表 -->
|
|||
|
|
<view class="recipe-detail__materials">
|
|||
|
|
<text class="materials-title">所需材料:</text>
|
|||
|
|
<view class="materials-list">
|
|||
|
|
<view
|
|||
|
|
v-for="mat in selectedRecipe.materials"
|
|||
|
|
:key="mat.itemId"
|
|||
|
|
class="material-item"
|
|||
|
|
:class="{ 'material-item--missing': isMaterialMissing(selectedRecipe, mat.itemId) }"
|
|||
|
|
>
|
|||
|
|
<text class="material-item__icon">{{ getMaterialIcon(mat.itemId) }}</text>
|
|||
|
|
<text class="material-item__name">{{ getMaterialName(mat.itemId) }}</text>
|
|||
|
|
<text class="material-item__count">{{ mat.count }}</text>
|
|||
|
|
<text class="material-item__have">拥有: {{ getMaterialCount(mat.itemId) }}</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 预估品质 -->
|
|||
|
|
<view class="recipe-detail__quality">
|
|||
|
|
<text class="quality-title">预估品质范围:</text>
|
|||
|
|
<view class="quality-range">
|
|||
|
|
<text class="quality-range__min" :style="{ color: getQualityColor(2) }">普通</text>
|
|||
|
|
<text class="quality-range__arrow">→</text>
|
|||
|
|
<text class="quality-range__max" :style="{ color: getQualityColor(5) }">史诗</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 操作按钮 -->
|
|||
|
|
<view class="recipe-detail__actions">
|
|||
|
|
<TextButton
|
|||
|
|
text="开始制造"
|
|||
|
|
type="primary"
|
|||
|
|
:disabled="!selectedRecipe.canCraftNow"
|
|||
|
|
@click="startCraftingRecipe"
|
|||
|
|
/>
|
|||
|
|
<TextButton text="取消" @click="selectedRecipe = null" />
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup>
|
|||
|
|
import { ref, computed } from 'vue'
|
|||
|
|
import { usePlayerStore } from '@/store/player'
|
|||
|
|
import { useGameStore } from '@/store/game'
|
|||
|
|
import { ITEM_CONFIG } from '@/config/items.js'
|
|||
|
|
import {
|
|||
|
|
getCraftableRecipes,
|
|||
|
|
getRecipesByCategory,
|
|||
|
|
calculateCraftingTime,
|
|||
|
|
calculateSuccessRate,
|
|||
|
|
startCrafting,
|
|||
|
|
completeCrafting,
|
|||
|
|
getAllCategories,
|
|||
|
|
getCategoryInfo
|
|||
|
|
} from '@/utils/craftingSystem.js'
|
|||
|
|
import { getActiveTasks } from '@/utils/taskSystem.js'
|
|||
|
|
import { TASK_TYPES } from '@/utils/taskSystem.js'
|
|||
|
|
import FilterTabs from '@/components/common/FilterTabs.vue'
|
|||
|
|
import TextButton from '@/components/common/TextButton.vue'
|
|||
|
|
|
|||
|
|
const player = usePlayerStore()
|
|||
|
|
const game = useGameStore()
|
|||
|
|
|
|||
|
|
const selectedCategory = ref('weapon')
|
|||
|
|
const selectedRecipe = ref(null)
|
|||
|
|
|
|||
|
|
// 分类列表
|
|||
|
|
const categories = computed(() => {
|
|||
|
|
const allCats = getAllCategories()
|
|||
|
|
return allCats.map(cat => ({
|
|||
|
|
id: cat.id,
|
|||
|
|
name: cat.name,
|
|||
|
|
icon: cat.icon
|
|||
|
|
}))
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 可制作的配方
|
|||
|
|
const craftableRecipes = computed(() => {
|
|||
|
|
return getCraftableRecipes(player)
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 当前分类的配方
|
|||
|
|
const filteredRecipes = computed(() => {
|
|||
|
|
return getRecipesByCategory(player, selectedCategory.value)
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 活动中的制造任务
|
|||
|
|
const activeCraftingTask = computed(() => {
|
|||
|
|
const activeTasks = getActiveTasks(game)
|
|||
|
|
return activeTasks.find(t => t.type === TASK_TYPES.CRAFTING)
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 获取选中分类名称
|
|||
|
|
function getSelectedCategoryName() {
|
|||
|
|
const cat = getCategoryInfo(selectedCategory.value)
|
|||
|
|
return cat.name
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取制造技能等级
|
|||
|
|
function getCraftingSkillLevel() {
|
|||
|
|
const craftingSkill = player.skills.crafting
|
|||
|
|
if (!craftingSkill || !craftingSkill.unlocked) {
|
|||
|
|
return '未解锁'
|
|||
|
|
}
|
|||
|
|
return `Lv.${craftingSkill.level}`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取配方描述
|
|||
|
|
function getRecipeDescription(recipe) {
|
|||
|
|
const item = ITEM_CONFIG[recipe.resultItem]
|
|||
|
|
return item?.description || ''
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查材料是否缺失
|
|||
|
|
function isMaterialMissing(recipe, materialId) {
|
|||
|
|
const missing = recipe.missingMaterials?.find(m => m.itemId === materialId)
|
|||
|
|
return !!missing
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取材料图标
|
|||
|
|
function getMaterialIcon(itemId) {
|
|||
|
|
const item = ITEM_CONFIG[itemId]
|
|||
|
|
return item?.icon || '📦'
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取材料名称
|
|||
|
|
function getMaterialName(itemId) {
|
|||
|
|
const item = ITEM_CONFIG[itemId]
|
|||
|
|
return item?.name || itemId
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取材料拥有数量
|
|||
|
|
function getMaterialCount(itemId) {
|
|||
|
|
const invItem = player.inventory.find(i => i.id === itemId)
|
|||
|
|
return invItem?.count || 0
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取制造时间显示
|
|||
|
|
function getCraftingTimeDisplay(recipe) {
|
|||
|
|
const time = calculateCraftingTime(player, recipe)
|
|||
|
|
if (time >= 60) {
|
|||
|
|
return `${Math.floor(time / 60)}分${time % 60}秒`
|
|||
|
|
}
|
|||
|
|
return `${time}秒`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取成功率显示
|
|||
|
|
function getSuccessRateDisplay(recipe) {
|
|||
|
|
const rate = calculateSuccessRate(player, recipe)
|
|||
|
|
return `${rate}%`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取成功率样式类
|
|||
|
|
function getSuccessRateClass(recipe) {
|
|||
|
|
const rate = calculateSuccessRate(player, recipe)
|
|||
|
|
if (rate >= 80) return 'success-rate--high'
|
|||
|
|
if (rate >= 50) return 'success-rate--medium'
|
|||
|
|
return 'success-rate--low'
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取所需技能显示
|
|||
|
|
function getRequiredSkillDisplay(recipe) {
|
|||
|
|
const skill = player.skills[recipe.requiredSkill]
|
|||
|
|
if (!skill || !skill.unlocked) {
|
|||
|
|
return `需要 ${recipe.requiredSkill} Lv.${recipe.requiredSkillLevel}`
|
|||
|
|
}
|
|||
|
|
if (skill.level < recipe.requiredSkillLevel) {
|
|||
|
|
return `${recipe.requiredSkill} Lv.${skill.level}/${recipe.requiredSkillLevel}`
|
|||
|
|
}
|
|||
|
|
return `${recipe.requiredSkill} Lv.${skill.level}`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取品质颜色
|
|||
|
|
function getQualityColor(quality) {
|
|||
|
|
const colors = {
|
|||
|
|
1: '#9e9e9e', // 垃圾
|
|||
|
|
2: '#ffffff', // 普通
|
|||
|
|
3: '#4caf50', // 优秀
|
|||
|
|
4: '#2196f3', // 稀有
|
|||
|
|
5: '#9c27b0', // 史诗
|
|||
|
|
6: '#ff9800' // 传说
|
|||
|
|
}
|
|||
|
|
return colors[quality] || '#ffffff'
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取制造进度
|
|||
|
|
function getCraftingProgress() {
|
|||
|
|
if (!activeCraftingTask.value) return 0
|
|||
|
|
return Math.floor(activeCraftingTask.value.progress.percentage || 0)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取制造物品名称
|
|||
|
|
function getCraftingItemName() {
|
|||
|
|
if (!activeCraftingTask.value) return ''
|
|||
|
|
const recipeId = activeCraftingTask.value.data.recipeId
|
|||
|
|
const item = ITEM_CONFIG[recipeId]
|
|||
|
|
return item?.name || recipeId
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 选择配方
|
|||
|
|
function selectRecipe(recipe) {
|
|||
|
|
selectedRecipe.value = recipe
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 开始制造
|
|||
|
|
function startCraftingRecipe() {
|
|||
|
|
if (!selectedRecipe.value) return
|
|||
|
|
|
|||
|
|
const result = startCrafting(game, player, selectedRecipe.value.id)
|
|||
|
|
|
|||
|
|
if (result.success) {
|
|||
|
|
game.addLog(result.message, 'success')
|
|||
|
|
selectedRecipe.value = null
|
|||
|
|
} else {
|
|||
|
|
game.addLog(result.message, 'error')
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 关闭抽屉
|
|||
|
|
function close() {
|
|||
|
|
game.closeDrawer()
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style lang="scss" scoped>
|
|||
|
|
.crafting-drawer {
|
|||
|
|
height: 100%;
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
background: #1a1a2e;
|
|||
|
|
color: #eee;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.drawer-header {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
align-items: center;
|
|||
|
|
padding: 16px;
|
|||
|
|
background: #16162a;
|
|||
|
|
border-bottom: 1px solid #333;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.header-left {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 4px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.drawer-title {
|
|||
|
|
font-size: 18px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.drawer-subtitle {
|
|||
|
|
font-size: 12px;
|
|||
|
|
color: #888;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.drawer-close {
|
|||
|
|
font-size: 28px;
|
|||
|
|
color: #888;
|
|||
|
|
cursor: pointer;
|
|||
|
|
padding: 0 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.crafting-skill-info {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
padding: 12px 16px;
|
|||
|
|
background: #1e1e36;
|
|||
|
|
gap: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.skill-info__label {
|
|||
|
|
font-size: 12px;
|
|||
|
|
color: #888;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.skill-info__level {
|
|||
|
|
font-size: 14px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: #4caf50;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-list {
|
|||
|
|
flex: 1;
|
|||
|
|
padding: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-item {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
align-items: center;
|
|||
|
|
padding: 12px;
|
|||
|
|
margin-bottom: 8px;
|
|||
|
|
background: #252540;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
border: 1px solid #333;
|
|||
|
|
transition: all 0.2s;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-item--disabled {
|
|||
|
|
opacity: 0.5;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-item__main {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 12px;
|
|||
|
|
flex: 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-item__icon {
|
|||
|
|
font-size: 24px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-item__info {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 4px;
|
|||
|
|
flex: 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-item__name {
|
|||
|
|
font-size: 14px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-item__desc {
|
|||
|
|
font-size: 12px;
|
|||
|
|
color: #888;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-materials {
|
|||
|
|
display: flex;
|
|||
|
|
flex-wrap: wrap;
|
|||
|
|
gap: 4px;
|
|||
|
|
margin-top: 4px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.material-tag {
|
|||
|
|
font-size: 10px;
|
|||
|
|
padding: 2px 6px;
|
|||
|
|
background: #1e1e36;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.material-tag--missing {
|
|||
|
|
color: #f44336;
|
|||
|
|
background: #3a1a1a;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-item__right {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
align-items: flex-end;
|
|||
|
|
gap: 4px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-time {
|
|||
|
|
font-size: 12px;
|
|||
|
|
color: #4caf50;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-success-rate {
|
|||
|
|
font-size: 12px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.success-rate--high {
|
|||
|
|
color: #4caf50;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.success-rate--medium {
|
|||
|
|
color: #ff9800;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.success-rate--low {
|
|||
|
|
color: #f44336;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-empty {
|
|||
|
|
padding: 32px;
|
|||
|
|
text-align: center;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-empty__text {
|
|||
|
|
color: #888;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.crafting-progress {
|
|||
|
|
padding: 16px;
|
|||
|
|
background: #1e1e36;
|
|||
|
|
border-top: 1px solid #333;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.progress-header {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
margin-bottom: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.progress-title {
|
|||
|
|
font-size: 14px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.progress-percent {
|
|||
|
|
font-size: 14px;
|
|||
|
|
color: #4caf50;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.progress-bar {
|
|||
|
|
height: 8px;
|
|||
|
|
background: #333;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
overflow: hidden;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.progress-bar__fill {
|
|||
|
|
height: 100%;
|
|||
|
|
background: linear-gradient(90deg, #4caf50, #8bc34a);
|
|||
|
|
transition: width 0.3s;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.progress-item {
|
|||
|
|
display: block;
|
|||
|
|
margin-top: 8px;
|
|||
|
|
font-size: 12px;
|
|||
|
|
color: #888;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 配方详情弹窗
|
|||
|
|
.recipe-detail-popup {
|
|||
|
|
position: fixed;
|
|||
|
|
top: 0;
|
|||
|
|
left: 0;
|
|||
|
|
right: 0;
|
|||
|
|
bottom: 0;
|
|||
|
|
background: rgba(0, 0, 0, 0.8);
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
z-index: 1000;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-detail {
|
|||
|
|
width: 90%;
|
|||
|
|
max-width: 400px;
|
|||
|
|
max-height: 80%;
|
|||
|
|
background: #1a1a2e;
|
|||
|
|
border-radius: 12px;
|
|||
|
|
padding: 16px;
|
|||
|
|
overflow-y: auto;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-detail__header {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 12px;
|
|||
|
|
margin-bottom: 16px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-detail__icon {
|
|||
|
|
font-size: 32px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-detail__name {
|
|||
|
|
font-size: 18px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-detail__stats {
|
|||
|
|
margin-bottom: 16px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.stat-row {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
padding: 8px 0;
|
|||
|
|
border-bottom: 1px solid #333;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.stat-label {
|
|||
|
|
color: #888;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.stat-value {
|
|||
|
|
font-weight: bold;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-detail__materials {
|
|||
|
|
margin-bottom: 16px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.materials-title {
|
|||
|
|
display: block;
|
|||
|
|
margin-bottom: 8px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.materials-list {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.material-item {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 8px;
|
|||
|
|
padding: 8px;
|
|||
|
|
background: #252540;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.material-item--missing {
|
|||
|
|
background: #3a1a1a;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.material-item__icon {
|
|||
|
|
font-size: 20px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.material-item__name {
|
|||
|
|
flex: 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.material-item__count {
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: #4caf50;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.material-item__have {
|
|||
|
|
font-size: 12px;
|
|||
|
|
color: #888;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-detail__quality {
|
|||
|
|
margin-bottom: 16px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.quality-title {
|
|||
|
|
display: block;
|
|||
|
|
margin-bottom: 8px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.quality-range {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.quality-range__arrow {
|
|||
|
|
color: #888;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.recipe-detail__actions {
|
|||
|
|
display: flex;
|
|||
|
|
gap: 8px;
|
|||
|
|
}
|
|||
|
|
</style>
|