325 lines
10 KiB
Vue
325 lines
10 KiB
Vue
<template>
|
||
<div class="material-detail">
|
||
<el-card v-loading="loading">
|
||
<template #header>
|
||
<div class="card-header">
|
||
<el-button link @click="handleBack">
|
||
<el-icon><ArrowLeft /></el-icon>
|
||
返回
|
||
</el-button>
|
||
<div class="header-actions">
|
||
<el-button v-if="canEdit" type="primary" @click="handleEdit">编辑</el-button>
|
||
<el-button v-if="canSubmit" type="warning" @click="handleSubmit">提交审核</el-button>
|
||
<el-button v-if="canApprove" type="success" @click="handleApprove">审核通过</el-button>
|
||
<el-button v-if="canReject" type="danger" @click="handleReject">审核拒绝</el-button>
|
||
<el-button v-if="canDelete" type="danger" @click="handleDelete">删除</el-button>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="材料名称">{{ material.name }}</el-descriptions-item>
|
||
<el-descriptions-item label="专业类别">{{ material.major_category_display }}</el-descriptions-item>
|
||
<el-descriptions-item label="材料分类">{{ material.material_category }}</el-descriptions-item>
|
||
<el-descriptions-item label="材料子类">{{ material.material_subcategory }}</el-descriptions-item>
|
||
<el-descriptions-item label="规格型号">{{ material.spec || '-' }}</el-descriptions-item>
|
||
<el-descriptions-item label="符合标准">{{ material.standard || '-' }}</el-descriptions-item>
|
||
<el-descriptions-item label="应用场景">{{ material.application_scene_display || '-' }}</el-descriptions-item>
|
||
<el-descriptions-item label="所属品牌">{{ material.factory_name }}</el-descriptions-item>
|
||
<el-descriptions-item label="状态">
|
||
<el-tag :type="getStatusType(material.status)">
|
||
{{ material.status_display }}
|
||
</el-tag>
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
|
||
<el-divider>应用场景说明</el-divider>
|
||
<div class="content-text">{{ material.application_desc || '暂无' }}</div>
|
||
|
||
<el-divider>替代材料信息</el-divider>
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="替代材料类型">{{ material.replace_type_display || '-' }}</el-descriptions-item>
|
||
<el-descriptions-item label="竞争优势">{{ material.advantage_display || '-' }}</el-descriptions-item>
|
||
</el-descriptions>
|
||
<div class="content-text">{{ material.advantage_desc || '暂无' }}</div>
|
||
|
||
<el-divider>成本信息</el-divider>
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="成本对比百分数">
|
||
{{ material.cost_compare ? `${material.cost_compare}%` : '-' }}
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
<div class="content-text">{{ material.cost_desc || '暂无' }}</div>
|
||
|
||
<el-divider>案例</el-divider>
|
||
<div class="content-text">{{ material.cases || '暂无' }}</div>
|
||
|
||
<el-divider>宣传页图片</el-divider>
|
||
<div v-if="material.brochure_url" class="brochure-container">
|
||
<el-image
|
||
:src="material.brochure_url"
|
||
fit="contain"
|
||
:preview-src-list="[material.brochure_url]"
|
||
style="max-width: 100%; max-height: 500px;"
|
||
/>
|
||
</div>
|
||
<div v-else class="content-text">暂无</div>
|
||
|
||
<el-divider>星级评价</el-divider>
|
||
<el-row :gutter="20">
|
||
<el-col :span="8">
|
||
<div class="star-item">
|
||
<span class="star-label">质量提升等级:</span>
|
||
<el-rate v-model="material.quality_level" disabled :max="3" />
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="star-item">
|
||
<span class="star-label">耐久可靠等级:</span>
|
||
<el-rate v-model="material.durability_level" disabled :max="3" />
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="star-item">
|
||
<span class="star-label">环保健康等级:</span>
|
||
<el-rate v-model="material.eco_level" disabled :max="3" />
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row :gutter="20" style="margin-top: 20px;">
|
||
<el-col :span="8">
|
||
<div class="star-item">
|
||
<span class="star-label">循环低碳等级:</span>
|
||
<el-rate v-model="material.carbon_level" disabled :max="3" />
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="star-item">
|
||
<span class="star-label">总评分等级:</span>
|
||
<el-rate v-model="material.score_level" disabled :max="3" />
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-divider>施工与限制</el-divider>
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="连接方式">{{ material.connection_method || '-' }}</el-descriptions-item>
|
||
<el-descriptions-item label="施工工艺">{{ material.construction_method || '-' }}</el-descriptions-item>
|
||
</el-descriptions>
|
||
<div class="content-text">{{ material.limit_condition || '暂无' }}</div>
|
||
|
||
<el-divider>其他信息</el-divider>
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="创建时间">{{ formatDate(material.created_at) }}</el-descriptions-item>
|
||
<el-descriptions-item label="更新时间">{{ formatDate(material.updated_at) }}</el-descriptions-item>
|
||
</el-descriptions>
|
||
</el-card>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, onMounted } from 'vue'
|
||
import { useRoute, useRouter } from 'vue-router'
|
||
import { useUserStore } from '@/stores/user'
|
||
import { getMaterialDetail, deleteMaterial, submitMaterial, approveMaterial, rejectMaterial } from '@/api/material'
|
||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||
|
||
const route = useRoute()
|
||
const router = useRouter()
|
||
const userStore = useUserStore()
|
||
|
||
const material = ref({})
|
||
const loading = ref(false)
|
||
|
||
const isAdmin = computed(() => userStore.isAdmin)
|
||
|
||
// 判断是否可以编辑
|
||
const canEdit = computed(() => {
|
||
if (isAdmin.value) return true
|
||
return material.value.status === 'draft' && userStore.factoryId === material.value.factory
|
||
})
|
||
|
||
// 判断是否可以提交
|
||
const canSubmit = computed(() => {
|
||
return material.value.status === 'draft' && (isAdmin.value || userStore.factoryId === material.value.factory)
|
||
})
|
||
|
||
// 判断是否可以审核
|
||
const canApprove = computed(() => {
|
||
return isAdmin.value && material.value.status === 'pending'
|
||
})
|
||
|
||
// 判断是否可以拒绝
|
||
const canReject = computed(() => {
|
||
return isAdmin.value && material.value.status === 'pending'
|
||
})
|
||
|
||
// 判断是否可以删除
|
||
const canDelete = computed(() => {
|
||
if (isAdmin.value) return true
|
||
return material.value.status === 'draft' && userStore.factoryId === material.value.factory
|
||
})
|
||
|
||
// 获取状态类型
|
||
const getStatusType = (status) => {
|
||
const statusMap = {
|
||
draft: 'info',
|
||
pending: 'warning',
|
||
approved: 'success'
|
||
}
|
||
return statusMap[status] || 'info'
|
||
}
|
||
|
||
// 格式化日期
|
||
const formatDate = (dateStr) => {
|
||
if (!dateStr) return '-'
|
||
const date = new Date(dateStr)
|
||
return date.toLocaleString('zh-CN')
|
||
}
|
||
|
||
// 加载数据
|
||
const loadData = async () => {
|
||
loading.value = true
|
||
try {
|
||
const id = route.params.id
|
||
material.value = await getMaterialDetail(id)
|
||
} catch (error) {
|
||
console.error('加载数据失败:', error)
|
||
ElMessage.error('加载数据失败')
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 返回
|
||
const handleBack = () => {
|
||
router.back()
|
||
}
|
||
|
||
// 编辑
|
||
const handleEdit = () => {
|
||
router.push(`/materials/${material.value.id}/edit`)
|
||
}
|
||
|
||
// 提交
|
||
const handleSubmit = async () => {
|
||
try {
|
||
await ElMessageBox.confirm('确认提交该材料进行审核吗?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
})
|
||
|
||
await submitMaterial(material.value.id)
|
||
ElMessage.success('提交成功')
|
||
loadData()
|
||
} catch (error) {
|
||
if (error !== 'cancel') {
|
||
console.error('提交失败:', error)
|
||
ElMessage.error('提交失败')
|
||
}
|
||
}
|
||
}
|
||
|
||
// 审核通过
|
||
const handleApprove = async () => {
|
||
try {
|
||
await ElMessageBox.confirm('确认审核通过该材料吗?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
})
|
||
|
||
await approveMaterial(material.value.id)
|
||
ElMessage.success('审核通过')
|
||
loadData()
|
||
} catch (error) {
|
||
if (error !== 'cancel') {
|
||
console.error('审核失败:', error)
|
||
ElMessage.error('审核失败')
|
||
}
|
||
}
|
||
}
|
||
|
||
// 审核拒绝
|
||
const handleReject = async () => {
|
||
try {
|
||
await ElMessageBox.confirm('确认拒绝该材料吗?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
})
|
||
|
||
await rejectMaterial(material.value.id)
|
||
ElMessage.success('已拒绝')
|
||
loadData()
|
||
} catch (error) {
|
||
if (error !== 'cancel') {
|
||
console.error('操作失败:', error)
|
||
ElMessage.error('操作失败')
|
||
}
|
||
}
|
||
}
|
||
|
||
// 删除
|
||
const handleDelete = async () => {
|
||
try {
|
||
await ElMessageBox.confirm('确认删除该材料吗?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
})
|
||
|
||
await deleteMaterial(material.value.id)
|
||
ElMessage.success('删除成功')
|
||
router.push('/materials')
|
||
} catch (error) {
|
||
if (error !== 'cancel') {
|
||
console.error('删除失败:', error)
|
||
ElMessage.error('删除失败')
|
||
}
|
||
}
|
||
}
|
||
|
||
onMounted(() => {
|
||
loadData()
|
||
})
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.material-detail {
|
||
.card-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
|
||
.header-actions {
|
||
display: flex;
|
||
gap: 10px;
|
||
}
|
||
}
|
||
|
||
.content-text {
|
||
padding: 10px 0;
|
||
line-height: 1.8;
|
||
white-space: pre-wrap;
|
||
}
|
||
|
||
.brochure-container {
|
||
display: flex;
|
||
justify-content: center;
|
||
padding: 20px 0;
|
||
}
|
||
|
||
.star-item {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.star-label {
|
||
margin-right: 10px;
|
||
color: #606266;
|
||
}
|
||
}
|
||
}
|
||
</style>
|