``1123 5
This commit is contained in:
parent
8505056616
commit
eea371a159
44
src/api/system/cost.js
Normal file
44
src/api/system/cost.js
Normal file
@ -0,0 +1,44 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询零件成本列表
|
||||
export function listCost(query) {
|
||||
return request({
|
||||
url: '/system/cost/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询零件成本详细
|
||||
export function getCost(id) {
|
||||
return request({
|
||||
url: '/system/cost/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增零件成本
|
||||
export function addCost(data) {
|
||||
return request({
|
||||
url: '/system/cost',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改零件成本
|
||||
export function updateCost(data) {
|
||||
return request({
|
||||
url: '/system/cost',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除零件成本
|
||||
export function delCost(id) {
|
||||
return request({
|
||||
url: '/system/cost/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
393
src/views/system/cost/index.vue
Normal file
393
src/views/system/cost/index.vue
Normal file
@ -0,0 +1,393 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<h3 class="page-title"><i class="el-icon-coin"></i> 零件成本查询</h3>
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="物料编码" prop="materialCode">
|
||||
<el-input
|
||||
v-model="queryParams.materialCode"
|
||||
placeholder="请输入物料编码"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="物料名称" prop="materialName">
|
||||
<el-input
|
||||
v-model="queryParams.materialName"
|
||||
placeholder="请输入物料名称"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="成本价" prop="costPrice">
|
||||
<el-input
|
||||
v-model="queryParams.costPrice"
|
||||
placeholder="请输入成本价"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建日期" prop="createDate">
|
||||
<el-date-picker clearable
|
||||
v-model="queryParams.createDate"
|
||||
type="date"
|
||||
value-format="yyyy-MM-dd"
|
||||
placeholder="请选择创建日期">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="车间" prop="workshop">
|
||||
<el-input
|
||||
v-model="queryParams.workshop"
|
||||
placeholder="请输入车间"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="单位" prop="unit">
|
||||
<el-input
|
||||
v-model="queryParams.unit"
|
||||
placeholder="请输入单位"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="仓库" prop="warehouse">
|
||||
<el-input
|
||||
v-model="queryParams.warehouse"
|
||||
placeholder="请输入仓库"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 物料多选 + 系数 + 生成报价单 -->
|
||||
<el-card class="quote-card" shadow="never">
|
||||
<div class="quote-row">
|
||||
<div class="quote-field">
|
||||
<label class="quote-label">物料搜索</label>
|
||||
<!-- 搜索模式切换:按编码/按名称 -->
|
||||
<el-radio-group v-model="searchMode" size="mini">
|
||||
<el-radio-button label="code">按编码</el-radio-button>
|
||||
<el-radio-button label="name">按名称</el-radio-button>
|
||||
</el-radio-group>
|
||||
|
||||
<el-select v-model="selectedMaterials" multiple filterable remote reserve-keyword :placeholder="searchMode === 'code' ? '按编码搜索' : '按名称搜索'"
|
||||
:remote-method="remoteSearchMaterial" :loading="materialLoading" value-key="materialCode" style="min-width: 420px;">
|
||||
<el-option
|
||||
v-for="item in materialOptions"
|
||||
:key="item.materialCode"
|
||||
:label="item.materialCode + ' - ' + item.materialName"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="quote-field">
|
||||
<label class="quote-label">系数</label>
|
||||
<el-input-number v-model="coefficient" :min="0" :step="0.01" controls-position="right" />
|
||||
</div>
|
||||
<div class="quote-actions">
|
||||
<el-button type="primary" size="mini" icon="el-icon-document" @click="handleGenerateQuote">生成售后报价单</el-button>
|
||||
<span class="quote-total">总计:{{ formattedTotal }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="selectedMaterials.length" class="selected-tags">
|
||||
<el-tag
|
||||
v-for="m in selectedMaterials"
|
||||
:key="m.materialCode"
|
||||
type="info"
|
||||
closable
|
||||
@close="removeSelected(m)"
|
||||
>{{ m.materialCode }} - {{ m.materialName }}</el-tag>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['system:cost:export']"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="costList"
|
||||
stripe
|
||||
border
|
||||
size="mini"
|
||||
highlight-current-row
|
||||
:header-cell-style="headerCellStyle"
|
||||
:cell-style="cellStyle"
|
||||
>
|
||||
<el-table-column label="物料编码" align="center" prop="materialCode" />
|
||||
<el-table-column label="物料名称" align="center" prop="materialName" />
|
||||
<el-table-column label="成本价" align="right" prop="costPrice" width="140">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.costPrice }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建日期" align="center" prop="createDate" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createDate, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="车间" align="center" prop="workshop" />
|
||||
<el-table-column label="单位" align="center" prop="unit" />
|
||||
<el-table-column label="仓库" align="center" prop="warehouse" />
|
||||
<el-table-column label="规格型号" align="center" prop="specificationModel" />
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 售后报价单预览/导出 -->
|
||||
<el-dialog title="售后报价单" :visible.sync="quoteDialogVisible" width="720px">
|
||||
<el-table :data="selectedMaterials" size="mini" border style="margin-bottom: 8px;">
|
||||
<el-table-column label="物料编码" prop="materialCode" align="center" />
|
||||
<el-table-column label="物料名称" prop="materialName" />
|
||||
<el-table-column label="成本价" prop="costPrice" align="right" width="140">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.costPrice }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="系数" align="center" width="100">
|
||||
<template>
|
||||
<span>{{ coefficient }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="小计" align="right" width="140">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ (toNumber(scope.row.costPrice) * toNumber(coefficient)).toString() }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="quote-summary">
|
||||
<span>合计:</span>
|
||||
<strong>{{ formattedTotal }}</strong>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="quoteDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="exportQuoteCSV">导出CSV</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listCost } from "@/api/system/cost";
|
||||
|
||||
export default {
|
||||
name: "Cost",
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 零件成本表格数据
|
||||
costList: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
materialCode: undefined,
|
||||
materialName: undefined,
|
||||
costPrice: undefined,
|
||||
createDate: undefined,
|
||||
workshop: undefined,
|
||||
unit: undefined,
|
||||
warehouse: undefined,
|
||||
specificationModel: undefined
|
||||
},
|
||||
// 物料选择
|
||||
selectedMaterials: [],
|
||||
materialOptions: [],
|
||||
materialLoading: false,
|
||||
// 搜索模式:code 按编码,name 按名称
|
||||
searchMode: 'code',
|
||||
// 系数
|
||||
coefficient: 1,
|
||||
// 报价单对话框
|
||||
quoteDialogVisible: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
selectedTotal() {
|
||||
const sum = this.selectedMaterials.reduce((acc, cur) => acc + this.toNumber(cur.costPrice), 0);
|
||||
return sum * this.toNumber(this.coefficient);
|
||||
},
|
||||
formattedTotal() {
|
||||
return this.selectedTotal.toString();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询零件成本列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listCost(this.queryParams).then(response => {
|
||||
this.costList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('system/cost/export', {
|
||||
...this.queryParams
|
||||
}, `cost_${new Date().getTime()}.xlsx`)
|
||||
},
|
||||
headerCellStyle() {
|
||||
return { background: '#f7f8fa', color: '#606266', fontWeight: 600 };
|
||||
},
|
||||
cellStyle({ column }) {
|
||||
if (column && column.property === 'costPrice') {
|
||||
return { textAlign: 'right' };
|
||||
}
|
||||
return {};
|
||||
},
|
||||
// --- 物料搜索与选择 ---
|
||||
remoteSearchMaterial(query) {
|
||||
if (!query) {
|
||||
this.materialOptions = [];
|
||||
return;
|
||||
}
|
||||
this.materialLoading = true;
|
||||
// 根据搜索模式仅传一个字段:materialCode 或 materialName
|
||||
const params = { pageNum: 1, pageSize: 20 };
|
||||
if (this.searchMode === 'code') {
|
||||
params.materialCode = query;
|
||||
} else {
|
||||
params.materialName = query;
|
||||
}
|
||||
listCost(params).then(res => {
|
||||
this.materialOptions = res.rows || [];
|
||||
}).finally(() => {
|
||||
this.materialLoading = false;
|
||||
})
|
||||
},
|
||||
removeSelected(item) {
|
||||
this.selectedMaterials = this.selectedMaterials.filter(m => m.materialCode !== item.materialCode);
|
||||
},
|
||||
toNumber(v) {
|
||||
const n = Number(v);
|
||||
return isNaN(n) ? 0 : n;
|
||||
},
|
||||
// --- 生成售后报价单 ---
|
||||
handleGenerateQuote() {
|
||||
if (!this.selectedMaterials.length) {
|
||||
this.$message.warning('请先选择至少一个物料');
|
||||
return;
|
||||
}
|
||||
if (this.toNumber(this.coefficient) < 0) {
|
||||
this.$message.warning('系数不能为负数');
|
||||
return;
|
||||
}
|
||||
this.quoteDialogVisible = true;
|
||||
},
|
||||
exportQuoteCSV() {
|
||||
const rows = [];
|
||||
rows.push(['物料编码', '物料名称', '成本价', '系数', '小计']);
|
||||
this.selectedMaterials.forEach(m => {
|
||||
const subtotal = this.toNumber(m.costPrice) * this.toNumber(this.coefficient);
|
||||
rows.push([m.materialCode, m.materialName, m.costPrice, this.coefficient, subtotal]);
|
||||
});
|
||||
rows.push(['总计', '', '', this.coefficient, this.selectedTotal]);
|
||||
const csv = rows.map(r => r.map(v => '"' + String(v).replace(/"/g, '""') + '"').join(',')).join('\r\n');
|
||||
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
|
||||
const link = document.createElement('a');
|
||||
link.href = URL.createObjectURL(blob);
|
||||
link.download = `售后报价单_${new Date().toISOString().slice(0,19).replace(/[:T]/g,'-')}.csv`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
this.$message.success('CSV 已导出');
|
||||
this.quoteDialogVisible = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-title {
|
||||
margin: 0 0 12px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.page-title .el-icon-coin {
|
||||
margin-right: 8px;
|
||||
color: #409EFF;
|
||||
}
|
||||
.mb8 {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.el-table .cell {
|
||||
padding: 6px 8px;
|
||||
}
|
||||
.quote-card {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.quote-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.quote-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.quote-label {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
.quote-actions {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.quote-total {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
.selected-tags {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.selected-tags .el-tag {
|
||||
margin-right: 6px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue
Block a user