---初始化后台管理web页面项目

This commit is contained in:
2025-08-20 14:39:30 +08:00
parent ad49711a7e
commit 87545a8baf
2057 changed files with 282864 additions and 213 deletions

View File

@ -0,0 +1,714 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" title="查看订单详情" @cancel="handleCancel">
<div class="info-box">
<a-card :bordered="false">
<div class="title-name">{{ baseInfo?.theme }}</div>
<div class="title-info">
<span>创建人{{ baseInfo?.createUserName }}</span>
<span>创建时间{{ baseInfo?.createDate }}</span>
<span>最后修改人{{ baseInfo?.modifyUserName }}</span>
<span>修改时间{{ baseInfo?.modifyDate }}</span>
</div>
<div>
<a-button size="small" class="title-btn" @click="handlePrint">打印</a-button>
</div>
</a-card>
<a-card :bordered="false">
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="订单信息">
<a-row>基础信息</a-row>
<a-row>
<a-col :span="12">采购单号{{ baseInfo?.purchaseNumber }}</a-col>
<a-col :span="12">订单主题{{ baseInfo?.theme }}</a-col>
</a-row>
<a-row>
<a-col :span="12">采购日期{{ baseInfo?.purchaseDate }}</a-col>
<a-col :span="12">供应商名称{{ baseInfo?.supplierName }}</a-col>
</a-row>
<a-row>
<a-col :span="12">联系人{{ baseInfo?.supplierPerson }}</a-col>
<a-col :span="12">联系方式{{ baseInfo?.supplierWay }}</a-col>
</a-row>
<a-row>
<a-col :span="12">采购部门{{ baseInfo?.purchaseDeptName }}</a-col>
<a-col :span="12">采购人员{{ baseInfo?.purchasePersonName }}</a-col>
</a-row>
<a-row>
<a-col :span="12">联系电话{{ baseInfo?.purchasePhone }}</a-col>
<a-col :span="12">关联项目{{ baseInfo?.relatedProjectName }}</a-col>
</a-row>
<a-row> 结算方式{{ baseInfo?.payTypeName }} </a-row>
<a-row> 交货地址{{ baseInfo?.payAddress }} </a-row>
<a-row> 备注{{ baseInfo?.remark }} </a-row>
<BasicTable @register="registerPurchaseTable">
<template #toolbar>
<a-button type="primary" @click="handleExport('purchase')">导出</a-button>
</template>
</BasicTable>
<div class="table-bottom">
<span>合计</span>
<div>
<span>总量{{ baseInfo?.countSum }}</span>
<span> 总金额{{ baseInfo?.amountSum }}</span>
</div>
</div>
<div>
附件
<Upload
v-if="baseInfo?.filePath"
v-model:value="baseInfo.filePath"
listType="dragger"
:style="{ width: '200px', display: 'none' }"
:showRemoveIcon="false"
/>
</div>
</a-tab-pane>
<a-tab-pane key="2">
<template #tab>
<span>
入库记录
<Icon
icon="ant-design:check-circle-filled"
:size="20"
v-if="baseInfo?.inStoreState === 1"
/>
<Icon
icon="ant-design:exclamation-circle-filled"
color="#FF1A2E"
:size="20"
v-else
/>
</span>
</template>
<BasicTable @register="registerInstoreTable">
<template #toolbar>
<a-button type="primary" @click="handleExport('instore')">导出</a-button>
</template>
</BasicTable>
</a-tab-pane>
<a-tab-pane key="3">
<template #tab>
<span>
到票记录
<Icon
icon="ant-design:check-circle-filled"
:size="20"
v-if="baseInfo?.ticketState === 1"
/>
<Icon
icon="ant-design:exclamation-circle-filled"
color="#FF1A2E"
:size="20"
v-else
/>
</span>
</template>
<BasicTable @register="registerTicketTable">
<template #toolbar>
<a-button type="primary" @click="handleExport('ticket')">导出</a-button>
</template>
</BasicTable>
</a-tab-pane>
<a-tab-pane key="4">
<template #tab>
<span>
付款记录
<Icon
icon="ant-design:check-circle-filled"
:size="20"
v-if="baseInfo?.payState === 1"
/>
<Icon
icon="ant-design:exclamation-circle-filled"
color="#FF1A2E"
:size="20"
v-else
/>
</span>
</template>
<BasicTable @register="registerPayTable">
<template #toolbar>
<a-button type="primary" @click="handleExport('pay')">导出</a-button>
</template>
</BasicTable>
</a-tab-pane>
<a-tab-pane key="5" tab="审批记录">
<FlowRecord
v-if="isReady"
:list="workflowList"
:processInstanceId="baseInfo.processInstanceId"
/>
</a-tab-pane>
<a-tab-pane key="6" tab="操作记录">
<BasicTable @register="registerLogTable">
<template #toolbar>
<a-button type="primary" @click="handleExport('log')">导出</a-button>
</template>
</BasicTable>
</a-tab-pane>
</a-tabs>
</a-card>
</div>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { BasicTable, useTable, BasicColumn, FormSchema } from '/@/components/Table';
import { BasicModal, useModalInner } from '/@/components/Modal';
import {
exportPurchaseInfo,
exportInstoreInfo,
exportTicketInfo,
exportPayInfo,
exportLogInfo,
} from '/@/api/erp/purchase/order';
import { getPurchaseCheckInfo } from '/@/api/erp/purchase/order';
import { getRecordList } from '/@/api/erp/purchase/order';
import { getFileList } from '/@/api/system/file';
import { useMessage } from '/@/hooks/web/useMessage';
import { downloadByData } from '/@/utils/file/download';
import FlowRecord from '/@/views/workflow/task/components/flow/FlowRecord.vue';
import Icon from '/@/components/Icon/index';
import Upload from '/@/components/Form/src/components/Upload.vue';
import printJS from 'print-js';
import domtoimage from 'dom-to-image';
import { isNil } from 'lodash-es';
const purchaseColumns: BasicColumn[] = [
{
title: '物料编码',
dataIndex: 'code',
},
{
title: '物料名称',
dataIndex: 'name',
},
{
title: '规格型号',
dataIndex: 'model',
},
{
title: '单位',
dataIndex: 'unitName',
},
{
title: '单价',
dataIndex: 'price',
},
{
title: '采购数量',
dataIndex: 'count',
},
{
title: '折扣',
dataIndex: 'discount',
},
{
title: '税率',
dataIndex: 'taxRate',
},
{
title: '税费',
dataIndex: 'taxBreak',
},
{
title: '税后金额',
dataIndex: 'afterTaxAmount',
},
{
title: '已入库数量',
dataIndex: 'inStoreCount',
},
{
title: '未入库数量',
dataIndex: 'noInStoreCount',
},
{
title: '退货数量',
dataIndex: 'returnCount',
},
{
title: '交付日期',
dataIndex: 'deliveryDate',
},
];
const instoreColumns: BasicColumn[] = [
{
dataIndex: 'code',
title: '入库单号',
align: 'center',
width: 100,
},
{
dataIndex: 'theme',
title: '入库订单主题',
align: 'center',
width: 100,
},
{
dataIndex: 'date',
title: '入库日期',
align: 'center',
width: 100,
},
{
dataIndex: 'name',
title: '供应商名称',
align: 'center',
width: 100,
},
{
dataIndex: 'person',
title: '入库人员',
align: 'center',
width: 100,
},
{
dataIndex: 'store',
title: '入库仓库',
align: 'center',
width: 100,
},
];
const ticketColumns: BasicColumn[] = [
{
dataIndex: 'code',
title: '到票编号',
align: 'center',
width: 100,
},
{
dataIndex: 'theme',
title: '到票主题',
align: 'center',
width: 100,
},
{
dataIndex: 'date',
title: '到票日期',
align: 'center',
width: 100,
},
{
dataIndex: 'name',
title: '开票方',
align: 'center',
width: 100,
},
{
dataIndex: 'ticketNum',
title: '发票号码',
align: 'center',
width: 100,
},
{
dataIndex: 'ticketAmout',
title: '到票金额',
align: 'center',
width: 100,
},
];
const payColumns: BasicColumn[] = [
{
dataIndex: 'code',
title: '付款编号',
align: 'center',
width: 100,
},
{
dataIndex: 'theme',
title: '付款主题',
align: 'center',
width: 100,
},
{
dataIndex: 'date',
title: '付款日期',
align: 'center',
width: 100,
},
{
dataIndex: 'amount',
title: '付款总额',
align: 'center',
width: 100,
},
{
dataIndex: 'payer',
title: '收款方',
align: 'center',
width: 100,
},
{
dataIndex: 'account',
title: '银行账号',
align: 'center',
width: 100,
},
];
const logColumns: BasicColumn[] = [
{
dataIndex: 'operateUserAccount',
title: '操作人',
align: 'center',
},
{
dataIndex: 'createDate',
title: '操作时间',
align: 'center',
},
{
dataIndex: 'executeResultJson',
title: '操作类型',
align: 'center',
},
];
const searchFormSchema: FormSchema[] = [
{
field: 'keyword',
label: '',
component: 'Input',
colProps: { span: 8 },
componentProps: {
placeholder: '请输入要查询的关键字',
},
},
];
const purchaseInfoDataSource = ref<any>([]);
const instoreDataSource = ref<any>([]);
const ticketDataSource = ref<any>([]);
const payDataSource = ref<any>([]);
const logInfoDataSource = ref<any>([]);
const isReady = ref(false);
const rowId = ref('');
const activeKey = ref('1');
const baseInfo = ref();
const workflowList = ref();
const imgList = ref<any>([]);
const { notification } = useMessage();
const [registerModal, { setModalProps }] = useModalInner(async (data) => {
setModalProps({
confirmLoading: false,
destroyOnClose: true,
showCancelBtn: false,
showOkBtn: false,
width: 1000,
fixedHeight: true,
footer: null,
});
rowId.value = data.id;
getInfo();
});
const [registerPurchaseTable, { getSelectRowKeys: getPurchaseRowKeys }] = useTable({
title: '采购物料',
dataSource: purchaseInfoDataSource,
rowKey: 'id',
columns: purchaseColumns,
bordered: true,
pagination: false,
rowSelection: {
type: 'checkbox',
},
});
const [registerInstoreTable, { getSelectRowKeys: getInstoreRowKeys, setProps: setInstoreProps }] =
useTable({
dataSource: instoreDataSource,
rowKey: 'id',
columns: instoreColumns,
handleSearchInfoFn(info) {
const filterData = instoreDataSource.value.filter((item) => {
for (const key in item) {
if (!isNil(item[key]) && item[key].toString().indexOf(info.keyword) > -1) {
return item;
}
}
});
setInstoreProps({ dataSource: filterData });
return info;
},
formConfig: {
schemas: searchFormSchema,
},
bordered: true,
pagination: false,
useSearchForm: true,
rowSelection: {
type: 'checkbox',
},
});
const [registerTicketTable, { getSelectRowKeys: getTicketRowKeys, setProps: setTicketProps }] =
useTable({
dataSource: ticketDataSource,
rowKey: 'id',
columns: ticketColumns,
handleSearchInfoFn(info) {
const filterData = ticketDataSource.value.filter((item) => {
for (const key in item) {
if (!isNil(item[key]) && item[key].toString().indexOf(info.keyword) > -1) {
return item;
}
}
});
setTicketProps({ dataSource: filterData });
return info;
},
formConfig: {
schemas: searchFormSchema,
},
bordered: true,
pagination: false,
useSearchForm: true,
rowSelection: {
type: 'checkbox',
},
});
const [registerPayTable, { getSelectRowKeys: getPayRowKeys, setProps: setPayProps }] = useTable({
dataSource: payDataSource,
rowKey: 'id',
columns: payColumns,
handleSearchInfoFn(info) {
const filterData = payDataSource.value.filter((item) => {
for (const key in item) {
if (!isNil(item[key]) && item[key].toString().indexOf(info.keyword) > -1) {
return item;
}
}
});
setPayProps({ dataSource: filterData });
return info;
},
formConfig: {
schemas: searchFormSchema,
},
bordered: true,
pagination: false,
useSearchForm: true,
rowSelection: {
type: 'checkbox',
},
});
const [registerLogTable, { getSelectRowKeys: getLogRowKeys, setProps: setLogProps }] = useTable({
dataSource: logInfoDataSource,
rowKey: 'id',
columns: logColumns,
handleSearchInfoFn(info) {
const filterData = logInfoDataSource.value.filter((item) => {
for (const key in item) {
if (!isNil(item[key]) && item[key].toString().indexOf(info.keyword) > -1) {
return item;
}
}
});
setLogProps({ dataSource: filterData });
return info;
},
formConfig: {
schemas: searchFormSchema,
},
useSearchForm: true,
bordered: true,
pagination: false,
rowSelection: {
type: 'checkbox',
},
});
const getInfo = async () => {
const res = await getPurchaseCheckInfo(rowId.value);
baseInfo.value = res;
purchaseInfoDataSource.value = res?.caseErpPurchaseDetailList;
instoreDataSource.value = res?.inStoreLogVoList.map((x) => {
return {
code: x.code,
theme: x.theme,
date: x.date,
name: x.name,
person: x.person,
store: x.store,
};
});
ticketDataSource.value = res?.ticketLogVoList.map((x) => {
return {
code: x.code,
theme: x.theme,
date: x.date,
name: x.name,
ticketNum: x.ticketNum,
ticketAmout: x.ticketAmout,
};
});
payDataSource.value = res?.payLogVoList.map((x) => {
return {
code: x.code,
theme: x.theme,
date: x.date,
amount: x.amount,
payer: x.payer,
account: x.account,
};
});
logInfoDataSource.value = res?.logList.map((x) => {
return {
operateUserAccount: x.operateUserAccount,
createDate: x.createDate,
executeResultJson: x.executeResultJson,
};
});
if (baseInfo.value.processInstanceId) {
const res = await getRecordList(baseInfo.value.processInstanceId);
workflowList.value = [
{
records: res.taskRecords,
schemaName: '当前流程',
},
];
}
isReady.value = true;
if (baseInfo.value.filePath) {
imgList.value = await getFileList({ folderId: baseInfo.value.filePath });
}
};
const handleCancel = () => {
isReady.value = false;
workflowList.value = [];
activeKey.value = '1';
};
const handleExport = async (type) => {
const params: any = {
saleId: rowId.value,
};
let title = '';
let res;
switch (type) {
case 'purchase':
if (!notice(getPurchaseRowKeys().length)) return;
title = '采购信息';
params.ids = getPurchaseRowKeys();
res = await exportPurchaseInfo(params);
break;
case 'instore':
if (!notice(getInstoreRowKeys().length)) return;
title = '入库记录';
params.ids = getInstoreRowKeys();
res = await exportInstoreInfo(params);
break;
case 'ticket':
if (!notice(getTicketRowKeys().length)) return;
title = '到票记录';
params.ids = getTicketRowKeys();
res = await exportTicketInfo(params);
break;
case 'pay':
if (!notice(getPayRowKeys().length)) return;
title = '付款记录';
params.ids = getPayRowKeys();
res = await exportPayInfo(params);
break;
case 'log':
title = '操作记录';
params.ids = getLogRowKeys();
res = await exportLogInfo(params);
break;
}
downloadByData(
res.data,
`${title}.xlsx`,
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
);
};
const notice = (length) => {
if (!length) {
notification.warning({
message: 'Tip',
description: '请选择需要导出的数据',
});
return false;
}
return true;
};
const handlePrint = async () => {
const element: HTMLElement = window.document.querySelector('.info-box')!;
const url = await domtoimage.toPng(element);
printJS({
printable: url,
type: 'image',
documentTitle: '打印',
});
};
</script>
<style lang="less" scoped>
.info-box {
background-color: #fff;
width: 100%;
height: 100%;
padding: 16px;
margin-right: 8px;
.title-name {
font-size: 18px;
color: #444;
font-weight: 700;
}
.title-info {
margin: 10px 0;
span {
margin-right: 40px;
}
}
.table-bottom {
display: flex;
justify-content: space-between;
margin: 10px 0;
& > div > span {
margin-left: 40px;
}
}
.title-btn {
margin-right: 5px;
}
}
.ant-row {
margin-bottom: 15px;
}
:deep(.vben-basic-table) {
height: 300px;
}
:deep(.ant-table-wrapper),
:deep(.ant-table-title) {
background-color: #f8f8f8;
}
:deep(.ant-card-body) {
background-color: #f8f8f8;
margin-bottom: 12px;
padding: 15px;
}
:deep(.ant-tabs) {
height: 70%;
}
:deep(.ant-tabs-content) {
height: 100%;
}
</style>