You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

845 lines
24 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div>
<my-card title="搜索条件" search>
<n-form inline>
<n-form-item label="申请部门">
<n-tree-select
v-model:value="searchForm.deptId"
class="w-180px"
label-field="deptName"
key-field="deptId"
:options="treeOptions"
></n-tree-select>
<!-- <n-select v-model:value="searchForm.status" :options="statusOptions" class="w-180px"></n-select> -->
</n-form-item>
<n-form-item label="供应商">
<n-select v-model:value="searchForm.vendorId" :options="supperOptions" class="w-180px"></n-select>
</n-form-item>
<n-form-item label="计划日期">
<n-date-picker v-model:value="dateArr" type="daterange"></n-date-picker>
</n-form-item>
<n-form-item>
<component :is="useSearchBtn(search, reset)"></component>
</n-form-item>
</n-form>
</my-card>
<my-card title="采购订单">
<template #right>
<div>
<component
:is="useDelBtn(delSelect, undefined, '确定要删除所有已选中的数据吗?', Boolean(!selectKeys.length))"
></component>
<component
:is="
useAddBtn(
() => {
editFlag = true;
showDialog = true;
},
undefined,
'新增订单'
)
"
></component>
<cx-columns v-model:columns="columns"></cx-columns>
</div>
</template>
<n-data-table
children-key="lineList"
:row-key="row => row.planId"
:loading="loading"
:columns="columns"
:data="data"
@update-checked-row-keys="handleSelect"
></n-data-table>
<my-pagination v-model:search-form="searchForm" @init="init"></my-pagination>
</my-card>
<my-dialog
v-model:show="showDialog"
width="800px"
:title="!editFlag ? '修改采购订单' : '新增采购订单'"
@submit="submit"
@cancel="cancel"
>
<template #content>
<div>
<n-form ref="addFormRef" :rules="rules" label-placement="left" :label-width="100" :model="dialogForm">
<n-grid :cols="2" x-gap="10">
<n-form-item-grid-item :span="1" label="申请部门" path="deptId">
<n-tree-select
v-model:value="dialogForm.deptId"
label-field="deptName"
key-field="deptId"
:options="treeOptions"
@update:value="treeSelect"
></n-tree-select>
</n-form-item-grid-item>
<!-- <n-form-item-grid-item :span="1" label="申请人">
<n-input></n-input>
</n-form-item-grid-item> -->
<n-form-item-grid-item :span="1" label="供应商" path="vendorId">
<n-select
v-model:value="dialogForm.vendorId"
:options="supperOptions"
@update:value="handleSelectSupper"
></n-select>
</n-form-item-grid-item>
<n-form-item-grid-item :span="1" label="订单编号" path="planId">
<n-select
v-model:value="dialogForm.planId"
:options="rawProucreOptions"
filterable
@update:value="handleSelectRawProucre"
></n-select>
</n-form-item-grid-item>
<n-form-item-grid-item :span="1" label="总金额">{{ getTotalPric }}</n-form-item-grid-item>
<n-form-item-grid-item :span="1" label="总数量">
{{ getTotalNum }}
</n-form-item-grid-item>
<n-form-item-grid-item :span="1" label="总数量">
{{ getTotalWeight }}
</n-form-item-grid-item>
</n-grid>
</n-form>
<n-tabs
default-value="明细1"
type="card"
:addable="addable"
:closable="closable"
tab-style="min-width: 80px;"
@close="handleClose"
@add="handleAdd"
>
<n-tab-pane v-for="panel in panels" :key="panel.name" :name="panel.name">
<n-form label-placement="left" :label-width="100">
<n-grid :cols="2" :x-gap="10">
<n-form-item-grid-item :span="1" label="物品名称">
<n-select
v-model:value="panel.form.itemId"
placeholder="请选择物品名称"
:options="itemOptions"
filterable
@update:value="selectItem(panel.form)"
></n-select>
</n-form-item-grid-item>
<n-form-item-grid-item :span="1" label="型号规格">
<n-input v-model:value="panel.form.specification" disabled placeholder="请选择物品"></n-input>
</n-form-item-grid-item>
<n-form-item-grid-item :span="1" label="单位">
<n-input v-model:value="panel.form.numMeasureName" disabled placeholder="请选择物品单位"></n-input>
</n-form-item-grid-item>
<n-form-item-grid-item :span="1" label="颜色">
<n-input v-model:value="panel.form.color" disabled placeholder="请选择物品颜色"></n-input>
</n-form-item-grid-item>
<n-form-item-grid-item :span="1" label="数量">
<n-input-number v-model:value="panel.form.quantity" class="w-full" :min="0">
<template #suffix>
<div>
{{ panel.form.numMeasureName }}
</div>
</template>
</n-input-number>
</n-form-item-grid-item>
<n-form-item-grid-item :span="1" label="单价">
<n-input-number v-model:value="panel.form.price" class="w-full" :min="0">
<template #suffix>
<div>¥</div>
</template>
</n-input-number>
</n-form-item-grid-item>
<!-- <n-form-item-grid-item :span="1" label="数量">
<n-input-number v-model:value="panel.form.weight" class="w-full" :min="0">
<template #suffix>
<div>(kg)</div>
</template>
</n-input-number>
</n-form-item-grid-item> -->
<n-form-item-grid-item :span="1" label="计划交货日期">
<n-date-picker
v-model:value="panel.form.deliveryDate"
type="date"
class="w-full"
:min="0"
></n-date-picker>
</n-form-item-grid-item>
<n-form-item-grid-item :span="1" label="申请原因">
<n-input v-model:value="panel.form.remark" type="textarea"></n-input>
</n-form-item-grid-item>
<n-form-item-grid-item :span="1" label="金额">
{{ getListTotal(panel, panel.form.weight, panel.form.price) }}
</n-form-item-grid-item>
</n-grid>
</n-form>
</n-tab-pane>
</n-tabs>
</div>
</template>
</my-dialog>
<my-dialog
v-model:show="detail"
sub-text="关闭"
width="800px"
title="订单明细"
:show-cancel="false"
@cancel="closeDetail"
@submit="closeDetail"
>
<template #content>
<div>
<n-data-table
class="w-760px"
:loading="detailLoading"
:columns="detailColumns"
:data="detailData"
></n-data-table>
</div>
</template>
</my-dialog>
</div>
</template>
<script setup lang="tsx">
import type { Ref } from 'vue';
import { ref, onMounted, computed, getCurrentInstance } from 'vue';
import type { FormInst, DataTableColumns, DataTableRowKey } from 'naive-ui';
import { useMessage } from 'naive-ui';
import BigNumber from 'bignumber.js';
import { listDept } from '@/service';
import { addDateRange, deepClone, createRequiredFormRule } from '@/utils';
import { handleTree } from '@/utils/form';
const { proxy } = getCurrentInstance() as any;
const { erp_auxiliary_status } = proxy.useDict('erp_auxiliary_status');
import { useSearchBtn, useInfoBtn, useBtn, useAddBtn, useEditBtn, useDelBtn } from '@/hooks/common/useBtn';
import {
addPurchase,
getAllSupplier,
// getAllRawProcureList,
getPurchaseList,
delPurchase,
getPurchaseDetail,
delPurchaseDetail,
getPurchaseTop,
editPurchase,
sendPurchase
} from '@/service/api/erp/rawProcureList';
import { getSaleOrderAll } from '@/service/api/sale/order';
import { getMaterialAllAccessory } from '@/service/api/md/itemlist/index';
import { useLoading } from '~/src/hooks';
const rules = {
deptId: createRequiredFormRule('请选择部门'),
vendorId: createRequiredFormRule('请选择供应商')
// planId: createRequiredFormRule('请选择订单')
};
const addFormRef = ref<FormInst | null>(null);
const message = useMessage();
const detailLoading = ref<boolean>(false);
const detail = ref<boolean>(false);
function closeDetail() {
detail.value = false;
}
const detailData = ref<Procure.rawProcureList.listType[]>([]);
const detailColumns: DataTableColumns<Procure.rawProcureList.listType> = [
{
title: '序号',
key: 'index',
render(_row, index) {
return index + 1;
},
width: 80
},
{
title: '物料名称',
key: 'itemName',
width: 180
},
{
title: '物料编码',
key: 'itemCode',
width: 180
},
{
title: '计划交货时间',
key: 'deliveryDate',
width: 180
},
{
title: '单价',
key: 'price',
width: 80
},
// {
// title: '数量',
// key: 'weight',
// width: 80
// },
{
title: '数量',
key: 'quantity',
width: 80
},
{
title: '规格型号',
key: 'specification',
width: 180
},
{
title: '总价格',
key: 'totalPrice',
width: 80
},
{
title: '操作',
key: 'action',
width: 90,
fixed: 'right',
render: row => {
return useDelBtn(() => {
delPurchaseDetail(row.lineId as string).then(res => {
if (res.code === 200) {
message.success('删除成功');
detailLoading.value = false;
getPurchaseDetail(row.purchaseId as string).then(respon => {
detailLoading.value = false;
detailData.value = respon.rows;
});
} else {
message.error('删除失败');
}
});
}, 'tiny');
}
}
];
type Panel = {
name: string;
form: { [key: string]: any };
};
const panels = ref<Panel[]>([
{
name: '明细1',
form: {}
}
]);
const addable = computed(() => {
return panels.value.length < 10;
});
const closable = computed(() => {
return panels.value.length > 1;
});
function handleAdd() {
panels.value.push({ name: `明细${panels.value.length + 1}`, form: {} });
}
function sendTip(num: number) {
if (num <= panels.value.length) message.warning('请从尾部开始删除');
}
function handleClose(name: string) {
let flag = 0;
const number = panels.value.length - 1;
panels.value.forEach((panel, index) => {
if (panel.name === name && index === number) {
panels.value = panels.value.filter(item => item.name !== name);
}
flag += 1;
});
sendTip(flag);
}
function getListTotal(total, num, price) {
const tempNum = new BigNumber(num || 0);
console.log(tempNum);
const tempQuantity = new BigNumber(total.form.quantity || 0);
const tempPrice = new BigNumber(price || 0);
total.form.totalPrice = tempQuantity.times(tempPrice).toFixed(4);
// if (total.form.unitType === 'num') {
// total.form.totalPrice = tempQuantity.times(tempPrice).toFixed(4);
// } else if (total.form.unitType === 'weight') {
// total.form.totalPrice = tempNum.times(tempPrice).toFixed(4);
// }
// eslint-disable-next-line no-param-reassign, @typescript-eslint/no-unused-vars
return total.form.totalPrice;
}
const editFlag = ref(false);
const getTotalPric = computed(() => {
return panels.value.reduce((total, panel) => {
const temp1 = new BigNumber(total || 0);
const temp2 = new BigNumber(panel.form.totalPrice || 0);
return parseFloat(temp1.plus(temp2).toFixed(4));
}, 0);
});
const getTotalNum = computed(() => {
return panels.value.reduce((total, panel) => {
const temp1 = new BigNumber(total || 0);
const temp2 = new BigNumber(panel.form.quantity || 0);
return parseFloat(temp1.plus(temp2).toFixed(4));
}, 0);
});
const getTotalWeight = computed(() => {
return panels.value.reduce((total, panel) => {
const temp1 = new BigNumber(total || 0);
const temp2 = new BigNumber(panel.form.weight || 0);
return parseFloat(temp1.plus(temp2).toFixed(4));
}, 0);
});
const { loading, startLoading, endLoading } = useLoading();
const showDialog = ref<boolean>(false);
const dateArr = ref<null | undefined | [number, number]>(null);
const selectKeys = ref<DataTableRowKey[]>([]);
function handleSelect(keys: DataTableRowKey[]) {
selectKeys.value = keys;
}
function delSelect() {
delPurchase(selectKeys.value.join(',')).then(res => {
if (res.code === 200) {
message.success('删除成功');
init();
} else {
message.error(res.msg);
}
});
}
// const statusOptions = [
// {
// label: '全部',
// value: undefined
// },
// {
// label: '待处理',
// value: '待处理'
// },
// {
// label: '处理中',
// value: '处理中'
// },
// {
// label: '已完成',
// value: '已完成'
// }
// ];
const searchForm = ref<{
vendorId: string | null;
attr1: string | null;
pageSize: number;
pageNum: number;
total: number;
deptId: string | null;
}>({
vendorId: null,
attr1: null,
deptId: null,
pageSize: 10,
pageNum: 1,
total: 0
});
function search() {
searchForm.value.pageNum = 1;
init();
}
function reset() {
searchForm.value = {
vendorId: null,
attr1: null,
deptId: null,
pageSize: 10,
pageNum: 1,
total: 0
};
dateArr.value = null;
init();
}
const dialogForm = ref<Procure.rawProcureList.columns>({
attr1: null,
beginTime: null,
checkedBy: null,
checkedByNick: null,
checkedTime: null,
contractTime: null,
createBy: null,
createByNick: null,
createTime: null,
deptId: null,
deptName: null,
enableFlag: null,
endTime: null,
filePath: null,
flowAction: null,
flowRecordJson: null,
invoiceSta: null,
lineList: [],
paidMoney: null,
params: {},
payableMoney: null,
planCode: null,
planId: null,
purchaseCode: null,
purchaseDate: null,
purchaseId: null,
quantity: null,
realTotalPrice: null,
realTotalWeight: null,
remark: null,
snidCode: null,
status: null,
totalPrice: null,
totalWeight: null,
type: null,
updateBy: null,
updateTime: null,
vendorAddress: null,
vendorCode: null,
vendorContact1: null,
vendorContact1Tel: null,
vendorId: null,
vendorName: null
});
function cancel() {
showDialog.value = false;
dialogForm.value = {
attr1: null,
beginTime: null,
checkedBy: null,
checkedByNick: null,
checkedTime: null,
contractTime: null,
createBy: null,
createByNick: null,
createTime: null,
deptId: null,
deptName: null,
enableFlag: null,
endTime: null,
filePath: null,
flowAction: null,
flowRecordJson: null,
invoiceSta: null,
lineList: [],
paidMoney: null,
params: {},
payableMoney: null,
planCode: null,
planId: null,
purchaseCode: null,
purchaseDate: null,
purchaseId: null,
quantity: null,
realTotalPrice: null,
realTotalWeight: null,
remark: null,
snidCode: null,
status: null,
totalPrice: null,
totalWeight: null,
type: null,
updateBy: null,
updateTime: null,
vendorAddress: null,
vendorCode: null,
vendorContact1: null,
vendorContact1Tel: null,
vendorId: null,
vendorName: null
};
panels.value = [
{
name: '明细1',
form: {}
}
];
init();
}
function submit() {
addFormRef.value?.validate(error => {
if (!error) {
dialogForm.value.lineList = [];
panels.value.forEach(item => {
delete item.form.id;
delete item.form.ifEnable;
delete item.form.ifSafeStock;
delete item.form.version;
delete item.form.createTime;
delete item.form.createBy;
item.form.unitOfMeasure = item.form.numMeasureName;
dialogForm.value.lineList.push(item.form as unknown as Procure.rawProcureList.listType);
});
delete dialogForm.value.children;
dialogForm.value.totalPrice = getTotalPric.value.toString();
dialogForm.value.quantity = getTotalNum.value.toString();
dialogForm.value.totalWeight = getTotalWeight.value.toString();
if (dialogForm.value.purchaseId) {
dialogForm.value.status = 'PREPARE';
editPurchase(dialogForm.value).then(res => {
if (res.code === 200) {
message.success(res.msg);
cancel();
}
});
} else {
dialogForm.value.attr1 = 'YL';
dialogForm.value.status = 'PREPARE';
addPurchase(dialogForm.value).then(res => {
if (res.code === 200) {
message.success(res.msg);
cancel();
}
});
}
}
});
}
const data = ref<Procure.rawProcureList.columns[]>([]);
const columns: Ref<DataTableColumns<Procure.rawProcureList.columns>> = ref([
{
type: 'selection'
},
{
title: '订单编号',
key: 'purchaseCode',
width: 100
},
{
title: '采购部门',
key: 'deptName',
width: 280
},
{ title: '供应商', key: 'vendorName', width: 180 },
{
title: '关联订单编号',
key: 'planCode',
width: 180
},
{
title: '计划数量',
key: 'quantity',
width: 80
},
// {
// title: '计划数量',
// key: 'totalWeight',
// width: 80
// },
{
title: '总价',
key: 'totalPrice',
width: 80
},
// {
// title: '型号规格',
// key: 'specification',
// width: 180
// },
// {
// title: '单位',
// key: 'unitOfMeasure',
// width: 80
// },
// {
// title: '计划开始日期',
// key: 'planDateStart',
// width: 180
// },
{
title: '创建日期',
key: 'createTime',
width: 180
},
{
title: '计划员',
key: 'createBy',
width: 150
},
{
title: '状态',
key: 'status',
width: 80,
fixed: 'right',
align: 'center',
render: row => {
console.log(row.status);
return <dict-tag options={erp_auxiliary_status.value} value={row.status}></dict-tag>;
}
},
// {
// title: '计划时间',
// key: 'planMonth',
// width: 280
// },
{
title: '操作',
key: 'action',
fixed: 'right',
width: 220,
render: row => {
const Btn: JSX.Element[] = [];
if (row.status === 'PREPARE') {
Btn.push(
useBtn(
() => {
// row.status = 'DISTRIBUTE';
sendPurchase({ ...row, status: 'DISTRIBUTE' }).then(res => {
console.log(res);
if (res.code === 200) {
message.success('下发成功');
init();
}
});
},
'send',
'tiny'
)
);
Btn.push(
useEditBtn(() => {
editFlag.value = true;
getPurchaseTop(row.purchaseId as string).then(res => {
dialogForm.value = deepClone(res.data);
if (res.data.lineList.length > 0) {
panels.value = [];
res.data.lineList.forEach((item, index) => {
panels.value.push({
name: `明细${index + 1}`,
form: { ...item, deliveryDate: new Date(item.deliveryDate), numMeasureName: item.unitOfMeasure }
});
});
}
showDialog.value = true;
});
}, 'tiny')
);
}
Btn.push(
...[
useInfoBtn(
() => {
detail.value = true;
detailLoading.value = true;
getPurchaseDetail(row.purchaseId as string).then(res => {
detailLoading.value = false;
detailData.value = res.rows;
});
},
'tiny',
'明细'
),
useDelBtn(() => {
delPurchase(row.purchaseId as string).then(res => {
if (res.code === 200) {
message.success('删除成功!');
init();
}
});
}, 'tiny')
]
);
return Btn;
}
}
]);
function init() {
startLoading();
if (dateArr.value) {
addDateRange(searchForm.value, dateArr.value);
}
searchForm.value.attr1 = 'YL';
getPurchaseList(searchForm.value).then(res => {
data.value = res.rows;
searchForm.value.total = res.total;
endLoading();
});
}
const itemOptions = ref<
{
value: string;
label: string;
unitType: string;
numMeasureId: number;
numMeasureName: string;
weightMeasureId: number;
weightMeasureName: string;
}[]
>([]);
function selectItem(form) {
itemOptions.value.forEach(item => {
if (item.value === form.itemId) {
Object.assign(form, item);
if (item.numMeasureId && item.numMeasureId !== 0) {
form.numMeasureName = item.numMeasureName;
} else {
form.numMeasureName = item.weightMeasureName;
}
}
});
}
const treeOptions = ref<any>();
function treeSelect(_val, item) {
dialogForm.value.deptId = item.deptId;
dialogForm.value.deptName = item.deptName;
}
const supperOptions = ref<{ value: string; label: string }[]>([]);
function handleSelectSupper(_val, item) {
dialogForm.value.vendorAddress = item.address;
dialogForm.value.vendorCode = item.vendorCode;
dialogForm.value.vendorContact1 = item.contact1;
dialogForm.value.vendorContact1Tel = item.contact1Tel;
dialogForm.value.vendorName = item.vendorName;
}
const rawProucreOptions = ref<{ value: string; label: string }[]>([]);
function handleSelectRawProucre(_val, item) {
dialogForm.value.planId = item.value;
dialogForm.value.planCode = item.label;
// dialogForm.value = Object.assign(dialogForm.value, item);
}
onMounted(() => {
// 获取物料列表
getMaterialAllAccessory({ pageSize: 999 }).then(res => {
console.log(res);
res.rows.forEach(item => {
itemOptions.value.push({
value: item.id,
label: item.itemName + "(" + item.colorName + ")",
...item
});
});
});
// 获取部门列表
listDept({}).then(res => {
treeOptions.value = handleTree(res.data, 'deptId', 'parentId', 'children');
// console.log(handleTree(res.data, 'deptId', 'parentId', 'children'), 222);
// console.log(res, 11);
});
// 获取供应商列表
getAllSupplier({ pageSize: 999 }).then(res => {
res.rows.forEach(item => {
supperOptions.value.push({
value: item.id,
label: item.supplierName,
...item
});
});
});
// 获取计划列表
getSaleOrderAll().then(res => {
res.data.forEach(item => {
rawProucreOptions.value.push({
value: item.id,
label: item.orderCode,
...item
});
});
});
init();
});
</script>
<style scoped></style>