<template>
|
<div class="app-container">
|
<el-card shadow="never">
|
<div class="toolbar">
|
<el-input
|
v-model="query.keyword"
|
placeholder="搜索名称/类别"
|
clearable
|
style="width: 240px"
|
@keyup.enter="handleSearch"
|
/>
|
<el-select
|
v-model="query.status"
|
placeholder="状态"
|
clearable
|
style="width: 140px; margin-left: 12px"
|
>
|
<el-option label="启用" value="启用" />
|
<el-option label="停用" value="停用" />
|
</el-select>
|
<el-button type="primary" style="margin-left: 12px" @click="handleSearch">查询</el-button>
|
<el-button @click="resetQuery">重置</el-button>
|
<el-button type="success" plain style="float: right" @click="openCreate">新增</el-button>
|
</div>
|
|
<el-table :data="pagedList" border style="width: 100%" height="480">
|
<el-table-column prop="id" label="编号" width="90" sortable />
|
<el-table-column prop="name" label="名称" min-width="140" />
|
<el-table-column prop="category" label="类别" width="120" />
|
<el-table-column prop="stock" label="库存" width="100" sortable />
|
<el-table-column prop="price" label="单价(¥)" width="120">
|
<template #default="scope">{{ formatPrice(scope.row.price) }}</template>
|
</el-table-column>
|
<el-table-column label="状态" width="120">
|
<template #default="scope">
|
<el-tag :type="scope.row.status === '启用' ? 'success' : 'info'">{{ scope.row.status }}</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column prop="updatedAt" label="更新时间" min-width="160" />
|
<el-table-column label="操作" width="180" fixed="right">
|
<template #default="scope">
|
<el-button link type="primary" @click="openEdit(scope.row)">编辑</el-button>
|
<el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<div class="pagination">
|
<el-pagination
|
background
|
layout="total, sizes, prev, pager, next, jumper"
|
:total="filteredList.length"
|
:page-sizes="[5, 10, 20, 50]"
|
:page-size="pager.pageSize"
|
:current-page="pager.pageNum"
|
@size-change="handleSizeChange"
|
@current-change="handleCurrentChange"
|
/>
|
</div>
|
</el-card>
|
|
<el-dialog v-model="dialogVisible" :title="isEdit ? '编辑' : '新增'" width="520px">
|
<el-form :model="form" :rules="rules" ref="formRef" label-width="90px">
|
<el-form-item label="名称" prop="name">
|
<el-input v-model="form.name" placeholder="请输入名称" />
|
</el-form-item>
|
<el-form-item label="类别" prop="category">
|
<el-select v-model="form.category" placeholder="请选择类别" style="width: 100%">
|
<el-option label="原料" value="原料" />
|
<el-option label="半成品" value="半成品" />
|
<el-option label="成品" value="成品" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="库存" prop="stock">
|
<el-input v-model.number="form.stock" type="number" min="0" />
|
</el-form-item>
|
<el-form-item label="单价(¥)" prop="price">
|
<el-input v-model.number="form.price" type="number" min="0" step="0.01" />
|
</el-form-item>
|
<el-form-item label="状态" prop="status">
|
<el-radio-group v-model="form.status">
|
<el-radio label="启用">启用</el-radio>
|
<el-radio label="停用">停用</el-radio>
|
</el-radio-group>
|
</el-form-item>
|
</el-form>
|
<template #footer>
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
</template>
|
</el-dialog>
|
</div>
|
|
</template>
|
|
<script setup>
|
import { ref, reactive, computed, nextTick } from 'vue'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
defineOptions({ name: 'FakePage' })
|
|
const query = reactive({
|
keyword: '',
|
status: ''
|
})
|
|
const pager = reactive({
|
pageNum: 1,
|
pageSize: 10
|
})
|
|
const allList = ref(generateMockData())
|
|
const filteredList = computed(() => {
|
const keyword = (query.keyword || '').trim()
|
const status = query.status
|
return allList.value.filter(item => {
|
const hitKeyword = !keyword || item.name.includes(keyword) || item.category.includes(keyword)
|
const hitStatus = !status || item.status === status
|
return hitKeyword && hitStatus
|
})
|
})
|
|
const pagedList = computed(() => {
|
const start = (pager.pageNum - 1) * pager.pageSize
|
const end = start + pager.pageSize
|
return filteredList.value.slice(start, end)
|
})
|
|
function handleSearch() {
|
pager.pageNum = 1
|
}
|
|
function resetQuery() {
|
query.keyword = ''
|
query.status = ''
|
pager.pageNum = 1
|
}
|
|
function handleSizeChange(size) {
|
pager.pageSize = size
|
pager.pageNum = 1
|
}
|
|
function handleCurrentChange(page) {
|
pager.pageNum = page
|
}
|
|
function formatPrice(val) {
|
return Number(val || 0).toFixed(2)
|
}
|
|
// 新增/编辑
|
const dialogVisible = ref(false)
|
const isEdit = ref(false)
|
const formRef = ref()
|
const form = reactive({ id: null, name: '', category: '', stock: 0, price: 0, status: '启用' })
|
|
const rules = {
|
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
category: [{ required: true, message: '请选择类别', trigger: 'change' }],
|
stock: [{ required: true, message: '请输入库存', trigger: 'blur' }],
|
price: [{ required: true, message: '请输入单价', trigger: 'blur' }]
|
}
|
|
function openCreate() {
|
isEdit.value = false
|
Object.assign(form, { id: null, name: '', category: '', stock: 0, price: 0, status: '启用' })
|
dialogVisible.value = true
|
nextTick(() => formRef.value?.clearValidate?.())
|
}
|
|
function openEdit(row) {
|
isEdit.value = true
|
Object.assign(form, JSON.parse(JSON.stringify(row)))
|
dialogVisible.value = true
|
nextTick(() => formRef.value?.clearValidate?.())
|
}
|
|
function submitForm() {
|
formRef.value?.validate?.((valid) => {
|
if (!valid) return
|
if (isEdit.value) {
|
const index = allList.value.findIndex(x => x.id === form.id)
|
if (index > -1) {
|
allList.value[index] = { ...form, updatedAt: nowString() }
|
ElMessage.success('已保存')
|
}
|
} else {
|
const newId = Date.now()
|
allList.value.unshift({ ...form, id: newId, updatedAt: nowString() })
|
ElMessage.success('已新增')
|
}
|
dialogVisible.value = false
|
})
|
}
|
|
function handleDelete(row) {
|
ElMessageBox.confirm(`确认删除【${row.name}】吗?`, '提示', { type: 'warning' })
|
.then(() => {
|
allList.value = allList.value.filter(x => x.id !== row.id)
|
ElMessage.success('已删除')
|
})
|
.catch(() => {})
|
}
|
|
function generateMockData() {
|
const categories = ['原料', '半成品', '成品']
|
const statusOptions = ['启用', '停用']
|
const list = []
|
for (let i = 1; i <= 36; i++) {
|
list.push({
|
id: i,
|
name: `物料-${i.toString().padStart(3, '0')}`,
|
category: categories[i % categories.length],
|
stock: Math.floor(Math.random() * 1000),
|
price: (Math.random() * 500 + 10).toFixed(2),
|
status: statusOptions[i % 2],
|
updatedAt: nowString()
|
})
|
}
|
return list
|
}
|
|
function nowString() {
|
const d = new Date()
|
const yyyy = d.getFullYear()
|
const MM = String(d.getMonth() + 1).padStart(2, '0')
|
const dd = String(d.getDate()).padStart(2, '0')
|
const hh = String(d.getHours()).padStart(2, '0')
|
const mm = String(d.getMinutes()).padStart(2, '0')
|
const ss = String(d.getSeconds()).padStart(2, '0')
|
return `${yyyy}-${MM}-${dd} ${hh}:${mm}:${ss}`
|
}
|
</script>
|
|
<style scoped>
|
.toolbar {
|
margin-bottom: 12px;
|
}
|
.pagination {
|
margin-top: 12px;
|
text-align: right;
|
}
|
</style>
|