产品入库,半成品委外单

This commit is contained in:
朱昊天
2026-05-11 17:59:12 +08:00
parent d1aab9dba1
commit f94ddb433d
31 changed files with 2119 additions and 77 deletions

View File

@@ -0,0 +1,40 @@
import request from '@/utils/request'
export function listProductInDetail(query) {
return request({
url: '/mat/productInDetail/list',
method: 'get',
params: query
})
}
export function getProductInDetail(detailId) {
return request({
url: '/mat/productInDetail/' + detailId,
method: 'get'
})
}
export function addProductInDetail(data) {
return request({
url: '/mat/productInDetail',
method: 'post',
data: data
})
}
export function updateProductInDetail(data) {
return request({
url: '/mat/productInDetail',
method: 'put',
data: data
})
}
export function delProductInDetail(detailId) {
return request({
url: '/mat/productInDetail/' + detailId,
method: 'delete'
})
}

View File

@@ -0,0 +1,39 @@
import request from '@/utils/request'
export function listProductOutsourceOrder(query) {
return request({
url: '/mat/productOutsourceOrder/list',
method: 'get',
params: query
})
}
export function getProductOutsourceOrder(orderId) {
return request({
url: '/mat/productOutsourceOrder/' + orderId,
method: 'get'
})
}
export function addProductOutsourceOrder(data) {
return request({
url: '/mat/productOutsourceOrder',
method: 'post',
data: data
})
}
export function delProductOutsourceOrder(orderId) {
return request({
url: '/mat/productOutsourceOrder/' + orderId,
method: 'delete'
})
}
export function receiveProductOutsourceOrder(orderId, data) {
return request({
url: '/mat/productOutsourceOrder/receive/' + orderId,
method: 'post',
data
})
}

View File

@@ -17,6 +17,14 @@
<el-descriptions-item label="产品名称">
{{ productDetail.productName || '-' }}
</el-descriptions-item>
<el-descriptions-item label="产品类型">
<el-tag :type="productTypeTagType(productDetail.productType)" effect="dark">
{{ productTypeLabel(productDetail.productType) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="库存">
{{ formatDecimal(productDetail.currentStock) }}
</el-descriptions-item>
<el-descriptions-item label="产品单价">
{{ formatDecimal(productDetail.unitPrice) }}
</el-descriptions-item>
@@ -188,6 +196,9 @@ import { Document } from '@element-plus/icons-vue';
const router = useRouter();
const route = useRoute();
const productTypeLabel = (val) => (val === 'semi' ? '半成品' : '产品');
const productTypeTagType = (val) => (val === 'semi' ? 'warning' : 'success');
const productDetail = ref({});
const loading = ref(true);
const materialLoading = ref(false);

View File

@@ -40,6 +40,13 @@
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="产品ID 主键" align="center" prop="productId" v-if="false" />
<el-table-column label="产品名称" align="center" prop="productName" />
<el-table-column label="产品类型" align="center" prop="productType" width="100">
<template #default="scope">
<el-tag :type="productTypeTagType(scope.row.productType)" effect="dark">
{{ productTypeLabel(scope.row.productType) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="产品规格" align="center" prop="spec" />
<el-table-column label="产品型号" align="center" prop="model" />
<el-table-column label="产品单价" align="center" prop="unitPrice">
@@ -47,6 +54,11 @@
{{ formatDecimal(scope.row.unitPrice) }}
</template>
</el-table-column>
<el-table-column label="库存" align="center" prop="currentStock" width="120">
<template #default="scope">
{{ formatDecimal(scope.row.currentStock) }}
</template>
</el-table-column>
<el-table-column label="附加属性" align="center" min-width="160">
<template #default="scope">
<el-tooltip
@@ -132,9 +144,24 @@
<el-form-item label="产品型号" prop="model">
<el-input v-model="form.model" placeholder="请输入产品型号" />
</el-form-item>
<el-form-item label="产品类型" prop="productType">
<el-select v-model="form.productType" placeholder="请选择产品类型" style="width: 100%">
<el-option label="产品" value="product" />
<el-option label="半成品" value="semi" />
</el-select>
</el-form-item>
<el-form-item label="产品单价" prop="unitPrice">
<el-input v-model="form.unitPrice" placeholder="请输入产品单价" />
</el-form-item>
<el-form-item label="库存" prop="currentStock">
<el-input-number
v-model="form.currentStock"
style="width: 100%"
:controls="false"
:min="0"
:precision="4"
/>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
@@ -403,12 +430,17 @@ const formatterTime = (time) => {
return proxy.parseTime(time, '{y}-{m}-{d}')
}
const productTypeLabel = (val) => (val === 'semi' ? '半成品' : '产品');
const productTypeTagType = (val) => (val === 'semi' ? 'warning' : 'success');
const data = reactive({
form: {
productId: null,
productName: null,
spec: null,
model: null,
productType: 'product',
currentStock: 0,
unitPrice: null,
delFlag: null,
createTime: null,
@@ -456,6 +488,8 @@ function reset() {
productName: null,
spec: null,
model: null,
productType: 'product',
currentStock: 0,
unitPrice: null,
delFlag: null,
createTime: null,
@@ -506,6 +540,12 @@ function handleUpdate(row) {
getProduct(_productId).then(response => {
loading.value = false;
form.value = response.data;
if (!form.value.productType) {
form.value.productType = 'product';
}
if (form.value.currentStock === null || form.value.currentStock === undefined) {
form.value.currentStock = 0;
}
// 处理图片文件列表
if (form.value.productImages) {
@@ -692,6 +732,8 @@ function submitForm() {
productName: form.value.productName,
spec: form.value.spec,
model: form.value.model,
productType: form.value.productType,
currentStock: form.value.currentStock,
unitPrice: form.value.unitPrice,
remark: form.value.remark,
productImages: form.value.productImages,

View File

@@ -0,0 +1,288 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="产品" prop="productId">
<el-select
v-model="queryParams.productId"
placeholder="请选择产品"
clearable
filterable
remote
:remote-method="remoteSearchProducts"
:loading="productLoading"
style="width: 260px"
>
<el-option
v-for="p in productOptions"
:key="p.productId"
:label="productOptionLabel(p)"
:value="p.productId"
/>
</el-select>
</el-form-item>
<el-form-item label="操作人" prop="operator">
<el-input v-model="queryParams.operator" placeholder="请输入入库操作人" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">撤回</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="明细ID" align="center" prop="detailId" v-if="false" />
<el-table-column label="产品" align="center" min-width="240">
<template #default="scope">
<div>{{ scope.row.productName || '-' }}</div>
<div style="color:#909399;font-size:12px;">
{{ [scope.row.spec, scope.row.model].filter(Boolean).join(' / ') }}
</div>
</template>
</el-table-column>
<el-table-column label="产品类型" align="center" prop="productType" width="100">
<template #default="scope">
<el-tag :type="productTypeTagType(scope.row.productType)" effect="dark">
{{ productTypeLabel(scope.row.productType) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="入库数量" align="center" prop="inNum" width="140">
<template #default="scope">
{{ formatDecimal(scope.row.inNum) }}
</template>
</el-table-column>
<el-table-column label="入库时间" align="center" prop="inTime" width="180">
<template #default="scope">
<span>{{ formatterTime(scope.row.inTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作人" align="center" prop="operator" width="120" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120">
<template #default="scope">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">撤回</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="产品" prop="productId">
<el-select
v-model="form.productId"
placeholder="请选择产品"
clearable
filterable
remote
:remote-method="remoteSearchProducts"
:loading="productLoading"
style="width: 100%"
>
<el-option
v-for="p in productOptions"
:key="p.productId"
:label="productOptionLabel(p)"
:value="p.productId"
/>
</el-select>
</el-form-item>
<el-form-item label="入库数量" prop="inNum">
<el-input-number v-model="form.inNum" style="width: 100%" :controls="false" :min="0" :precision="4" />
</el-form-item>
<el-form-item label="入库时间" prop="inTime">
<el-date-picker clearable v-model="form.inTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择入库时间" />
</el-form-item>
<el-form-item label="操作人" prop="operator">
<el-input v-model="form.operator" placeholder="请输入入库操作人" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="ProductInDetail">
import { listProductInDetail, delProductInDetail, addProductInDetail } from "@/api/mat/productInDetail";
import { listProductBase } from "@/api/mat/product";
import useUserStore from '@/store/modules/user'
import { formatDecimal } from '@/utils/gear'
const userStore = useUserStore()
const { proxy } = getCurrentInstance();
const list = ref([]);
const open = ref(false);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const productOptions = ref([]);
const productLoading = ref(false);
const formatterTime = (time) => {
return proxy.parseTime(time, '{y}-{m}-{d}')
}
const productTypeLabel = (val) => (val === 'semi' ? '半成品' : '成品');
const productTypeTagType = (val) => (val === 'semi' ? 'warning' : 'success');
const productOptionLabel = (p) => {
const name = p?.productName || '-';
const parts = [p?.spec, p?.model].filter(Boolean);
const typeText = p?.productType === 'semi' ? '半成品' : '成品';
const base = parts.length ? `${name}${parts.join(' / ')}` : name;
return `${typeText} - ${base}`;
};
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
productId: undefined,
inNum: undefined,
inTime: undefined,
operator: undefined,
},
rules: {
}
});
const { queryParams, form, rules } = toRefs(data);
function getList() {
loading.value = true;
listProductInDetail(queryParams.value).then(response => {
list.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
function cancel() {
open.value = false;
reset();
}
const nickName = computed(() => userStore.nickName)
function reset() {
const inTime = proxy.parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}')
form.value = {
detailId: null,
productId: null,
inNum: null,
inTime: inTime,
operator: nickName,
remark: null
};
proxy.resetForm("formRef");
}
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.detailId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
function handleAdd() {
reset();
open.value = true;
title.value = "添加产品入库单";
remoteSearchProducts('');
}
function submitForm() {
if (buttonLoading.value) return;
proxy.$refs["formRef"].validate(valid => {
if (!valid) return;
buttonLoading.value = true;
addProductInDetail(form.value).then(() => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
});
}
function handleDelete(row) {
const _detailIds = row?.detailId || ids.value;
proxy.$modal.confirm('是否确认撤回入库记录编号为"' + _detailIds + '"的数据项?').then(function () {
loading.value = true;
return delProductInDetail(_detailIds);
}).then(() => {
loading.value = true;
getList();
proxy.$modal.msgSuccess("撤回成功");
}).catch(() => {
}).finally(() => {
loading.value = false;
});
}
function handleExport() {
proxy.download('mat/productInDetail/export', {
...queryParams.value
}, `product_in_${new Date().getTime()}.xlsx`)
}
function remoteSearchProducts(keyword) {
productLoading.value = true;
listProductBase({ pageNum: 1, pageSize: 50, productName: keyword || undefined }).then(res => {
productOptions.value = res.rows || [];
}).finally(() => {
productLoading.value = false;
});
}
getList();
remoteSearchProducts('');
</script>

View File

@@ -0,0 +1,376 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="半成品" prop="productId">
<el-select
v-model="queryParams.productId"
placeholder="请选择半成品"
clearable
filterable
remote
:remote-method="remoteSearchProducts"
:loading="productLoading"
style="width: 260px"
>
<el-option
v-for="p in productOptions"
:key="p.productId"
:label="productOptionLabel(p)"
:value="p.productId"
/>
</el-select>
</el-form-item>
<el-form-item label="公司" prop="customerName">
<el-input v-model="queryParams.customerName" placeholder="请输入委托公司" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="操作人" prop="operator">
<el-input v-model="queryParams.operator" placeholder="请输入操作人" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">撤回</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="委外单号" align="center" prop="orderNo" width="170" />
<el-table-column label="产品类型" align="center" prop="productTypeSnapshot" width="100">
<template #default="scope">
<el-tag :type="productTypeTagType(scope.row.productTypeSnapshot)" effect="dark">
{{ productTypeLabel(scope.row.productTypeSnapshot) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="半成品" align="center" min-width="240">
<template #default="scope">
<div>{{ scope.row.productName || '-' }}</div>
<div style="color:#909399;font-size:12px;">
{{ [scope.row.spec, scope.row.model].filter(Boolean).join(' / ') }}
</div>
</template>
</el-table-column>
<el-table-column label="委托公司" align="center" prop="customerName" min-width="180" />
<el-table-column label="委派数量" align="center" prop="quantity" width="140">
<template #default="scope">
{{ formatDecimal(scope.row.quantity) }}
</template>
</el-table-column>
<el-table-column label="已收回" align="center" prop="receivedQty" width="140">
<template #default="scope">
{{ formatDecimal(scope.row.receivedQty) }}
</template>
</el-table-column>
<el-table-column label="收回状态" align="center" width="110">
<template #default="scope">
<el-tag :type="receiveStatusTagType(scope.row)" effect="dark">
{{ receiveStatusText(scope.row) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="委外时间" align="center" prop="outTime" width="180">
<template #default="scope">
<span>{{ formatterTime(scope.row.outTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作人" align="center" prop="operator" width="120" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120">
<template #default="scope">
<el-button link type="primary" icon="Check" :disabled="isFullyReceived(scope.row)" @click="openReceive(scope.row)">收回</el-button>
<el-button link type="primary" icon="Delete" :disabled="hasReceived(scope.row)" @click="handleDelete(scope.row)">撤回</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<el-dialog :title="title" v-model="open" width="520px" append-to-body>
<el-form ref="formRef" :model="form" :rules="rules" label-width="90px">
<el-form-item label="半成品" prop="productId">
<el-select
v-model="form.productId"
placeholder="请选择半成品"
clearable
filterable
remote
:remote-method="remoteSearchProducts"
:loading="productLoading"
style="width: 100%"
>
<el-option
v-for="p in productOptions"
:key="p.productId"
:label="productOptionLabel(p)"
:value="p.productId"
/>
</el-select>
</el-form-item>
<el-form-item label="委托公司" prop="customerName">
<el-input v-model="form.customerName" placeholder="请输入委托公司" />
</el-form-item>
<el-form-item label="委派数量" prop="quantity">
<el-input-number v-model="form.quantity" style="width: 100%" :controls="false" :min="0" :precision="4" />
</el-form-item>
<el-form-item label="委外时间" prop="outTime">
<el-date-picker clearable v-model="form.outTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择委外时间" />
</el-form-item>
<el-form-item label="操作人" prop="operator">
<el-input v-model="form.operator" placeholder="请输入操作人" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<el-dialog title="收回" v-model="receiveOpen" width="460px" append-to-body>
<el-form ref="receiveRef" :model="receiveForm" label-width="90px">
<el-form-item label="收回数量">
<el-input-number v-model="receiveForm.receiveQty" style="width: 100%" :controls="false" :min="0" :precision="4" />
</el-form-item>
<el-form-item label="收回时间">
<el-date-picker clearable v-model="receiveForm.receiveTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择收回时间" />
</el-form-item>
<el-form-item label="收回人">
<el-input v-model="receiveForm.receiveBy" placeholder="请输入收回人" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="receiveLoading" type="primary" @click="submitReceive"> </el-button>
<el-button @click="receiveOpen = false"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="ProductOutsourceOrder">
import { listProductOutsourceOrder, addProductOutsourceOrder, delProductOutsourceOrder, receiveProductOutsourceOrder } from "@/api/mat/productOutsourceOrder";
import { listProductBase } from "@/api/mat/product";
import useUserStore from '@/store/modules/user'
import { formatDecimal } from '@/utils/gear'
const userStore = useUserStore()
const { proxy } = getCurrentInstance();
const list = ref([]);
const open = ref(false);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const productOptions = ref([]);
const productLoading = ref(false);
const receiveOpen = ref(false);
const receiveLoading = ref(false);
const receiveForm = ref({ orderId: null, receiveQty: null, receiveTime: null, receiveBy: null });
const formatterTime = (time) => proxy.parseTime(time, '{y}-{m}-{d}')
const productTypeLabel = (val) => (val === 'semi' ? '半成品' : '成品');
const productTypeTagType = (val) => (val === 'semi' ? 'warning' : 'success');
const rowQty = (v) => (v === null || v === undefined ? 0 : Number(v) || 0);
const hasReceived = (row) => rowQty(row?.receivedQty) > 0;
const isFullyReceived = (row) => rowQty(row?.receivedQty) >= rowQty(row?.quantity);
const receiveStatusText = (row) => {
const totalQty = rowQty(row?.quantity);
const receivedQty = rowQty(row?.receivedQty);
if (receivedQty <= 0) return '未收回';
if (receivedQty >= totalQty) return '已收回';
return '部分收回';
};
const receiveStatusTagType = (row) => {
const t = receiveStatusText(row);
if (t === '已收回') return 'success';
if (t === '部分收回') return 'warning';
return 'info';
};
const productOptionLabel = (p) => {
const name = p?.productName || '-';
const parts = [p?.spec, p?.model].filter(Boolean);
return parts.length ? `${name}${parts.join(' / ')}` : name;
};
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
productId: undefined,
customerName: undefined,
operator: undefined,
},
rules: {
}
});
const { queryParams, form, rules } = toRefs(data);
function getList() {
loading.value = true;
listProductOutsourceOrder(queryParams.value).then(res => {
list.value = res.rows;
total.value = res.total;
loading.value = false;
});
}
function cancel() {
open.value = false;
reset();
}
const nickName = computed(() => userStore.nickName)
function reset() {
const outTime = proxy.parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}')
form.value = {
orderId: null,
orderNo: null,
productId: null,
customerId: null,
customerName: null,
quantity: null,
outTime,
operator: nickName,
remark: null
};
proxy.resetForm("formRef");
}
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.orderId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
function handleAdd() {
reset();
open.value = true;
title.value = "新增半成品委外单";
remoteSearchProducts('');
}
function submitForm() {
if (buttonLoading.value) return;
proxy.$refs["formRef"].validate(valid => {
if (!valid) return;
buttonLoading.value = true;
addProductOutsourceOrder(form.value).then(() => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
}).finally(() => {
buttonLoading.value = false;
});
});
}
function handleDelete(row) {
const _orderIds = row?.orderId || ids.value;
proxy.$modal.confirm('是否确认撤回委外单编号为"' + _orderIds + '"的数据项?').then(function () {
loading.value = true;
return delProductOutsourceOrder(_orderIds);
}).then(() => {
loading.value = true;
getList();
proxy.$modal.msgSuccess("撤回成功");
}).catch(() => {
}).finally(() => {
loading.value = false;
});
}
function openReceive(row) {
const outTime = proxy.parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}')
const totalQty = rowQty(row?.quantity);
const receivedQty = rowQty(row?.receivedQty);
const remaining = totalQty - receivedQty;
receiveForm.value = {
orderId: row?.orderId,
receiveQty: remaining > 0 ? remaining : 0,
receiveTime: outTime,
receiveBy: nickName
};
receiveOpen.value = true;
}
function submitReceive() {
if (receiveLoading.value) return;
const orderId = receiveForm.value.orderId;
receiveLoading.value = true;
receiveProductOutsourceOrder(orderId, {
receiveQty: receiveForm.value.receiveQty,
receiveTime: receiveForm.value.receiveTime,
receiveBy: receiveForm.value.receiveBy
}).then(() => {
proxy.$modal.msgSuccess("收回成功");
receiveOpen.value = false;
getList();
}).finally(() => {
receiveLoading.value = false;
});
}
function handleExport() {
proxy.download('mat/productOutsourceOrder/export', {
...queryParams.value
}, `product_outsource_${new Date().getTime()}.xlsx`)
}
function remoteSearchProducts(keyword) {
productLoading.value = true;
listProductBase({ pageNum: 1, pageSize: 50, productName: keyword || undefined, productType: 'semi' }).then(res => {
productOptions.value = res.rows || [];
}).finally(() => {
productLoading.value = false;
});
}
getList();
remoteSearchProducts('');
</script>

View File

@@ -30,7 +30,7 @@
<el-button type="warning" plain icon="Download" size="mini" @click="handleExport">导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain size="mini" @click="openFlow">统计/打印</el-button>
<el-button type="info" plain size="mini" @click="openFlow">统计/导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" />
</el-row>
@@ -296,7 +296,7 @@
</div>
<template #footer>
<el-button :disabled="!flowResult" @click="printFlow">打印</el-button>
<el-button :disabled="!flowResult" @click="exportFlow">导出Excel</el-button>
<el-button @click="flowOpen = false">关闭</el-button>
</template>
</el-dialog>
@@ -539,29 +539,24 @@ export default {
this.flowLoading = false
})
},
printFlow() {
const el = this.$refs.flowPrintContent
if (!el) return
const w = window.open('', '_blank')
if (!w) return
const html = `
<html>
<head>
<title>物料出入库统计</title>
<style>
body { font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","PingFang SC","Microsoft YaHei",sans-serif; padding: 12px; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #dcdfe6; padding: 6px 8px; font-size: 12px; }
</style>
</head>
<body>${el.innerHTML}</body>
</html>`
w.document.open()
w.document.write(html)
w.document.close()
w.focus()
w.print()
w.close()
exportFlow() {
if (!this.flowForm.itemId) {
this.$modal.msgError('请选择物料')
return
}
if (!this.flowForm.timeRange || this.flowForm.timeRange.length !== 2) {
this.$modal.msgError('请选择时间范围')
return
}
this.download(
'/gear/stockIoOrder/materialFlow/export',
{
itemId: this.flowForm.itemId,
startTime: this.flowForm.timeRange[0],
endTime: this.flowForm.timeRange[1]
},
`material_flow_${this.flowForm.itemId}_${new Date().getTime()}.xlsx`
)
},
submitEdit() {
this.$refs.editFormRef.validate((valid) => {

View File

@@ -27,7 +27,7 @@
<el-button type="warning" plain icon="Download" size="mini" @click="handleExport">导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain size="mini" @click="openFlow">统计/打印</el-button>
<el-button type="info" plain size="mini" @click="openFlow">统计/导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" />
</el-row>
@@ -277,7 +277,7 @@
</div>
<template #footer>
<el-button :disabled="!flowResult" @click="printFlow">打印</el-button>
<el-button :disabled="!flowResult" @click="exportFlow">导出Excel</el-button>
<el-button @click="flowOpen = false">关闭</el-button>
</template>
</el-dialog>
@@ -497,29 +497,24 @@ export default {
this.flowLoading = false
})
},
printFlow() {
const el = this.$refs.flowPrintContent
if (!el) return
const w = window.open('', '_blank')
if (!w) return
const html = `
<html>
<head>
<title>物料出入库统计</title>
<style>
body { font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","PingFang SC","Microsoft YaHei",sans-serif; padding: 12px; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #dcdfe6; padding: 6px 8px; font-size: 12px; }
</style>
</head>
<body>${el.innerHTML}</body>
</html>`
w.document.open()
w.document.write(html)
w.document.close()
w.focus()
w.print()
w.close()
exportFlow() {
if (!this.flowForm.itemId) {
this.$modal.msgError('请选择物料')
return
}
if (!this.flowForm.timeRange || this.flowForm.timeRange.length !== 2) {
this.$modal.msgError('请选择时间范围')
return
}
this.download(
'/gear/stockIoOrder/materialFlow/export',
{
itemId: this.flowForm.itemId,
startTime: this.flowForm.timeRange[0],
endTime: this.flowForm.timeRange[1]
},
`material_flow_${this.flowForm.itemId}_${new Date().getTime()}.xlsx`
)
},
submitEdit() {
this.$refs.editFormRef.validate((valid) => {

View File

@@ -50,7 +50,7 @@
<el-button type="warning" plain icon="Download" size="mini" @click="handleExport">导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain size="mini" @click="openFlow">统计/打印</el-button>
<el-button type="info" plain size="mini" @click="openFlow">统计/导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" />
</el-row>
@@ -371,7 +371,7 @@
</div>
<template #footer>
<el-button :disabled="!flowResult" @click="printFlow">打印</el-button>
<el-button :disabled="!flowResult" @click="exportFlow">导出Excel</el-button>
<el-button @click="flowOpen = false">关闭</el-button>
</template>
</el-dialog>
@@ -694,29 +694,24 @@ export default {
this.flowLoading = false
})
},
printFlow() {
const el = this.$refs.flowPrintContent
if (!el) return
const w = window.open('', '_blank')
if (!w) return
const html = `
<html>
<head>
<title>物料出入库统计</title>
<style>
body { font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","PingFang SC","Microsoft YaHei",sans-serif; padding: 12px; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #dcdfe6; padding: 6px 8px; font-size: 12px; }
</style>
</head>
<body>${el.innerHTML}</body>
</html>`
w.document.open()
w.document.write(html)
w.document.close()
w.focus()
w.print()
w.close()
exportFlow() {
if (!this.flowForm.itemId) {
this.$modal.msgError('请选择物料')
return
}
if (!this.flowForm.timeRange || this.flowForm.timeRange.length !== 2) {
this.$modal.msgError('请选择时间范围')
return
}
this.download(
'/gear/stockIoOrder/materialFlow/export',
{
itemId: this.flowForm.itemId,
startTime: this.flowForm.timeRange[0],
endTime: this.flowForm.timeRange[1]
},
`material_flow_${this.flowForm.itemId}_${new Date().getTime()}.xlsx`
)
},
showDetail(row) {
this.detailOpen = true