339 lines
8.7 KiB
Vue
339 lines
8.7 KiB
Vue
<template>
|
|
<div class="materials">
|
|
<el-card>
|
|
<template #header>
|
|
<div class="card-header">
|
|
<span>材料库</span>
|
|
<el-button type="primary" @click="handleAdd">新增材料</el-button>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- 搜索表单 -->
|
|
<el-form :inline="true" :model="searchForm" class="search-form">
|
|
<el-form-item label="材料名称">
|
|
<el-input v-model="searchForm.name" placeholder="请输入材料名称" clearable />
|
|
</el-form-item>
|
|
|
|
<el-form-item label="专业类别">
|
|
<el-select v-model="searchForm.major_category" placeholder="请选择专业类别" clearable>
|
|
<el-option label="建筑" value="architecture" />
|
|
<el-option label="景观" value="landscape" />
|
|
<el-option label="设备" value="equipment" />
|
|
<el-option label="装修" value="decoration" />
|
|
</el-select>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="状态">
|
|
<el-select v-model="searchForm.status" placeholder="请选择状态" clearable>
|
|
<el-option label="创建中" value="draft" />
|
|
<el-option label="待审核" value="pending" />
|
|
<el-option label="已审核" value="approved" />
|
|
</el-select>
|
|
</el-form-item>
|
|
|
|
<el-form-item>
|
|
<el-button type="primary" @click="handleSearch">搜索</el-button>
|
|
<el-button @click="handleReset">重置</el-button>
|
|
</el-form-item>
|
|
</el-form>
|
|
|
|
<!-- 材料表格 -->
|
|
<el-table :data="tableData" stripe v-loading="loading">
|
|
<el-table-column prop="name" label="材料名称" />
|
|
<el-table-column prop="major_category_display" label="专业类别" />
|
|
<el-table-column prop="material_category" label="材料分类" />
|
|
<el-table-column prop="material_subcategory" label="材料子类" />
|
|
<el-table-column prop="factory_name" label="所属品牌" />
|
|
<el-table-column prop="status_display" label="状态">
|
|
<template #default="{ row }">
|
|
<el-tag :type="getStatusType(row.status)">
|
|
{{ row.status_display }}
|
|
</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="操作" width="200">
|
|
<template #default="{ row }">
|
|
<el-button link type="primary" @click="handleView(row)">查看</el-button>
|
|
<el-button link type="primary" @click="handleEdit(row)" v-if="canEdit(row)">编辑</el-button>
|
|
<el-button link type="primary" @click="handleSubmit(row)" v-if="canSubmit(row)">提交</el-button>
|
|
<el-button link type="success" @click="handleApprove(row)" v-if="canApprove(row)">通过</el-button>
|
|
<el-button link type="danger" @click="handleReject(row)" v-if="canReject(row)">拒绝</el-button>
|
|
<el-button link type="danger" @click="handleDelete(row)" v-if="canDelete(row)">删除</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<!-- 分页 -->
|
|
<div class="pagination">
|
|
<el-pagination
|
|
v-model:current-page="pagination.page"
|
|
v-model:page-size="pagination.size"
|
|
:page-sizes="[10, 20, 50, 100]"
|
|
layout="total, sizes, prev, pager, next, jumper"
|
|
:total="pagination.total"
|
|
@size-change="handleSizeChange"
|
|
@current-change="handleCurrentChange"
|
|
/>
|
|
</div>
|
|
</el-card>
|
|
|
|
<!-- 材料表单对话框 -->
|
|
<MaterialForm
|
|
v-if="showForm"
|
|
:visible="showForm"
|
|
:material="currentMaterial"
|
|
@close="showForm = false"
|
|
@success="handleFormSuccess"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, reactive, onMounted, computed } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import { useUserStore } from '@/stores/user'
|
|
import { getMaterialList, deleteMaterial, submitMaterial, approveMaterial, rejectMaterial } from '@/api/material'
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
import MaterialForm from '@/components/MaterialForm.vue'
|
|
|
|
const router = useRouter()
|
|
const userStore = useUserStore()
|
|
|
|
const isAdmin = computed(() => userStore.isAdmin)
|
|
|
|
// 表格数据
|
|
const tableData = ref([])
|
|
const loading = ref(false)
|
|
|
|
// 搜索表单
|
|
const searchForm = reactive({
|
|
name: '',
|
|
major_category: '',
|
|
status: ''
|
|
})
|
|
|
|
// 分页
|
|
const pagination = reactive({
|
|
page: 1,
|
|
size: 10,
|
|
total: 0
|
|
})
|
|
|
|
// 表单对话框
|
|
const showForm = ref(false)
|
|
const currentMaterial = ref(null)
|
|
|
|
// 获取状态类型
|
|
const getStatusType = (status) => {
|
|
const statusMap = {
|
|
draft: 'info',
|
|
pending: 'warning',
|
|
approved: 'success'
|
|
}
|
|
return statusMap[status] || 'info'
|
|
}
|
|
|
|
// 判断是否可以编辑
|
|
const canEdit = (row) => {
|
|
if (isAdmin.value) return true
|
|
return row.status === 'draft' && userStore.factoryId === row.factory
|
|
}
|
|
|
|
// 判断是否可以提交
|
|
const canSubmit = (row) => {
|
|
return row.status === 'draft' && (isAdmin.value || userStore.factoryId === row.factory)
|
|
}
|
|
|
|
// 判断是否可以审核
|
|
const canApprove = (row) => {
|
|
return isAdmin.value && row.status === 'pending'
|
|
}
|
|
|
|
// 判断是否可以拒绝
|
|
const canReject = (row) => {
|
|
return isAdmin.value && row.status === 'pending'
|
|
}
|
|
|
|
// 判断是否可以删除
|
|
const canDelete = (row) => {
|
|
if (isAdmin.value) return true
|
|
return row.status === 'draft' && userStore.factoryId === row.factory
|
|
}
|
|
|
|
// 加载数据
|
|
const loadData = async () => {
|
|
loading.value = true
|
|
try {
|
|
const params = {
|
|
page: pagination.page,
|
|
page_size: pagination.size,
|
|
...searchForm
|
|
}
|
|
const data = await getMaterialList(params)
|
|
tableData.value = data.results || data
|
|
pagination.total = data.count || data.length
|
|
} catch (error) {
|
|
console.error('加载数据失败:', error)
|
|
ElMessage.error('加载数据失败')
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
// 搜索
|
|
const handleSearch = () => {
|
|
pagination.page = 1
|
|
loadData()
|
|
}
|
|
|
|
// 重置
|
|
const handleReset = () => {
|
|
Object.assign(searchForm, {
|
|
name: '',
|
|
major_category: '',
|
|
status: ''
|
|
})
|
|
pagination.page = 1
|
|
loadData()
|
|
}
|
|
|
|
// 分页大小变化
|
|
const handleSizeChange = (size) => {
|
|
pagination.size = size
|
|
loadData()
|
|
}
|
|
|
|
// 当前页变化
|
|
const handleCurrentChange = (page) => {
|
|
pagination.page = page
|
|
loadData()
|
|
}
|
|
|
|
// 新增
|
|
const handleAdd = () => {
|
|
currentMaterial.value = null
|
|
showForm.value = true
|
|
}
|
|
|
|
// 查看
|
|
const handleView = (row) => {
|
|
router.push(`/materials/${row.id}`)
|
|
}
|
|
|
|
// 编辑
|
|
const handleEdit = (row) => {
|
|
currentMaterial.value = { ...row }
|
|
showForm.value = true
|
|
}
|
|
|
|
// 提交
|
|
const handleSubmit = async (row) => {
|
|
try {
|
|
await ElMessageBox.confirm('确认提交该材料进行审核吗?', '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
})
|
|
|
|
await submitMaterial(row.id)
|
|
ElMessage.success('提交成功')
|
|
loadData()
|
|
} catch (error) {
|
|
if (error !== 'cancel') {
|
|
console.error('提交失败:', error)
|
|
ElMessage.error('提交失败')
|
|
}
|
|
}
|
|
}
|
|
|
|
// 审核通过
|
|
const handleApprove = async (row) => {
|
|
try {
|
|
await ElMessageBox.confirm('确认审核通过该材料吗?', '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
})
|
|
|
|
await approveMaterial(row.id)
|
|
ElMessage.success('审核通过')
|
|
loadData()
|
|
} catch (error) {
|
|
if (error !== 'cancel') {
|
|
console.error('审核失败:', error)
|
|
ElMessage.error('审核失败')
|
|
}
|
|
}
|
|
}
|
|
|
|
// 审核拒绝
|
|
const handleReject = async (row) => {
|
|
try {
|
|
await ElMessageBox.confirm('确认拒绝该材料吗?', '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
})
|
|
|
|
await rejectMaterial(row.id)
|
|
ElMessage.success('已拒绝')
|
|
loadData()
|
|
} catch (error) {
|
|
if (error !== 'cancel') {
|
|
console.error('操作失败:', error)
|
|
ElMessage.error('操作失败')
|
|
}
|
|
}
|
|
}
|
|
|
|
// 删除
|
|
const handleDelete = async (row) => {
|
|
try {
|
|
await ElMessageBox.confirm('确认删除该材料吗?', '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
})
|
|
|
|
await deleteMaterial(row.id)
|
|
ElMessage.success('删除成功')
|
|
loadData()
|
|
} catch (error) {
|
|
if (error !== 'cancel') {
|
|
console.error('删除失败:', error)
|
|
ElMessage.error('删除失败')
|
|
}
|
|
}
|
|
}
|
|
|
|
// 表单成功回调
|
|
const handleFormSuccess = () => {
|
|
showForm.value = false
|
|
loadData()
|
|
}
|
|
|
|
onMounted(() => {
|
|
loadData()
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.materials {
|
|
.card-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.search-form {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.pagination {
|
|
margin-top: 20px;
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
}
|
|
}
|
|
</style>
|