feat:mpr-物资管理前端(申购单、入库单、物料库存、领用记录)
- 新增 mpr API 接口定义(申购单、入库单、物料库存、领用单 CRUD) - 新增申购单列表页与表单页,支持明细内联编辑和一次性提交审批 - 新增入库单列表页与表单页,支持仓库下拉选择和入库明细管理 - 新增物料库存列表页,支持状态筛选(闲置/领用中/已领用/已领完) - 新增领用记录列表页与表单页,支持从库存选择物品和非清单物品两类领用 - 注册物资管理路由菜单(申购单管理、入库单管理、物料库存、领用记录) Made-with: Cursor
This commit is contained in:
parent
a80f3b69ac
commit
ab030d2487
|
|
@ -0,0 +1,114 @@
|
||||||
|
import config from "@/config"
|
||||||
|
import http from "@/utils/request"
|
||||||
|
export default {
|
||||||
|
requisition: {
|
||||||
|
list: {
|
||||||
|
name: "申购单列表",
|
||||||
|
req: async function(data){
|
||||||
|
return await http.get(`${config.API_URL}/mpr/requisition/`, data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
name: "创建申购单",
|
||||||
|
req: async function(data){
|
||||||
|
return await http.post(`${config.API_URL}/mpr/requisition/`, data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
name: "获取申购单详情",
|
||||||
|
req: async function(id){
|
||||||
|
return await http.get(`${config.API_URL}/mpr/requisition/${id}/`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
name: "更新申购单",
|
||||||
|
req: async function(id, data){
|
||||||
|
return await http.put(`${config.API_URL}/mpr/requisition/${id}/`, data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
delete: {
|
||||||
|
name: "删除申购单",
|
||||||
|
req: async function(id){
|
||||||
|
return await http.delete(`${config.API_URL}/mpr/requisition/${id}/`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
warehouseStock: {
|
||||||
|
list: {
|
||||||
|
name: "物料库存列表",
|
||||||
|
req: async function(data){
|
||||||
|
return await http.get(`${config.API_URL}/mpr/warehouse_stock/`, data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
name: "获取库存详情",
|
||||||
|
req: async function(id){
|
||||||
|
return await http.get(`${config.API_URL}/mpr/warehouse_stock/${id}/`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
materialRequisition: {
|
||||||
|
list: {
|
||||||
|
name: "领用单列表",
|
||||||
|
req: async function(data){
|
||||||
|
return await http.get(`${config.API_URL}/mpr/material_requisition/`, data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
name: "创建领用单",
|
||||||
|
req: async function(data){
|
||||||
|
return await http.post(`${config.API_URL}/mpr/material_requisition/`, data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
name: "获取领用单详情",
|
||||||
|
req: async function(id){
|
||||||
|
return await http.get(`${config.API_URL}/mpr/material_requisition/${id}/`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
name: "更新领用单",
|
||||||
|
req: async function(id, data){
|
||||||
|
return await http.put(`${config.API_URL}/mpr/material_requisition/${id}/`, data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
delete: {
|
||||||
|
name: "删除领用单",
|
||||||
|
req: async function(id){
|
||||||
|
return await http.delete(`${config.API_URL}/mpr/material_requisition/${id}/`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
warehouseEntry: {
|
||||||
|
list: {
|
||||||
|
name: "入库单列表",
|
||||||
|
req: async function(data){
|
||||||
|
return await http.get(`${config.API_URL}/mpr/warehouse_entry/`, data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
name: "创建入库单",
|
||||||
|
req: async function(data){
|
||||||
|
return await http.post(`${config.API_URL}/mpr/warehouse_entry/`, data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
name: "获取入库单详情",
|
||||||
|
req: async function(id){
|
||||||
|
return await http.get(`${config.API_URL}/mpr/warehouse_entry/${id}/`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
name: "更新入库单",
|
||||||
|
req: async function(id, data){
|
||||||
|
return await http.put(`${config.API_URL}/mpr/warehouse_entry/${id}/`, data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
delete: {
|
||||||
|
name: "删除入库单",
|
||||||
|
req: async function(id){
|
||||||
|
return await http.delete(`${config.API_URL}/mpr/warehouse_entry/${id}/`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2091,6 +2091,55 @@ const routes = [
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
//物资申购 mpr
|
||||||
|
{
|
||||||
|
name: "mpr",
|
||||||
|
path: "/mpr",
|
||||||
|
meta: {
|
||||||
|
title: "物资管理",
|
||||||
|
icon: "el-icon-document",
|
||||||
|
type: "menu",
|
||||||
|
perms: ["mpr"],
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
name: "requisition",
|
||||||
|
path: "/mpr/requisition",
|
||||||
|
meta: {
|
||||||
|
title: "申购单管理",
|
||||||
|
perms: ["requisition"],
|
||||||
|
},
|
||||||
|
component: "mpr/requisition",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "warehouse_entry",
|
||||||
|
path: "/mpr/warehouse_entry",
|
||||||
|
meta: {
|
||||||
|
title: "入库单管理",
|
||||||
|
perms: ["warehouse_entry"],
|
||||||
|
},
|
||||||
|
component: "mpr/warehouse_entry",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "warehouse_stock",
|
||||||
|
path: "/mpr/warehouse_stock",
|
||||||
|
meta: {
|
||||||
|
title: "物料库存",
|
||||||
|
perms: ["warehouse_stock"],
|
||||||
|
},
|
||||||
|
component: "mpr/warehouse_stock",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "material_requisition",
|
||||||
|
path: "/mpr/material_requisition",
|
||||||
|
meta: {
|
||||||
|
title: "领用记录",
|
||||||
|
perms: ["material_requisition"],
|
||||||
|
},
|
||||||
|
component: "mpr/material_requisition",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
//采购 pum
|
//采购 pum
|
||||||
{
|
{
|
||||||
name: "pum",
|
name: "pum",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,128 @@
|
||||||
|
<template>
|
||||||
|
<el-container>
|
||||||
|
<el-header>
|
||||||
|
<div class="left-panel">
|
||||||
|
<el-button type="primary" icon="el-icon-plus" @click="handleAdd" v-auth="'material_requisition.create'">新增领用单</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="right-panel">
|
||||||
|
<el-select v-model="query.belong_dept" placeholder="领用部门" clearable style="width: 140px; margin-right: 10px;" @change="handleQuery">
|
||||||
|
<el-option v-for="d in deptOptions" :key="d.id" :label="d.name" :value="d.id"></el-option>
|
||||||
|
</el-select>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateRange"
|
||||||
|
type="daterange"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
style="width: 260px; margin-right: 10px;"
|
||||||
|
@change="handleDateChange"
|
||||||
|
></el-date-picker>
|
||||||
|
<el-input v-model="query.search" placeholder="编号/操作人/领取人" clearable style="width: 200px;" @keyup.enter="handleQuery"></el-input>
|
||||||
|
<el-button type="primary" icon="el-icon-search" @click="handleQuery"></el-button>
|
||||||
|
</div>
|
||||||
|
</el-header>
|
||||||
|
<el-main class="nopadding">
|
||||||
|
<scTable
|
||||||
|
ref="table"
|
||||||
|
:apiObj="$API.mpr.materialRequisition.list"
|
||||||
|
row-key="id"
|
||||||
|
stripe
|
||||||
|
:query="query"
|
||||||
|
@row-click="rowClick"
|
||||||
|
>
|
||||||
|
<el-table-column type="index" width="50" />
|
||||||
|
<el-table-column label="编号" prop="number" width="200" sortable show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="审批状态" width="200" show-overflow-tooltip>
|
||||||
|
<template #default="scope">
|
||||||
|
<template v-if="scope.row.ticket_">
|
||||||
|
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">
|
||||||
|
{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}
|
||||||
|
</el-tag>
|
||||||
|
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_?.name }}</el-tag>
|
||||||
|
</template>
|
||||||
|
<el-tag v-else type="info">未提交</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="领用部门" prop="belong_dept_name" width="120" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="填报时间" prop="req_date" width="120" sortable show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="领取人" prop="collector" width="100" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="操作人" prop="create_by_name" width="100" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="创建时间" prop="create_time" width="170" sortable show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="备注" prop="note" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="操作" fixed="right" align="center" width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button link type="danger" @click.stop="handleDel(scope.row)" v-auth="'material_requisition.delete'">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</scTable>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
<el-drawer title="领用记录详情" v-model="drawerVisible" :size="'85%'" destroy-on-close>
|
||||||
|
<requisition-form :mode="mode" :t_id="t_id" @success="handleSuccess"></requisition-form>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import API from '@/api'
|
||||||
|
import requisitionForm from './material_requisition_form.vue'
|
||||||
|
import { actStateEnum } from "@/utils/enum.js"
|
||||||
|
|
||||||
|
const table = ref(null)
|
||||||
|
const query = ref({})
|
||||||
|
const dateRange = ref(null)
|
||||||
|
const drawerVisible = ref(false)
|
||||||
|
const mode = ref('add')
|
||||||
|
const t_id = ref(null)
|
||||||
|
const deptOptions = ref([])
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
let res = await API.system.dept.list.req({ page: 0 })
|
||||||
|
deptOptions.value = Array.isArray(res) ? res : (res.results || [])
|
||||||
|
} catch (e) {}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleAdd = () => {
|
||||||
|
mode.value = 'add'
|
||||||
|
t_id.value = null
|
||||||
|
drawerVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowClick = (row) => {
|
||||||
|
t_id.value = row.id
|
||||||
|
mode.value = 'show'
|
||||||
|
drawerVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleQuery = () => {
|
||||||
|
table.value.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDateChange = (val) => {
|
||||||
|
if (val) {
|
||||||
|
query.value.req_date_after = val[0]
|
||||||
|
query.value.req_date_before = val[1]
|
||||||
|
} else {
|
||||||
|
delete query.value.req_date_after
|
||||||
|
delete query.value.req_date_before
|
||||||
|
}
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDel = (row) => {
|
||||||
|
ElMessageBox.confirm('确定删除该领用记录吗?', '提示', { type: 'warning' })
|
||||||
|
.then(() => {
|
||||||
|
API.mpr.materialRequisition.delete.req(row.id).then(() => {
|
||||||
|
ElMessage.success('删除成功')
|
||||||
|
table.value.refresh()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSuccess = () => {
|
||||||
|
drawerVisible.value = false
|
||||||
|
table.value.refresh()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,397 @@
|
||||||
|
<template>
|
||||||
|
<el-container>
|
||||||
|
<el-main class="nopadding">
|
||||||
|
<div style="padding: 20px;">
|
||||||
|
<el-descriptions title="物资领用单" :column="3" border>
|
||||||
|
<el-descriptions-item label="编号">{{ formData.number || '自动生成' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="领用部门">{{ formData.belong_dept_name || currentUser.belong_dept_name }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="填报时间">
|
||||||
|
<el-date-picker
|
||||||
|
v-if="isEditable"
|
||||||
|
v-model="formData.req_date"
|
||||||
|
type="date"
|
||||||
|
placeholder="填报时间"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
style="width: 200px;"
|
||||||
|
/>
|
||||||
|
<span v-else>{{ formData.req_date }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="操作人">{{ formData.create_by_name || currentUser.name }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="领取人">
|
||||||
|
<el-input v-if="isEditable" v-model="formData.collector" placeholder="领取人" style="width: 200px;" />
|
||||||
|
<span v-else>{{ formData.collector }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="备注">
|
||||||
|
<el-input v-if="isEditable" v-model="formData.note" type="textarea" :rows="1" placeholder="备注" />
|
||||||
|
<span v-else>{{ formData.note }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
|
||||||
|
<!-- 库存物品(从物料库存中选择) -->
|
||||||
|
<div style="margin-top: 20px;">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
||||||
|
<h4 style="margin: 0;">库存物品领用</h4>
|
||||||
|
<el-button v-if="isEditable" type="primary" size="small" icon="el-icon-plus" @click="openStockPicker">从库存选择</el-button>
|
||||||
|
</div>
|
||||||
|
<el-table :data="stockItems" border stripe style="width: 100%">
|
||||||
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||||
|
<el-table-column label="领用类型" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="isEditable" v-model="scope.row.req_type" placeholder="领用类型" />
|
||||||
|
<span v-else>{{ scope.row.req_type }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="物资名称" min-width="120" prop="name" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="规格型号" width="120" prop="spec" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="单位" width="80" prop="unit"></el-table-column>
|
||||||
|
<el-table-column label="库存量" width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<span style="color: #909399;">{{ scope.row.stock_quantity }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="领用量" width="130">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input-number
|
||||||
|
v-if="isEditable"
|
||||||
|
v-model="scope.row.quantity"
|
||||||
|
:min="0"
|
||||||
|
:max="Number(scope.row.stock_quantity)"
|
||||||
|
:precision="3"
|
||||||
|
size="small"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
<span v-else>{{ scope.row.quantity }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="备注" min-width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="isEditable" v-model="scope.row.note" placeholder="备注" />
|
||||||
|
<span v-else>{{ scope.row.note }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column v-if="isEditable" label="操作" width="80" align="center" fixed="right">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button link type="danger" @click="delStockItem(scope.$index)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 非物资清单物品 -->
|
||||||
|
<div style="margin-top: 20px;">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
||||||
|
<h4 style="margin: 0;">非物资清单物品</h4>
|
||||||
|
<el-button v-if="isEditable" type="primary" size="small" icon="el-icon-plus" @click="addNonStockItem">添加</el-button>
|
||||||
|
</div>
|
||||||
|
<el-table :data="nonStockItems" border stripe style="width: 100%">
|
||||||
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||||
|
<el-table-column label="领用类型" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="isEditable" v-model="scope.row.req_type" placeholder="领用类型" />
|
||||||
|
<span v-else>{{ scope.row.req_type }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="物资名称" min-width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="isEditable" v-model="scope.row.name" placeholder="名称" />
|
||||||
|
<span v-else>{{ scope.row.name }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="规格型号" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="isEditable" v-model="scope.row.spec" placeholder="规格型号" />
|
||||||
|
<span v-else>{{ scope.row.spec }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="单位" width="80">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="isEditable" v-model="scope.row.unit" placeholder="单位" />
|
||||||
|
<span v-else>{{ scope.row.unit }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="领用量" width="130">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input-number v-if="isEditable" v-model="scope.row.quantity" :min="0" :precision="3" size="small" controls-position="right" />
|
||||||
|
<span v-else>{{ scope.row.quantity }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="备注" min-width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="isEditable" v-model="scope.row.note" placeholder="备注" />
|
||||||
|
<span v-else>{{ scope.row.note }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column v-if="isEditable" label="操作" width="80" align="center" fixed="right">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button link type="danger" @click="delNonStockItem(scope.$index)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="text-align: right; margin-top: 15px; font-size: 14px;">
|
||||||
|
<span style="margin-right: 30px;">部门负责人:___________</span>
|
||||||
|
<span>领取人:{{ formData.collector || '___________' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-footer style="padding: 10px 20px; text-align: left;">
|
||||||
|
<el-button type="danger"
|
||||||
|
v-if="localMode === 'edit'"
|
||||||
|
style="margin-right: 4px;"
|
||||||
|
@click="handleDel"
|
||||||
|
:loading="saveLoading"
|
||||||
|
>删除</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="isEditable"
|
||||||
|
type="primary"
|
||||||
|
style="margin-right: 4px;"
|
||||||
|
@click="handleSubmit"
|
||||||
|
:loading="saveLoading"
|
||||||
|
>提交审批</el-button>
|
||||||
|
<ticketd_b
|
||||||
|
v-if="formData.ticket_ && localMode === 'show'"
|
||||||
|
:t_id="formData.id"
|
||||||
|
:ticket_="formData.ticket_"
|
||||||
|
:ticket_data="ticket_data"
|
||||||
|
@success="$emit('success')"
|
||||||
|
ref="ticketd_b"
|
||||||
|
></ticketd_b>
|
||||||
|
</el-footer>
|
||||||
|
</el-main>
|
||||||
|
<el-aside width="20%" v-if="formData.ticket_">
|
||||||
|
<ticketd :ticket_="formData.ticket_" @success="$emit('success')"></ticketd>
|
||||||
|
</el-aside>
|
||||||
|
</el-container>
|
||||||
|
|
||||||
|
<!-- 库存选择对话框 -->
|
||||||
|
<el-dialog title="选择库存物品" v-model="stockPickerVisible" width="80%" destroy-on-close>
|
||||||
|
<div style="margin-bottom: 10px; display: flex; gap: 10px;">
|
||||||
|
<el-input v-model="stockSearch" placeholder="搜索名称/规格/供应商" clearable style="width: 300px;" @keyup.enter="loadStockList"></el-input>
|
||||||
|
<el-button type="primary" @click="loadStockList">搜索</el-button>
|
||||||
|
</div>
|
||||||
|
<el-table :data="stockList" border stripe @selection-change="handleStockSelectionChange" max-height="400">
|
||||||
|
<el-table-column type="selection" width="55" />
|
||||||
|
<el-table-column label="名称" prop="name" min-width="120" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="规格" prop="spec" width="120" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="单位" prop="unit" width="80"></el-table-column>
|
||||||
|
<el-table-column label="库存量" prop="quantity" width="100"></el-table-column>
|
||||||
|
<el-table-column label="仓库" prop="warehouse_name" width="100" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="入库单号" prop="entry_number" width="180" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="供应商" prop="supplier_name" width="120" show-overflow-tooltip></el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="stockPickerVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmStockPick">确认选择 ({{ selectedStocks.length }})</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ticketd_b from "@/views/wf/ticketd_b.vue"
|
||||||
|
import ticketd from '@/views/wf/ticketd.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'MaterialRequisitionForm',
|
||||||
|
components: { ticketd_b, ticketd },
|
||||||
|
props: {
|
||||||
|
mode: { type: String, default: 'show' },
|
||||||
|
t_id: { type: String, default: "" }
|
||||||
|
},
|
||||||
|
emits: ['success'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formData: {},
|
||||||
|
stockItems: [],
|
||||||
|
nonStockItems: [],
|
||||||
|
localMode: this.mode,
|
||||||
|
saveLoading: false,
|
||||||
|
ticket_data: {},
|
||||||
|
currentUser: this.$TOOL.data.get("USER_INFO") || {},
|
||||||
|
stockPickerVisible: false,
|
||||||
|
stockSearch: '',
|
||||||
|
stockList: [],
|
||||||
|
selectedStocks: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isEditable() {
|
||||||
|
return this.localMode === 'add' || this.localMode === 'edit'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
if (this.t_id) {
|
||||||
|
this.loadData()
|
||||||
|
} else {
|
||||||
|
this.localMode = 'add'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async loadData() {
|
||||||
|
try {
|
||||||
|
let res = await this.$API.mpr.materialRequisition.item.req(this.t_id)
|
||||||
|
this.formData = res
|
||||||
|
const allItems = res.items_ || []
|
||||||
|
this.stockItems = allItems.filter(i => i.is_stock_item).map(i => ({
|
||||||
|
...i,
|
||||||
|
stock_id: i.stock,
|
||||||
|
stock_quantity: '—',
|
||||||
|
}))
|
||||||
|
this.nonStockItems = allItems.filter(i => !i.is_stock_item)
|
||||||
|
if (res.ticket_ && res.ticket_.state_.type === 1 && res.create_by === this.currentUser.id) {
|
||||||
|
this.localMode = 'edit'
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error('加载失败')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async openStockPicker() {
|
||||||
|
this.stockSearch = ''
|
||||||
|
this.selectedStocks = []
|
||||||
|
await this.loadStockList()
|
||||||
|
this.stockPickerVisible = true
|
||||||
|
},
|
||||||
|
async loadStockList() {
|
||||||
|
try {
|
||||||
|
let res = await this.$API.mpr.warehouseStock.list.req({ page: 0, search: this.stockSearch })
|
||||||
|
const existingIds = new Set(this.stockItems.map(i => i.stock_id))
|
||||||
|
this.stockList = (Array.isArray(res) ? res : res.results || []).filter(
|
||||||
|
s => Number(s.quantity) > 0 && !existingIds.has(s.id)
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error('加载库存失败')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleStockSelectionChange(rows) {
|
||||||
|
this.selectedStocks = rows
|
||||||
|
},
|
||||||
|
confirmStockPick() {
|
||||||
|
this.selectedStocks.forEach(s => {
|
||||||
|
this.stockItems.push({
|
||||||
|
is_stock_item: true,
|
||||||
|
stock_id: s.id,
|
||||||
|
name: s.name,
|
||||||
|
spec: s.spec,
|
||||||
|
unit: s.unit,
|
||||||
|
stock_quantity: s.quantity,
|
||||||
|
quantity: 0,
|
||||||
|
req_type: '',
|
||||||
|
note: '',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.stockPickerVisible = false
|
||||||
|
},
|
||||||
|
addNonStockItem() {
|
||||||
|
this.nonStockItems.push({
|
||||||
|
is_stock_item: false,
|
||||||
|
name: '',
|
||||||
|
spec: '',
|
||||||
|
unit: '',
|
||||||
|
quantity: 0,
|
||||||
|
req_type: '',
|
||||||
|
note: '',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
delStockItem(index) {
|
||||||
|
this.stockItems.splice(index, 1)
|
||||||
|
},
|
||||||
|
delNonStockItem(index) {
|
||||||
|
this.nonStockItems.splice(index, 1)
|
||||||
|
},
|
||||||
|
validate() {
|
||||||
|
if (!this.formData.req_date) {
|
||||||
|
this.$message.warning('请选择填报时间')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const allItems = [...this.stockItems, ...this.nonStockItems]
|
||||||
|
if (allItems.length === 0) {
|
||||||
|
this.$message.warning('请至少添加一项领用物品')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for (let i = 0; i < this.stockItems.length; i++) {
|
||||||
|
const row = this.stockItems[i]
|
||||||
|
if (!row.quantity || Number(row.quantity) <= 0) {
|
||||||
|
this.$message.warning(`库存物品第${i + 1}行:领用量必须大于0`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (Number(row.quantity) > Number(row.stock_quantity)) {
|
||||||
|
this.$message.warning(`库存物品第${i + 1}行:领用量(${row.quantity})超过库存量(${row.stock_quantity})`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i = 0; i < this.nonStockItems.length; i++) {
|
||||||
|
const row = this.nonStockItems[i]
|
||||||
|
if (!row.name) {
|
||||||
|
this.$message.warning(`非清单物品第${i + 1}行:请填写物资名称`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!row.quantity || Number(row.quantity) <= 0) {
|
||||||
|
this.$message.warning(`非清单物品第${i + 1}行:领用量必须大于0`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
buildPayload() {
|
||||||
|
const items = []
|
||||||
|
this.stockItems.forEach(row => {
|
||||||
|
items.push({
|
||||||
|
is_stock_item: true,
|
||||||
|
stock: row.stock_id,
|
||||||
|
req_type: row.req_type,
|
||||||
|
name: row.name,
|
||||||
|
spec: row.spec,
|
||||||
|
unit: row.unit,
|
||||||
|
quantity: row.quantity,
|
||||||
|
note: row.note,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.nonStockItems.forEach(row => {
|
||||||
|
items.push({
|
||||||
|
is_stock_item: false,
|
||||||
|
req_type: row.req_type,
|
||||||
|
name: row.name,
|
||||||
|
spec: row.spec,
|
||||||
|
unit: row.unit,
|
||||||
|
quantity: row.quantity,
|
||||||
|
note: row.note,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
req_date: this.formData.req_date,
|
||||||
|
collector: this.formData.collector,
|
||||||
|
note: this.formData.note,
|
||||||
|
items: items
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async handleSubmit() {
|
||||||
|
if (!this.validate()) return
|
||||||
|
this.saveLoading = true
|
||||||
|
try {
|
||||||
|
if (this.localMode === 'add') {
|
||||||
|
await this.$API.mpr.materialRequisition.create.req(this.buildPayload())
|
||||||
|
this.$message.success('提交成功')
|
||||||
|
} else if (this.localMode === 'edit') {
|
||||||
|
await this.$API.mpr.materialRequisition.update.req(this.formData.id, this.buildPayload())
|
||||||
|
this.$message.success('更新并提交成功')
|
||||||
|
}
|
||||||
|
this.$emit('success')
|
||||||
|
} catch (error) {
|
||||||
|
const msg = error?.response?.data?.detail || error?.response?.data?.message || '提交失败'
|
||||||
|
this.$message.error(msg)
|
||||||
|
} finally {
|
||||||
|
this.saveLoading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleDel() {
|
||||||
|
this.$confirm('确定删除该领用单吗?', '提示', { type: 'warning' })
|
||||||
|
.then(() => {
|
||||||
|
this.$API.mpr.materialRequisition.delete.req(this.formData.id).then(() => {
|
||||||
|
this.$message.success('删除成功')
|
||||||
|
this.$emit('success')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
<template>
|
||||||
|
<el-container>
|
||||||
|
<el-header>
|
||||||
|
<div class="left-panel">
|
||||||
|
<el-button type="primary" icon="el-icon-plus" @click="handleAdd" v-auth="'requisition.create'">新增申购</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="right-panel">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateRange"
|
||||||
|
type="daterange"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
style="width: 260px; margin-right: 10px;"
|
||||||
|
@change="handleDateChange"
|
||||||
|
></el-date-picker>
|
||||||
|
<el-input
|
||||||
|
v-model="query.search"
|
||||||
|
placeholder="编号/申购人"
|
||||||
|
clearable
|
||||||
|
style="width: 200px;"
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
></el-input>
|
||||||
|
<el-button type="primary" icon="el-icon-search" @click="handleQuery"></el-button>
|
||||||
|
</div>
|
||||||
|
</el-header>
|
||||||
|
<el-main class="nopadding">
|
||||||
|
<scTable
|
||||||
|
ref="table"
|
||||||
|
:apiObj="$API.mpr.requisition.list"
|
||||||
|
row-key="id"
|
||||||
|
stripe
|
||||||
|
:query="query"
|
||||||
|
@row-click="rowClick"
|
||||||
|
>
|
||||||
|
<el-table-column type="index" width="50" />
|
||||||
|
<el-table-column label="编号" prop="number" width="200" sortable show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="审批状态" width="200" show-overflow-tooltip>
|
||||||
|
<template #default="scope">
|
||||||
|
<template v-if="scope.row.ticket_">
|
||||||
|
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">
|
||||||
|
{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}
|
||||||
|
</el-tag>
|
||||||
|
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_?.name }}</el-tag>
|
||||||
|
</template>
|
||||||
|
<el-tag v-else type="info">未提交</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="申购部门" prop="belong_dept_name" width="120" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="申购人" prop="create_by_name" width="100" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="联系电话" prop="phone" width="130" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="申购日期" prop="req_date" width="120" sortable show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="合计金额" prop="total_amount" width="120" sortable show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="备注" prop="note" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="操作" fixed="right" align="center" width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button link type="danger" @click.stop="handleDel(scope.row)" v-auth="'requisition.delete'">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</scTable>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
<el-drawer title="物资申购单" v-model="drawerVisible" :size="'85%'" destroy-on-close>
|
||||||
|
<requisition-form :mode="mode" :t_id="t_id" @success="handleSuccess"></requisition-form>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import API from '@/api'
|
||||||
|
import requisitionForm from './requisition_form.vue'
|
||||||
|
import { actStateEnum } from "@/utils/enum.js"
|
||||||
|
|
||||||
|
const table = ref(null)
|
||||||
|
const query = ref({})
|
||||||
|
const dateRange = ref(null)
|
||||||
|
const drawerVisible = ref(false)
|
||||||
|
const mode = ref('add')
|
||||||
|
const t_id = ref(null)
|
||||||
|
|
||||||
|
const handleAdd = () => {
|
||||||
|
mode.value = 'add'
|
||||||
|
t_id.value = null
|
||||||
|
drawerVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowClick = (row) => {
|
||||||
|
t_id.value = row.id
|
||||||
|
mode.value = 'show'
|
||||||
|
drawerVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleQuery = () => {
|
||||||
|
table.value.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDateChange = (val) => {
|
||||||
|
if (val) {
|
||||||
|
query.value.req_date_after = val[0]
|
||||||
|
query.value.req_date_before = val[1]
|
||||||
|
} else {
|
||||||
|
delete query.value.req_date_after
|
||||||
|
delete query.value.req_date_before
|
||||||
|
}
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDel = (row) => {
|
||||||
|
ElMessageBox.confirm('确定删除该申购单吗?', '提示', { type: 'warning' })
|
||||||
|
.then(() => {
|
||||||
|
API.mpr.requisition.delete.req(row.id).then(() => {
|
||||||
|
ElMessage.success('删除成功')
|
||||||
|
table.value.refresh()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSuccess = () => {
|
||||||
|
drawerVisible.value = false
|
||||||
|
table.value.refresh()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,279 @@
|
||||||
|
<template>
|
||||||
|
<el-container>
|
||||||
|
<el-main class="nopadding">
|
||||||
|
<div style="padding: 20px;">
|
||||||
|
<el-descriptions title="物资申购单" :column="3" border>
|
||||||
|
<el-descriptions-item label="编号">{{ formData.number || '自动生成' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="申购部门">{{ formData.belong_dept_name || currentUser.belong_dept_name }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="申购人">{{ formData.create_by_name || currentUser.name }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="联系电话">
|
||||||
|
<el-input v-if="isEditable" v-model="formData.phone" placeholder="联系电话" style="width: 200px;" />
|
||||||
|
<span v-else>{{ formData.phone }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="申购日期">
|
||||||
|
<el-date-picker
|
||||||
|
v-if="isEditable"
|
||||||
|
v-model="formData.req_date"
|
||||||
|
type="date"
|
||||||
|
placeholder="申购日期"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
style="width: 200px;"
|
||||||
|
/>
|
||||||
|
<span v-else>{{ formData.req_date }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="合计金额">
|
||||||
|
<span style="font-weight: bold; color: #e6a23c;">¥ {{ calcTotalAmount }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="备注" :span="3">
|
||||||
|
<el-input v-if="isEditable" v-model="formData.note" type="textarea" :rows="2" placeholder="备注" />
|
||||||
|
<span v-else>{{ formData.note }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
|
||||||
|
<div style="margin-top: 20px;">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
||||||
|
<h4 style="margin: 0;">申购明细</h4>
|
||||||
|
<el-button v-if="isEditable" type="primary" size="small" icon="el-icon-plus" @click="addItem">添加物品</el-button>
|
||||||
|
</div>
|
||||||
|
<el-table :data="items" border stripe style="width: 100%">
|
||||||
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||||
|
<el-table-column label="物品名称" min-width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="isEditable" v-model="scope.row.item_name" placeholder="物品名称" />
|
||||||
|
<span v-else>{{ scope.row.item_name }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="规格及型号" min-width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="isEditable" v-model="scope.row.spec" placeholder="规格型号" />
|
||||||
|
<span v-else>{{ scope.row.spec }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="单位" width="80">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="isEditable" v-model="scope.row.unit" placeholder="单位" />
|
||||||
|
<span v-else>{{ scope.row.unit }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="申购数量" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input-number v-if="isEditable" v-model="scope.row.req_quantity" :min="0" :precision="3" size="small" controls-position="right" />
|
||||||
|
<span v-else>{{ scope.row.req_quantity }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="现库存量" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input-number v-if="isEditable" v-model="scope.row.current_stock" :min="0" :precision="3" size="small" controls-position="right" />
|
||||||
|
<span v-else>{{ scope.row.current_stock }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="需用日期" width="160">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-date-picker v-if="isEditable" v-model="scope.row.need_date" type="date" placeholder="需用日期" value-format="YYYY-MM-DD" size="small" />
|
||||||
|
<span v-else>{{ scope.row.need_date }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="需采购数量" width="130">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input-number v-if="isEditable" v-model="scope.row.purchase_quantity" :min="0" :precision="3" size="small" controls-position="right" />
|
||||||
|
<span v-else>{{ scope.row.purchase_quantity }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="单价" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input-number v-if="isEditable" v-model="scope.row.unit_price" :min="0" :precision="2" size="small" controls-position="right" />
|
||||||
|
<span v-else>{{ scope.row.unit_price }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="总价" width="110">
|
||||||
|
<template #default="scope">
|
||||||
|
<span style="font-weight: bold;">{{ calcRowTotal(scope.row) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="备注" min-width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="isEditable" v-model="scope.row.note" placeholder="备注" />
|
||||||
|
<span v-else>{{ scope.row.note }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column v-if="isEditable" label="操作" width="80" align="center" fixed="right">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button link type="danger" @click="delItem(scope.$index)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div style="text-align: right; margin-top: 10px; font-size: 16px; font-weight: bold;">
|
||||||
|
合计:¥ {{ calcTotalAmount }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-footer style="padding: 10px 20px; text-align: left;">
|
||||||
|
<el-button type="danger"
|
||||||
|
v-if="localMode === 'edit'"
|
||||||
|
style="margin-right: 4px;"
|
||||||
|
@click="handleDel"
|
||||||
|
:loading="saveLoading"
|
||||||
|
>删除</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="isEditable"
|
||||||
|
type="primary"
|
||||||
|
style="margin-right: 4px;"
|
||||||
|
@click="handleSubmit"
|
||||||
|
:loading="saveLoading"
|
||||||
|
>提交审批</el-button>
|
||||||
|
<ticketd_b
|
||||||
|
v-if="formData.ticket_ && localMode === 'show'"
|
||||||
|
:t_id="formData.id"
|
||||||
|
:ticket_="formData.ticket_"
|
||||||
|
:ticket_data="ticket_data"
|
||||||
|
@success="$emit('success')"
|
||||||
|
ref="ticketd_b"
|
||||||
|
></ticketd_b>
|
||||||
|
</el-footer>
|
||||||
|
</el-main>
|
||||||
|
<el-aside width="20%" v-if="formData.ticket_">
|
||||||
|
<ticketd :ticket_="formData.ticket_" @success="$emit('success')"></ticketd>
|
||||||
|
</el-aside>
|
||||||
|
</el-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ticketd_b from "@/views/wf/ticketd_b.vue"
|
||||||
|
import ticketd from '@/views/wf/ticketd.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'RequisitionForm',
|
||||||
|
components: { ticketd_b, ticketd },
|
||||||
|
props: {
|
||||||
|
mode: { type: String, default: 'show' },
|
||||||
|
t_id: { type: String, default: "" }
|
||||||
|
},
|
||||||
|
emits: ['success'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formData: {},
|
||||||
|
items: [],
|
||||||
|
localMode: this.mode,
|
||||||
|
saveLoading: false,
|
||||||
|
ticket_data: {},
|
||||||
|
currentUser: this.$TOOL.data.get("USER_INFO") || {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isEditable() {
|
||||||
|
return this.localMode === 'add' || this.localMode === 'edit'
|
||||||
|
},
|
||||||
|
calcTotalAmount() {
|
||||||
|
let total = 0
|
||||||
|
this.items.forEach(row => {
|
||||||
|
total += Number(this.calcRowTotal(row))
|
||||||
|
})
|
||||||
|
return total.toFixed(2)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.t_id) {
|
||||||
|
this.loadData()
|
||||||
|
} else {
|
||||||
|
this.localMode = 'add'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
calcRowTotal(row) {
|
||||||
|
return (Number(row.purchase_quantity || 0) * Number(row.unit_price || 0)).toFixed(2)
|
||||||
|
},
|
||||||
|
async loadData() {
|
||||||
|
try {
|
||||||
|
let res = await this.$API.mpr.requisition.item.req(this.t_id)
|
||||||
|
this.formData = res
|
||||||
|
this.items = res.items_ || []
|
||||||
|
if (res.ticket_ && res.ticket_.state_.type === 1 && res.create_by === this.currentUser.id) {
|
||||||
|
this.localMode = 'edit'
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error('加载失败')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addItem() {
|
||||||
|
this.items.push({
|
||||||
|
item_name: '',
|
||||||
|
spec: '',
|
||||||
|
unit: '',
|
||||||
|
req_quantity: 0,
|
||||||
|
current_stock: 0,
|
||||||
|
need_date: null,
|
||||||
|
purchase_quantity: 0,
|
||||||
|
unit_price: 0,
|
||||||
|
total_price: 0,
|
||||||
|
note: ''
|
||||||
|
})
|
||||||
|
},
|
||||||
|
delItem(index) {
|
||||||
|
this.items.splice(index, 1)
|
||||||
|
},
|
||||||
|
validate() {
|
||||||
|
if (!this.formData.req_date) {
|
||||||
|
this.$message.warning('请选择申购日期')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (this.items.length === 0) {
|
||||||
|
this.$message.warning('请至少添加一项申购物品')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for (let i = 0; i < this.items.length; i++) {
|
||||||
|
if (!this.items[i].item_name) {
|
||||||
|
this.$message.warning(`第${i + 1}行:请填写物品名称`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
buildPayload() {
|
||||||
|
return {
|
||||||
|
phone: this.formData.phone,
|
||||||
|
req_date: this.formData.req_date,
|
||||||
|
note: this.formData.note,
|
||||||
|
items: this.items.map(row => ({
|
||||||
|
item_name: row.item_name,
|
||||||
|
spec: row.spec,
|
||||||
|
unit: row.unit,
|
||||||
|
req_quantity: row.req_quantity,
|
||||||
|
current_stock: row.current_stock,
|
||||||
|
need_date: row.need_date,
|
||||||
|
purchase_quantity: row.purchase_quantity,
|
||||||
|
unit_price: row.unit_price,
|
||||||
|
note: row.note
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async handleSubmit() {
|
||||||
|
if (!this.validate()) return
|
||||||
|
this.saveLoading = true
|
||||||
|
try {
|
||||||
|
if (this.localMode === 'add') {
|
||||||
|
await this.$API.mpr.requisition.create.req(this.buildPayload())
|
||||||
|
this.$message.success('提交成功')
|
||||||
|
} else if (this.localMode === 'edit') {
|
||||||
|
await this.$API.mpr.requisition.update.req(this.formData.id, this.buildPayload())
|
||||||
|
this.$message.success('更新并提交成功')
|
||||||
|
}
|
||||||
|
this.$emit('success')
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error('提交失败')
|
||||||
|
} finally {
|
||||||
|
this.saveLoading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleDel() {
|
||||||
|
this.$confirm('确定删除该申购单吗?', '提示', { type: 'warning' })
|
||||||
|
.then(() => {
|
||||||
|
this.$API.mpr.requisition.delete.req(this.formData.id).then(() => {
|
||||||
|
this.$message.success('删除成功')
|
||||||
|
this.$emit('success')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
<template>
|
||||||
|
<el-container>
|
||||||
|
<el-header>
|
||||||
|
<div class="left-panel">
|
||||||
|
<el-button type="primary" icon="el-icon-plus" @click="handleAdd" v-auth="'warehouse_entry.create'">新增入库单</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="right-panel">
|
||||||
|
<el-select v-model="query.warehouse" placeholder="仓库" clearable style="width: 150px; margin-right: 10px;" @change="handleQuery">
|
||||||
|
<el-option v-for="w in warehouseOptions" :key="w.id" :label="w.name" :value="w.id"></el-option>
|
||||||
|
</el-select>
|
||||||
|
<el-select v-model="query.entry_type" placeholder="入库类型" clearable style="width: 150px; margin-right: 10px;" @change="handleQuery">
|
||||||
|
<el-option label="原材料正常入库" value="raw_normal"></el-option>
|
||||||
|
<el-option label="原材料暂估入库" value="raw_estimated"></el-option>
|
||||||
|
<el-option label="产品入库" value="product"></el-option>
|
||||||
|
<el-option label="其他" value="other"></el-option>
|
||||||
|
</el-select>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateRange"
|
||||||
|
type="daterange"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
style="width: 260px; margin-right: 10px;"
|
||||||
|
@change="handleDateChange"
|
||||||
|
></el-date-picker>
|
||||||
|
<el-input v-model="query.search" placeholder="编号/操作人" clearable style="width: 180px;" @keyup.enter="handleQuery"></el-input>
|
||||||
|
<el-button type="primary" icon="el-icon-search" @click="handleQuery"></el-button>
|
||||||
|
</div>
|
||||||
|
</el-header>
|
||||||
|
<el-main class="nopadding">
|
||||||
|
<scTable
|
||||||
|
ref="table"
|
||||||
|
:apiObj="$API.mpr.warehouseEntry.list"
|
||||||
|
row-key="id"
|
||||||
|
stripe
|
||||||
|
:query="query"
|
||||||
|
@row-click="rowClick"
|
||||||
|
>
|
||||||
|
<el-table-column type="index" width="50" />
|
||||||
|
<el-table-column label="编号" prop="number" width="200" sortable show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="审批状态" width="200" show-overflow-tooltip>
|
||||||
|
<template #default="scope">
|
||||||
|
<template v-if="scope.row.ticket_">
|
||||||
|
<el-tag :type="actStateEnum[scope.row.ticket_?.act_state]?.type">
|
||||||
|
{{ actStateEnum[scope.row.ticket_?.act_state]?.text }}
|
||||||
|
</el-tag>
|
||||||
|
<el-tag type="info" effect="plain">{{ scope.row.ticket_?.state_?.name }}</el-tag>
|
||||||
|
</template>
|
||||||
|
<el-tag v-else type="info">未提交</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="仓库" prop="warehouse_name" width="120" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="入库类型" prop="entry_type_display" width="140" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="入库方式" prop="entry_method_display" width="100" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="入库日期" prop="entry_date" width="120" sortable show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="操作人" prop="create_by_name" width="100" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="合计金额" prop="total_amount" width="120" sortable show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="备注" prop="note" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="操作" fixed="right" align="center" width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button link type="danger" @click.stop="handleDel(scope.row)" v-auth="'warehouse_entry.delete'">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</scTable>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
<el-drawer title="仓库入库单" v-model="drawerVisible" :size="'85%'" destroy-on-close>
|
||||||
|
<entry-form :mode="mode" :t_id="t_id" @success="handleSuccess"></entry-form>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import API from '@/api'
|
||||||
|
import entryForm from './warehouse_entry_form.vue'
|
||||||
|
import { actStateEnum } from "@/utils/enum.js"
|
||||||
|
|
||||||
|
const table = ref(null)
|
||||||
|
const query = ref({})
|
||||||
|
const dateRange = ref(null)
|
||||||
|
const drawerVisible = ref(false)
|
||||||
|
const mode = ref('add')
|
||||||
|
const t_id = ref(null)
|
||||||
|
const warehouseOptions = ref([])
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
let res = await API.inm.warehouse.list.req({ page: 0 })
|
||||||
|
warehouseOptions.value = res
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleAdd = () => {
|
||||||
|
mode.value = 'add'
|
||||||
|
t_id.value = null
|
||||||
|
drawerVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowClick = (row) => {
|
||||||
|
t_id.value = row.id
|
||||||
|
mode.value = 'show'
|
||||||
|
drawerVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleQuery = () => {
|
||||||
|
table.value.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDateChange = (val) => {
|
||||||
|
if (val) {
|
||||||
|
query.value.entry_date_after = val[0]
|
||||||
|
query.value.entry_date_before = val[1]
|
||||||
|
} else {
|
||||||
|
delete query.value.entry_date_after
|
||||||
|
delete query.value.entry_date_before
|
||||||
|
}
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDel = (row) => {
|
||||||
|
ElMessageBox.confirm('确定删除该入库单吗?', '提示', { type: 'warning' })
|
||||||
|
.then(() => {
|
||||||
|
API.mpr.warehouseEntry.delete.req(row.id).then(() => {
|
||||||
|
ElMessage.success('删除成功')
|
||||||
|
table.value.refresh()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSuccess = () => {
|
||||||
|
drawerVisible.value = false
|
||||||
|
table.value.refresh()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,304 @@
|
||||||
|
<template>
|
||||||
|
<el-container>
|
||||||
|
<el-main class="nopadding">
|
||||||
|
<div style="padding: 20px;">
|
||||||
|
<el-descriptions title="仓库入库单" :column="3" border>
|
||||||
|
<el-descriptions-item label="编号">{{ formData.number || '自动生成' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="仓库名称">
|
||||||
|
<el-select v-if="isEditable" v-model="formData.warehouse" placeholder="选择仓库" style="width: 200px;">
|
||||||
|
<el-option v-for="w in warehouseOptions" :key="w.id" :label="w.name" :value="w.id"></el-option>
|
||||||
|
</el-select>
|
||||||
|
<span v-else>{{ formData.warehouse_name }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="入库日期">
|
||||||
|
<el-date-picker
|
||||||
|
v-if="isEditable"
|
||||||
|
v-model="formData.entry_date"
|
||||||
|
type="date"
|
||||||
|
placeholder="入库日期"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
style="width: 200px;"
|
||||||
|
/>
|
||||||
|
<span v-else>{{ formData.entry_date }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="入库类型">
|
||||||
|
<el-select v-if="isEditable" v-model="formData.entry_type" placeholder="入库类型" style="width: 200px;">
|
||||||
|
<el-option label="原材料正常入库" value="raw_normal"></el-option>
|
||||||
|
<el-option label="原材料暂估入库" value="raw_estimated"></el-option>
|
||||||
|
<el-option label="产品入库" value="product"></el-option>
|
||||||
|
<el-option label="其他" value="other"></el-option>
|
||||||
|
</el-select>
|
||||||
|
<span v-else>{{ formData.entry_type_display }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="入库方式">
|
||||||
|
<el-select v-if="isEditable" v-model="formData.entry_method" placeholder="入库方式" style="width: 200px;">
|
||||||
|
<el-option label="采购" value="purchase"></el-option>
|
||||||
|
<el-option label="自制" value="self_made"></el-option>
|
||||||
|
<el-option label="其他" value="other"></el-option>
|
||||||
|
</el-select>
|
||||||
|
<span v-else>{{ formData.entry_method_display }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="合计金额">
|
||||||
|
<span style="font-weight: bold; color: #e6a23c;">¥ {{ calcTotalAmount }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="操作人">{{ formData.create_by_name || currentUser.name }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="所属部门">{{ formData.belong_dept_name || currentUser.belong_dept_name }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="备注">
|
||||||
|
<el-input v-if="isEditable" v-model="formData.note" type="textarea" :rows="1" placeholder="备注" />
|
||||||
|
<span v-else>{{ formData.note }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
|
||||||
|
<div style="margin-top: 20px;">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
||||||
|
<h4 style="margin: 0;">入库明细</h4>
|
||||||
|
<el-button v-if="isEditable" type="primary" size="small" icon="el-icon-plus" @click="addItem">添加物品</el-button>
|
||||||
|
</div>
|
||||||
|
<el-table :data="items" border stripe style="width: 100%">
|
||||||
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||||
|
<el-table-column label="名称" min-width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="isEditable" v-model="scope.row.name" placeholder="名称" />
|
||||||
|
<span v-else>{{ scope.row.name }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="规格" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="isEditable" v-model="scope.row.spec" placeholder="规格" />
|
||||||
|
<span v-else>{{ scope.row.spec }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="单位" width="80">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="isEditable" v-model="scope.row.unit" placeholder="单位" />
|
||||||
|
<span v-else>{{ scope.row.unit }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="数量" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input-number v-if="isEditable" v-model="scope.row.quantity" :min="0" :precision="3" size="small" controls-position="right" />
|
||||||
|
<span v-else>{{ scope.row.quantity }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="单价" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input-number v-if="isEditable" v-model="scope.row.unit_price" :min="0" :precision="2" size="small" controls-position="right" />
|
||||||
|
<span v-else>{{ scope.row.unit_price }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="金额" width="110">
|
||||||
|
<template #default="scope">
|
||||||
|
<span style="font-weight: bold;">{{ calcRowAmount(scope.row) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="供应商名称" min-width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="isEditable" v-model="scope.row.supplier_name" placeholder="供应商" />
|
||||||
|
<span v-else>{{ scope.row.supplier_name }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="账单是否收到" width="120" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-checkbox v-if="isEditable" v-model="scope.row.invoice_received" />
|
||||||
|
<el-tag v-else :type="scope.row.invoice_received ? 'success' : 'danger'" size="small">
|
||||||
|
{{ scope.row.invoice_received ? '已收到' : '未收到' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="备注" min-width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-if="isEditable" v-model="scope.row.note" placeholder="备注" />
|
||||||
|
<span v-else>{{ scope.row.note }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column v-if="isEditable" label="操作" width="80" align="center" fixed="right">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button link type="danger" @click="delItem(scope.$index)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div style="text-align: right; margin-top: 10px; font-size: 16px; font-weight: bold;">
|
||||||
|
合计:¥ {{ calcTotalAmount }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-footer style="padding: 10px 20px; text-align: left;">
|
||||||
|
<el-button type="danger"
|
||||||
|
v-if="localMode === 'edit'"
|
||||||
|
style="margin-right: 4px;"
|
||||||
|
@click="handleDel"
|
||||||
|
:loading="saveLoading"
|
||||||
|
>删除</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="isEditable"
|
||||||
|
type="primary"
|
||||||
|
style="margin-right: 4px;"
|
||||||
|
@click="handleSubmit"
|
||||||
|
:loading="saveLoading"
|
||||||
|
>提交审批</el-button>
|
||||||
|
<ticketd_b
|
||||||
|
v-if="formData.ticket_ && localMode === 'show'"
|
||||||
|
:t_id="formData.id"
|
||||||
|
:ticket_="formData.ticket_"
|
||||||
|
:ticket_data="ticket_data"
|
||||||
|
@success="$emit('success')"
|
||||||
|
ref="ticketd_b"
|
||||||
|
></ticketd_b>
|
||||||
|
</el-footer>
|
||||||
|
</el-main>
|
||||||
|
<el-aside width="20%" v-if="formData.ticket_">
|
||||||
|
<ticketd :ticket_="formData.ticket_" @success="$emit('success')"></ticketd>
|
||||||
|
</el-aside>
|
||||||
|
</el-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ticketd_b from "@/views/wf/ticketd_b.vue"
|
||||||
|
import ticketd from '@/views/wf/ticketd.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'WarehouseEntryForm',
|
||||||
|
components: { ticketd_b, ticketd },
|
||||||
|
props: {
|
||||||
|
mode: { type: String, default: 'show' },
|
||||||
|
t_id: { type: String, default: "" }
|
||||||
|
},
|
||||||
|
emits: ['success'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formData: {
|
||||||
|
entry_type: 'raw_normal',
|
||||||
|
entry_method: 'purchase',
|
||||||
|
},
|
||||||
|
items: [],
|
||||||
|
localMode: this.mode,
|
||||||
|
saveLoading: false,
|
||||||
|
ticket_data: {},
|
||||||
|
currentUser: this.$TOOL.data.get("USER_INFO") || {},
|
||||||
|
warehouseOptions: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isEditable() {
|
||||||
|
return this.localMode === 'add' || this.localMode === 'edit'
|
||||||
|
},
|
||||||
|
calcTotalAmount() {
|
||||||
|
let total = 0
|
||||||
|
this.items.forEach(row => {
|
||||||
|
total += Number(this.calcRowAmount(row))
|
||||||
|
})
|
||||||
|
return total.toFixed(2)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
let res = await this.$API.inm.warehouse.list.req({ page: 0 })
|
||||||
|
this.warehouseOptions = res
|
||||||
|
if (this.t_id) {
|
||||||
|
this.loadData()
|
||||||
|
} else {
|
||||||
|
this.localMode = 'add'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
calcRowAmount(row) {
|
||||||
|
return (Number(row.quantity || 0) * Number(row.unit_price || 0)).toFixed(2)
|
||||||
|
},
|
||||||
|
async loadData() {
|
||||||
|
try {
|
||||||
|
let res = await this.$API.mpr.warehouseEntry.item.req(this.t_id)
|
||||||
|
this.formData = res
|
||||||
|
this.items = res.items_ || []
|
||||||
|
if (res.ticket_ && res.ticket_.state_.type === 1 && res.create_by === this.currentUser.id) {
|
||||||
|
this.localMode = 'edit'
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error('加载失败')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addItem() {
|
||||||
|
this.items.push({
|
||||||
|
name: '',
|
||||||
|
spec: '',
|
||||||
|
unit: '',
|
||||||
|
quantity: 0,
|
||||||
|
unit_price: 0,
|
||||||
|
amount: 0,
|
||||||
|
supplier_name: '',
|
||||||
|
invoice_received: false,
|
||||||
|
note: ''
|
||||||
|
})
|
||||||
|
},
|
||||||
|
delItem(index) {
|
||||||
|
this.items.splice(index, 1)
|
||||||
|
},
|
||||||
|
validate() {
|
||||||
|
if (!this.formData.warehouse) {
|
||||||
|
this.$message.warning('请选择仓库')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!this.formData.entry_date) {
|
||||||
|
this.$message.warning('请选择入库日期')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (this.items.length === 0) {
|
||||||
|
this.$message.warning('请至少添加一项入库物品')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for (let i = 0; i < this.items.length; i++) {
|
||||||
|
if (!this.items[i].name) {
|
||||||
|
this.$message.warning(`第${i + 1}行:请填写名称`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
buildPayload() {
|
||||||
|
return {
|
||||||
|
warehouse: this.formData.warehouse,
|
||||||
|
entry_date: this.formData.entry_date,
|
||||||
|
entry_type: this.formData.entry_type,
|
||||||
|
entry_method: this.formData.entry_method,
|
||||||
|
note: this.formData.note,
|
||||||
|
items: this.items.map(row => ({
|
||||||
|
name: row.name,
|
||||||
|
spec: row.spec,
|
||||||
|
unit: row.unit,
|
||||||
|
quantity: row.quantity,
|
||||||
|
unit_price: row.unit_price,
|
||||||
|
supplier_name: row.supplier_name,
|
||||||
|
invoice_received: row.invoice_received,
|
||||||
|
note: row.note
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async handleSubmit() {
|
||||||
|
if (!this.validate()) return
|
||||||
|
this.saveLoading = true
|
||||||
|
try {
|
||||||
|
if (this.localMode === 'add') {
|
||||||
|
await this.$API.mpr.warehouseEntry.create.req(this.buildPayload())
|
||||||
|
this.$message.success('提交成功')
|
||||||
|
} else if (this.localMode === 'edit') {
|
||||||
|
await this.$API.mpr.warehouseEntry.update.req(this.formData.id, this.buildPayload())
|
||||||
|
this.$message.success('更新并提交成功')
|
||||||
|
}
|
||||||
|
this.$emit('success')
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error('提交失败')
|
||||||
|
} finally {
|
||||||
|
this.saveLoading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleDel() {
|
||||||
|
this.$confirm('确定删除该入库单吗?', '提示', { type: 'warning' })
|
||||||
|
.then(() => {
|
||||||
|
this.$API.mpr.warehouseEntry.delete.req(this.formData.id).then(() => {
|
||||||
|
this.$message.success('删除成功')
|
||||||
|
this.$emit('success')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
<template>
|
||||||
|
<el-container>
|
||||||
|
<el-header>
|
||||||
|
<div class="left-panel"></div>
|
||||||
|
<div class="right-panel">
|
||||||
|
<el-select v-model="query.warehouse" placeholder="仓库" clearable style="width: 150px; margin-right: 10px;" @change="handleQuery">
|
||||||
|
<el-option v-for="w in warehouseOptions" :key="w.id" :label="w.name" :value="w.id"></el-option>
|
||||||
|
</el-select>
|
||||||
|
<el-select v-model="query.entry_type" placeholder="入库类型" clearable style="width: 150px; margin-right: 10px;" @change="handleQuery">
|
||||||
|
<el-option label="原材料正常入库" value="raw_normal"></el-option>
|
||||||
|
<el-option label="原材料暂估入库" value="raw_estimated"></el-option>
|
||||||
|
<el-option label="产品入库" value="product"></el-option>
|
||||||
|
<el-option label="其他" value="other"></el-option>
|
||||||
|
</el-select>
|
||||||
|
<el-select v-model="query.status" placeholder="物料状态" clearable style="width: 120px; margin-right: 10px;" @change="handleQuery">
|
||||||
|
<el-option label="闲置" value="idle"></el-option>
|
||||||
|
<el-option label="领用中" value="in_requisition"></el-option>
|
||||||
|
<el-option label="已领用" value="requisitioned"></el-option>
|
||||||
|
</el-select>
|
||||||
|
<el-select v-model="query.invoice_received" placeholder="账单状态" clearable style="width: 120px; margin-right: 10px;" @change="handleQuery">
|
||||||
|
<el-option label="已收到" :value="true"></el-option>
|
||||||
|
<el-option label="未收到" :value="false"></el-option>
|
||||||
|
</el-select>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateRange"
|
||||||
|
type="daterange"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
style="width: 260px; margin-right: 10px;"
|
||||||
|
@change="handleDateChange"
|
||||||
|
></el-date-picker>
|
||||||
|
<el-input v-model="query.search" placeholder="名称/规格/供应商/单号" clearable style="width: 220px;" @keyup.enter="handleQuery"></el-input>
|
||||||
|
<el-button type="primary" icon="el-icon-search" @click="handleQuery"></el-button>
|
||||||
|
</div>
|
||||||
|
</el-header>
|
||||||
|
<el-main class="nopadding">
|
||||||
|
<scTable
|
||||||
|
ref="table"
|
||||||
|
:apiObj="$API.mpr.warehouseStock.list"
|
||||||
|
row-key="id"
|
||||||
|
stripe
|
||||||
|
:query="query"
|
||||||
|
>
|
||||||
|
<el-table-column type="index" width="50" />
|
||||||
|
<el-table-column label="仓库" prop="warehouse_name" width="120" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="入库单号" prop="entry_number" width="200" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="入库日期" prop="entry_date" width="110" sortable show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="入库类型" prop="entry_type_display" width="140" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="入库方式" prop="entry_method_display" width="100" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="名称" prop="name" min-width="120" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="规格" prop="spec" width="120" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="单位" prop="unit" width="70" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="数量" prop="quantity" width="100" sortable show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="单价" prop="unit_price" width="100" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="金额" prop="amount" width="110" sortable show-overflow-tooltip>
|
||||||
|
<template #default="scope">
|
||||||
|
<span style="font-weight: bold;">{{ scope.row.amount }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="状态" width="100" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag v-if="Number(scope.row.quantity) <= 0" type="info" size="small">已领完</el-tag>
|
||||||
|
<el-tag v-else-if="scope.row.status === 'idle'" type="success" size="small">闲置</el-tag>
|
||||||
|
<el-tag v-else-if="scope.row.status === 'in_requisition'" type="warning" size="small">领用中</el-tag>
|
||||||
|
<el-tag v-else-if="scope.row.status === 'requisitioned'" type="danger" size="small">已领用</el-tag>
|
||||||
|
<el-tag v-else type="info" size="small">{{ scope.row.status_display }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="供应商" prop="supplier_name" width="140" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="账单" width="90" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag :type="scope.row.invoice_received ? 'success' : 'danger'" size="small">
|
||||||
|
{{ scope.row.invoice_received ? '已收到' : '未收到' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</scTable>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import API from '@/api'
|
||||||
|
|
||||||
|
const table = ref(null)
|
||||||
|
const query = ref({})
|
||||||
|
const dateRange = ref(null)
|
||||||
|
const warehouseOptions = ref([])
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
let res = await API.inm.warehouse.list.req({ page: 0 })
|
||||||
|
warehouseOptions.value = res
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleQuery = () => {
|
||||||
|
table.value.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDateChange = (val) => {
|
||||||
|
if (val) {
|
||||||
|
query.value.entry_date_after = val[0]
|
||||||
|
query.value.entry_date_before = val[1]
|
||||||
|
} else {
|
||||||
|
delete query.value.entry_date_after
|
||||||
|
delete query.value.entry_date_before
|
||||||
|
}
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
Loading…
Reference in New Issue