潘的第一次 commit
This commit is contained in:
147
erp-frontend-vue/src/views/Sales/Reports/DetailReport.vue
Normal file
147
erp-frontend-vue/src/views/Sales/Reports/DetailReport.vue
Normal file
@@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<el-card class="search-card" shadow="never">
|
||||
<el-form :model="searchForm" inline>
|
||||
<el-form-item label="订单编号">
|
||||
<el-input v-model="searchForm.orderCode" placeholder="请输入订单编号" clearable style="width: 180px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="客户名称">
|
||||
<el-input v-model="searchForm.customerName" placeholder="请输入客户名称" clearable style="width: 180px;" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>查询
|
||||
</el-button>
|
||||
<el-button @click="handleReset">
|
||||
<el-icon><Refresh /></el-icon>重置
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card class="table-card" shadow="never">
|
||||
<div class="toolbar">
|
||||
<el-button type="success" @click="handleExport">
|
||||
<el-icon><Download /></el-icon>导出
|
||||
</el-button>
|
||||
<el-button @click="handlePrint">
|
||||
<el-icon><Printer /></el-icon>打印
|
||||
</el-button>
|
||||
<el-divider direction="vertical" />
|
||||
<el-button type="primary" @click="handlePlanProduction">计划生产</el-button>
|
||||
<el-button type="warning" @click="handleStockSupply">库存供应</el-button>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="loading" :data="tableData" stripe border show-summary :summary-method="getSummaries">
|
||||
<el-table-column type="selection" width="50" />
|
||||
<el-table-column type="index" label="序号" width="60" />
|
||||
<el-table-column prop="orderCode" label="订单编号" width="150" />
|
||||
<el-table-column prop="orderDate" label="订单日期" width="120" />
|
||||
<el-table-column prop="customerName" label="客户名称" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="materialCode" label="物料编号" width="120" />
|
||||
<el-table-column prop="materialName" label="物料名称" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="spec" label="规格型号" width="150" />
|
||||
<el-table-column prop="unit" label="单位" width="80" />
|
||||
<el-table-column prop="orderQty" label="订单数量" width="100" align="right" />
|
||||
<el-table-column prop="price" label="单价" width="100" align="right" />
|
||||
<el-table-column prop="amount" label="金额" width="120" align="right">
|
||||
<template #default="{ row }">¥{{ row.amount?.toLocaleString() }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deliveryDate" label="交货日期" width="120" />
|
||||
<el-table-column prop="status" label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status === '审核' ? 'success' : ''">{{ row.status }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
v-model:current-page="pagination.page"
|
||||
v-model:page-size="pagination.pageSize"
|
||||
:page-sizes="[20, 50, 100]"
|
||||
:total="pagination.total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="loadData"
|
||||
@current-change="loadData"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Search, Refresh, Download, Printer } from '@element-plus/icons-vue'
|
||||
|
||||
interface DetailRow {
|
||||
orderCode: string
|
||||
orderDate: string
|
||||
customerName: string
|
||||
materialCode: string
|
||||
materialName: string
|
||||
spec: string
|
||||
unit: string
|
||||
orderQty: number
|
||||
price: number
|
||||
amount: number
|
||||
deliveryDate: string
|
||||
status: string
|
||||
}
|
||||
|
||||
const searchForm = reactive({ orderCode: '', customerName: '' })
|
||||
const pagination = reactive({ page: 1, pageSize: 20, total: 0 })
|
||||
const loading = ref(false)
|
||||
const tableData = ref<DetailRow[]>([])
|
||||
|
||||
const mockData: DetailRow[] = [
|
||||
{ orderCode: 'SO2024010001', orderDate: '2024-01-15', customerName: '深圳市ABC科技有限公司', materialCode: 'M001', materialName: '电子元器件A', spec: '10*10*5mm', unit: '个', orderQty: 100, price: 50, amount: 5000, deliveryDate: '2024-01-25', status: '审核' },
|
||||
{ orderCode: 'SO2024010001', orderDate: '2024-01-15', customerName: '深圳市ABC科技有限公司', materialCode: 'M002', materialName: '电子元器件B', spec: '20*15*8mm', unit: '个', orderQty: 200, price: 50, amount: 10000, deliveryDate: '2024-01-25', status: '审核' },
|
||||
{ orderCode: 'SO2024010002', orderDate: '2024-01-18', customerName: '广州市XYZ贸易有限公司', materialCode: 'M003', materialName: '机械零件C', spec: 'Φ50*100mm', unit: '件', orderQty: 50, price: 500, amount: 25000, deliveryDate: '2024-02-01', status: '开立' }
|
||||
]
|
||||
|
||||
const getSummaries = ({ columns, data }: { columns: any[], data: DetailRow[] }) => {
|
||||
const sums: string[] = []
|
||||
columns.forEach((column, index) => {
|
||||
if (index === 0) { sums[index] = '合计'; return }
|
||||
if (column.property === 'orderQty') {
|
||||
sums[index] = String(data.reduce((sum, row) => sum + row.orderQty, 0))
|
||||
} else if (column.property === 'amount') {
|
||||
sums[index] = '¥' + data.reduce((sum, row) => sum + row.amount, 0).toLocaleString()
|
||||
} else {
|
||||
sums[index] = ''
|
||||
}
|
||||
})
|
||||
return sums
|
||||
}
|
||||
|
||||
const loadData = async () => {
|
||||
loading.value = true
|
||||
setTimeout(() => {
|
||||
let list = [...mockData]
|
||||
if (searchForm.orderCode) list = list.filter(r => r.orderCode.includes(searchForm.orderCode))
|
||||
if (searchForm.customerName) list = list.filter(r => r.customerName.includes(searchForm.customerName))
|
||||
tableData.value = list
|
||||
pagination.total = list.length
|
||||
loading.value = false
|
||||
}, 300)
|
||||
}
|
||||
|
||||
const handleSearch = () => { pagination.page = 1; loadData() }
|
||||
const handleReset = () => { searchForm.orderCode = ''; searchForm.customerName = ''; handleSearch() }
|
||||
const handleExport = () => ElMessage.info('导出功能开发中')
|
||||
const handlePrint = () => ElMessage.info('打印功能开发中')
|
||||
const handlePlanProduction = () => ElMessage.info('计划生产功能开发中')
|
||||
const handleStockSupply = () => ElMessage.info('库存供应功能开发中')
|
||||
|
||||
onMounted(() => loadData())
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-container { padding: 4px; }
|
||||
.search-card { margin-bottom: 16px; }
|
||||
.search-card :deep(.el-card__body) { padding-bottom: 0; }
|
||||
.toolbar { margin-bottom: 16px; display: flex; gap: 8px; align-items: center; }
|
||||
.pagination-wrapper { margin-top: 16px; display: flex; justify-content: flex-end; }
|
||||
</style>
|
||||
135
erp-frontend-vue/src/views/Sales/Reports/PlanReport.vue
Normal file
135
erp-frontend-vue/src/views/Sales/Reports/PlanReport.vue
Normal file
@@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<el-card class="search-card" shadow="never">
|
||||
<el-form :model="searchForm" inline>
|
||||
<el-form-item label="订单编号">
|
||||
<el-input v-model="searchForm.orderCode" placeholder="请输入订单编号" clearable style="width: 180px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="客户名称">
|
||||
<el-input v-model="searchForm.customerName" placeholder="请输入客户名称" clearable style="width: 180px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="物料">
|
||||
<el-input v-model="searchForm.materialName" placeholder="请输入物料名称" clearable style="width: 180px;" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>查询
|
||||
</el-button>
|
||||
<el-button @click="handleReset">
|
||||
<el-icon><Refresh /></el-icon>重置
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card class="table-card" shadow="never">
|
||||
<div class="toolbar">
|
||||
<el-button type="success" @click="handleExport">
|
||||
<el-icon><Download /></el-icon>导出
|
||||
</el-button>
|
||||
<el-button @click="handlePrint">
|
||||
<el-icon><Printer /></el-icon>打印
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="loading" :data="tableData" stripe border show-summary>
|
||||
<el-table-column type="index" label="序号" width="60" />
|
||||
<el-table-column prop="orderCode" label="订单编号" width="150" />
|
||||
<el-table-column prop="customerName" label="客户名称" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="materialCode" label="物料编号" width="120" />
|
||||
<el-table-column prop="materialName" label="物料名称" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="spec" label="规格型号" width="150" />
|
||||
<el-table-column prop="unit" label="单位" width="80" />
|
||||
<el-table-column prop="orderQty" label="订单数量" width="100" align="right" />
|
||||
<el-table-column prop="planQty" label="计划数量" width="100" align="right" />
|
||||
<el-table-column prop="producedQty" label="已生产" width="100" align="right" />
|
||||
<el-table-column prop="deliveredQty" label="已发货" width="100" align="right" />
|
||||
<el-table-column prop="remainQty" label="未完成" width="100" align="right" />
|
||||
<el-table-column prop="deliveryDate" label="交货日期" width="120" />
|
||||
<el-table-column prop="status" label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getStatusType(row.status)">{{ row.status }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
v-model:current-page="pagination.page"
|
||||
v-model:page-size="pagination.pageSize"
|
||||
:page-sizes="[20, 50, 100]"
|
||||
:total="pagination.total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="loadData"
|
||||
@current-change="loadData"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Search, Refresh, Download, Printer } from '@element-plus/icons-vue'
|
||||
|
||||
interface PlanRow {
|
||||
orderCode: string
|
||||
customerName: string
|
||||
materialCode: string
|
||||
materialName: string
|
||||
spec: string
|
||||
unit: string
|
||||
orderQty: number
|
||||
planQty: number
|
||||
producedQty: number
|
||||
deliveredQty: number
|
||||
remainQty: number
|
||||
deliveryDate: string
|
||||
status: string
|
||||
}
|
||||
|
||||
const searchForm = reactive({ orderCode: '', customerName: '', materialName: '' })
|
||||
const pagination = reactive({ page: 1, pageSize: 20, total: 0 })
|
||||
const loading = ref(false)
|
||||
const tableData = ref<PlanRow[]>([])
|
||||
|
||||
const mockData: PlanRow[] = [
|
||||
{ orderCode: 'SO2024010001', customerName: '深圳市ABC科技有限公司', materialCode: 'M001', materialName: '电子元器件A', spec: '10*10*5mm', unit: '个', orderQty: 100, planQty: 100, producedQty: 80, deliveredQty: 50, remainQty: 50, deliveryDate: '2024-01-25', status: '生产中' },
|
||||
{ orderCode: 'SO2024010001', customerName: '深圳市ABC科技有限公司', materialCode: 'M002', materialName: '电子元器件B', spec: '20*15*8mm', unit: '个', orderQty: 200, planQty: 200, producedQty: 200, deliveredQty: 150, remainQty: 50, deliveryDate: '2024-01-25', status: '待发货' },
|
||||
{ orderCode: 'SO2024010002', customerName: '广州市XYZ贸易有限公司', materialCode: 'M003', materialName: '机械零件C', spec: 'Φ50*100mm', unit: '件', orderQty: 50, planQty: 50, producedQty: 0, deliveredQty: 0, remainQty: 50, deliveryDate: '2024-02-01', status: '待计划' }
|
||||
]
|
||||
|
||||
const getStatusType = (status: string) => {
|
||||
const map: Record<string, string> = { '待计划': 'info', '生产中': '', '待发货': 'warning', '已完成': 'success' }
|
||||
return map[status] || ''
|
||||
}
|
||||
|
||||
const loadData = async () => {
|
||||
loading.value = true
|
||||
setTimeout(() => {
|
||||
let list = [...mockData]
|
||||
if (searchForm.orderCode) list = list.filter(r => r.orderCode.includes(searchForm.orderCode))
|
||||
if (searchForm.customerName) list = list.filter(r => r.customerName.includes(searchForm.customerName))
|
||||
if (searchForm.materialName) list = list.filter(r => r.materialName.includes(searchForm.materialName))
|
||||
tableData.value = list
|
||||
pagination.total = list.length
|
||||
loading.value = false
|
||||
}, 300)
|
||||
}
|
||||
|
||||
const handleSearch = () => { pagination.page = 1; loadData() }
|
||||
const handleReset = () => { searchForm.orderCode = ''; searchForm.customerName = ''; searchForm.materialName = ''; handleSearch() }
|
||||
const handleExport = () => ElMessage.info('导出功能开发中')
|
||||
const handlePrint = () => ElMessage.info('打印功能开发中')
|
||||
|
||||
onMounted(() => loadData())
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-container { padding: 4px; }
|
||||
.search-card { margin-bottom: 16px; }
|
||||
.search-card :deep(.el-card__body) { padding-bottom: 0; }
|
||||
.toolbar { margin-bottom: 16px; display: flex; gap: 8px; }
|
||||
.pagination-wrapper { margin-top: 16px; display: flex; justify-content: flex-end; }
|
||||
</style>
|
||||
149
erp-frontend-vue/src/views/Sales/Reports/SevenDayReport.vue
Normal file
149
erp-frontend-vue/src/views/Sales/Reports/SevenDayReport.vue
Normal file
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<el-card class="search-card" shadow="never">
|
||||
<el-form :model="searchForm" inline>
|
||||
<el-form-item label="订单编号">
|
||||
<el-input v-model="searchForm.orderCode" placeholder="请输入订单编号" clearable style="width: 180px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="客户名称">
|
||||
<el-input v-model="searchForm.customerName" placeholder="请输入客户名称" clearable style="width: 180px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="交货日期">
|
||||
<el-date-picker
|
||||
v-model="searchForm.dateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>查询
|
||||
</el-button>
|
||||
<el-button @click="handleReset">
|
||||
<el-icon><Refresh /></el-icon>重置
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card class="table-card" shadow="never">
|
||||
<div class="toolbar">
|
||||
<el-button type="success" @click="handleExport">
|
||||
<el-icon><Download /></el-icon>导出
|
||||
</el-button>
|
||||
<el-button @click="handlePrint">
|
||||
<el-icon><Printer /></el-icon>打印
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="loading" :data="tableData" stripe border>
|
||||
<el-table-column type="index" label="序号" width="60" />
|
||||
<el-table-column prop="orderCode" label="订单编号" width="150" />
|
||||
<el-table-column prop="customerName" label="客户名称" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="materialCode" label="物料编号" width="120" />
|
||||
<el-table-column prop="materialName" label="物料名称" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="spec" label="规格型号" width="150" />
|
||||
<el-table-column prop="unit" label="单位" width="80" />
|
||||
<el-table-column prop="orderQty" label="订单数量" width="100" align="right" />
|
||||
<el-table-column prop="deliveredQty" label="已发货" width="100" align="right" />
|
||||
<el-table-column prop="remainQty" label="待发货" width="100" align="right" />
|
||||
<el-table-column prop="deliveryDate" label="交货日期" width="120" />
|
||||
<el-table-column prop="daysRemain" label="剩余天数" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getDaysType(row.daysRemain)">{{ row.daysRemain }}天</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getStatusType(row.status)">{{ row.status }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
v-model:current-page="pagination.page"
|
||||
v-model:page-size="pagination.pageSize"
|
||||
:page-sizes="[20, 50, 100]"
|
||||
:total="pagination.total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="loadData"
|
||||
@current-change="loadData"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Search, Refresh, Download, Printer } from '@element-plus/icons-vue'
|
||||
|
||||
interface SevenDayRow {
|
||||
orderCode: string
|
||||
customerName: string
|
||||
materialCode: string
|
||||
materialName: string
|
||||
spec: string
|
||||
unit: string
|
||||
orderQty: number
|
||||
deliveredQty: number
|
||||
remainQty: number
|
||||
deliveryDate: string
|
||||
daysRemain: number
|
||||
status: string
|
||||
}
|
||||
|
||||
const searchForm = reactive({ orderCode: '', customerName: '', dateRange: [] as string[] })
|
||||
const pagination = reactive({ page: 1, pageSize: 20, total: 0 })
|
||||
const loading = ref(false)
|
||||
const tableData = ref<SevenDayRow[]>([])
|
||||
|
||||
const mockData: SevenDayRow[] = [
|
||||
{ orderCode: 'SO2024010001', customerName: '深圳市ABC科技有限公司', materialCode: 'M001', materialName: '电子元器件A', spec: '10*10*5mm', unit: '个', orderQty: 100, deliveredQty: 50, remainQty: 50, deliveryDate: '2024-01-25', daysRemain: 2, status: '紧急' },
|
||||
{ orderCode: 'SO2024010001', customerName: '深圳市ABC科技有限公司', materialCode: 'M002', materialName: '电子元器件B', spec: '20*15*8mm', unit: '个', orderQty: 200, deliveredQty: 150, remainQty: 50, deliveryDate: '2024-01-25', daysRemain: 2, status: '紧急' },
|
||||
{ orderCode: 'SO2024010002', customerName: '广州市XYZ贸易有限公司', materialCode: 'M003', materialName: '机械零件C', spec: 'Φ50*100mm', unit: '件', orderQty: 50, deliveredQty: 0, remainQty: 50, deliveryDate: '2024-02-01', daysRemain: 7, status: '正常' }
|
||||
]
|
||||
|
||||
const getDaysType = (days: number) => {
|
||||
if (days <= 1) return 'danger'
|
||||
if (days <= 3) return 'warning'
|
||||
return 'success'
|
||||
}
|
||||
|
||||
const getStatusType = (status: string) => {
|
||||
const map: Record<string, string> = { '紧急': 'danger', '正常': 'success', '已完成': 'info' }
|
||||
return map[status] || ''
|
||||
}
|
||||
|
||||
const loadData = async () => {
|
||||
loading.value = true
|
||||
setTimeout(() => {
|
||||
let list = [...mockData]
|
||||
if (searchForm.orderCode) list = list.filter(r => r.orderCode.includes(searchForm.orderCode))
|
||||
if (searchForm.customerName) list = list.filter(r => r.customerName.includes(searchForm.customerName))
|
||||
tableData.value = list
|
||||
pagination.total = list.length
|
||||
loading.value = false
|
||||
}, 300)
|
||||
}
|
||||
|
||||
const handleSearch = () => { pagination.page = 1; loadData() }
|
||||
const handleReset = () => { searchForm.orderCode = ''; searchForm.customerName = ''; searchForm.dateRange = []; handleSearch() }
|
||||
const handleExport = () => ElMessage.info('导出功能开发中')
|
||||
const handlePrint = () => ElMessage.info('打印功能开发中')
|
||||
|
||||
onMounted(() => loadData())
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-container { padding: 4px; }
|
||||
.search-card { margin-bottom: 16px; }
|
||||
.search-card :deep(.el-card__body) { padding-bottom: 0; }
|
||||
.toolbar { margin-bottom: 16px; display: flex; gap: 8px; }
|
||||
.pagination-wrapper { margin-top: 16px; display: flex; justify-content: flex-end; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user