更新销售合同/提成/业绩、精工工序工价/生产审核/工时统计、仓储盘点/库存/补货/入库/库房管理,新增提成设置/销售业绩/库房管理/入库单移动端等模块及SQL脚本

This commit is contained in:
Developer
2026-08-05 08:13:08 +08:00
parent 33549c3787
commit fd84f9d3ca
94 changed files with 14531 additions and 345 deletions

View File

@@ -0,0 +1,713 @@
<template>
<!-- 修改人:Ld 修改时间:2026-07-29 15:27:40; 新增采购入库单移动端独立页面,原采购合同查询组件不改动 -->
<div class="app-container purchase-inbound-mobile">
<el-card class="inbound-shell">
<div class="page-header">
<div>
<div class="page-title">生成入库单</div>
<div class="page-subtitle">{{ arrivalContractLabel || '请选择供应商和合同号' }}</div>
</div>
<el-tag :type="hasArrivalData ? 'warning' : 'info'" size="small">
{{ hasArrivalData ? '待提交' : '待选择' }}
</el-tag>
</div>
<div class="query-panel">
<el-select
v-model="arrivalSupplierName"
class="query-control"
filterable
clearable
placeholder="请选择供应商"
size="small"
@change="getArrivalContract">
<el-option
v-for="item in suppliers"
:key="item.value"
:label="item.label"
:value="item.value"/>
</el-select>
<el-select
v-model="arrivalContractNo"
class="query-control"
filterable
clearable
placeholder="请选择合同号"
size="small"
@change="onArrivalContractChange">
<el-option
v-for="item in arrivalContract"
:key="item.value"
:label="item.label"
:value="item.value"/>
</el-select>
<el-button
class="query-button"
icon="el-icon-search"
type="primary"
plain
size="small"
@click="searchArrivalDetail">
查询
</el-button>
</div>
<div class="summary-grid">
<div class="summary-item summary-blue">
<span>入库单号</span>
<strong>{{ 入库单号 || '-' }}</strong>
</div>
<div class="summary-item summary-green">
<span>本次到货</span>
<strong>{{ arrivalCount }}</strong>
</div>
<div class="summary-item summary-orange">
<span>需质检</span>
<strong>{{ qualityCheckCount }}</strong>
</div>
<div class="summary-item summary-cyan">
<span>直入库</span>
<strong>{{ noQualityCheckCount }}</strong>
</div>
</div>
<div v-loading="loading" class="detail-area">
<el-empty v-if="arrivalTableData.length === 0" description="暂无合同明细"/>
<div v-else class="detail-list">
<div v-for="(item, index) in arrivalTableData" :key="getRowKey(item, index)" class="material-card">
<div class="material-main">
<div class="material-title">{{ item.物料名称 || item.采购件 || '-' }}</div>
<el-tag :type="item.需要质检 ? 'warning' : 'success'" size="mini">
{{ item.需要质检 ? '质检部' : '仓库' }}
</el-tag>
</div>
<div class="material-meta">
<span>合同:{{ item.采购合同编号 || arrivalContractLabel || '-' }}</span>
<span>图号:{{ item.图号或型号 || item.图号 || '-' }}</span>
</div>
<div class="quantity-row">
<div>
<span>采购数</span>
<strong>{{ item.采购数 || 0 }}</strong>
</div>
<div>
<span>已到数</span>
<strong>{{ item.已到数 || 0 }}</strong>
</div>
<div>
<span>可到数</span>
<strong>{{ getCanArrivalCount(item) }}</strong>
</div>
</div>
<div class="card-actions">
<div class="arrival-input">
<span>本次到货数量</span>
<el-input-number
v-model="item.到货数量"
:max="getCanArrivalCount(item)"
:min="0"
size="small"
controls-position="right"
@change="onArrivalCountChange(item)"/>
</div>
<div class="quality-switch">
<span>需要质检</span>
<el-switch
v-model="item.需要质检"
:disabled="Number(item.到货数量) === 0"
active-text="是"
inactive-text="否"/>
</div>
</div>
</div>
</div>
</div>
</el-card>
<div class="bottom-submit">
<el-button size="small" @click="clearArrivalCount">清空数量</el-button>
<el-button :disabled="!hasArrivalData" type="primary" size="small" @click="submitArrivalNotice">提交入库单</el-button>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'PurchaseInboundCreateMobile',
data() {
return {
loading: false,
suppliers: [],
arrivalSupplierName: '',
arrivalContractNo: '',
arrivalContract: [],
arrivalContractLabel: '',
arrivalNoticeLabel: '',
arrivalTableData: [],
入库单号: ''
}
},
computed: {
...mapGetters([
'id',
'token'
]),
hasArrivalData() {
return this.arrivalTableData.some(function(item) {
return Number(item.到货数量) > 0
})
},
arrivalCount() {
return this.arrivalTableData.filter(function(item) {
return Number(item.到货数量) > 0
}).length
},
qualityCheckCount() {
return this.arrivalTableData.filter(function(item) {
return Number(item.到货数量) > 0 && item.需要质检
}).length
},
noQualityCheckCount() {
return this.arrivalTableData.filter(function(item) {
return Number(item.到货数量) > 0 && !item.需要质检
}).length
}
},
created() {
this.getSuppliers()
},
mounted() {
// 修改人:Ld 修改时间:2026-07-30 13:41:07; 参考车间派工移动端页面,进入本页时覆盖全局固定最小宽度。
document.body.classList.add('purchase-inbound-mobile-page')
},
beforeDestroy() {
document.body.classList.remove('purchase-inbound-mobile-page')
},
methods: {
// 修改人:Ld 修改时间:2026-07-29 15:27:40; 移动端页面独立加载可入库供应商
getSuppliers() {
var param = []
var Data = this.CreateData('11', '供应商_入库查询', param)
this.ExecDatabase(Data).then(response => {
this.suppliers = response.data.map(function(item) {
return {
label: item.供应商名称,
value: item.供应商流水号
}
})
})
},
// 修改人:Ld 修改时间:2026-07-29 15:27:40; 供应商变化后联动查询可生成入库单的采购合同
getArrivalContract() {
this.arrivalContract = []
this.arrivalContractNo = ''
this.arrivalContractLabel = ''
this.arrivalNoticeLabel = ''
this.arrivalTableData = []
this.入库单号 = ''
if (!this.arrivalSupplierName) {
return
}
var param = []
param[0] = ['供应商流水号_check', 1]
param[1] = ['供应商流水号', this.arrivalSupplierName]
var Data = this.CreateData('11', '仓储管理_采购入库合同_查询', param)
this.ExecDatabase(Data).then(response => {
this.arrivalContract = response.data.map(function(item) {
return {
label: item.采购合同编号,
value: item.采购合同流水号
}
})
})
},
onArrivalContractChange(val) {
var selected = this.arrivalContract.find(function(item) {
return item.value === val
})
if (selected) {
this.arrivalContractLabel = selected.label
this.arrivalNoticeLabel = selected.label
this.searchArrivalDetail()
} else {
this.arrivalContractLabel = ''
this.arrivalNoticeLabel = ''
this.arrivalTableData = []
this.入库单号 = ''
}
},
// 修改人:Ld 修改时间:2026-07-29 15:27:40; 合同明细使用卡片录入,保留原提交字段
searchArrivalDetail() {
if (!this.arrivalSupplierName) {
this.$message.warning('请先选择供应商')
return
}
if (!this.arrivalContractNo) {
this.$message.warning('请先选择合同号')
return
}
this.loading = true
var param = []
param[0] = ['供应商流水号', this.arrivalSupplierName]
param[1] = ['采购合同流水号', this.arrivalContractNo]
var Data = this.CreateData('11', '采购管理_采购入库合同明细_查询', param)
this.ExecDatabase(Data).then(response => {
var data = response.data || []
this.arrivalTableData = data.map(function(item) {
return Object.assign({}, item, {
到货数量: 0,
需要质检: false
})
})
if (data.length > 0 && data[0].入库单号) {
this.入库单号 = data[0].入库单号
} else {
this.入库单号 = ''
}
if (this.arrivalTableData.length === 0) {
this.$message.info('该合同下没有物料明细')
}
}).finally(() => {
this.loading = false
})
},
onArrivalCountChange(row) {
if (Number(row.到货数量) === 0) {
row.需要质检 = false
}
},
getCanArrivalCount(row) {
var purchaseCount = Number(row.采购数 || 0)
var arrivedCount = Number(row.已到数 || 0)
var canArrivalCount = purchaseCount - arrivedCount
return canArrivalCount > 0 ? canArrivalCount : 0
},
getRowKey(row, index) {
return row.物料流水号 || row.采购合同明细流水号 || index
},
clearArrivalCount() {
this.arrivalTableData.forEach(function(item) {
item.到货数量 = 0
item.需要质检 = false
})
},
// 修改人:Ld 修改时间:2026-07-29 15:27:40; 提交接口和原采购合同查询弹窗保持一致
submitArrivalNotice() {
var arrivalData = this.arrivalTableData.filter(function(item) {
return Number(item.到货数量) > 0
})
if (arrivalData.length === 0) {
this.$message.warning('请至少填写一个物料的到货数量')
return
}
var toQualityCheck = arrivalData.filter(function(item) {
return item.需要质检 === true
})
var toWarehouse = arrivalData.filter(function(item) {
return item.需要质检 === false
})
var param = []
param[0] = ['通知内容', this.arrivalNoticeLabel]
param[1] = ['发起人', this.id]
param[2] = ['采购合同流水号', this.arrivalContractNo]
param[3] = ['到货数组', arrivalData.map(function(item) { return item.到货数量 }).join(',')]
param[4] = ['物料流水号组', arrivalData.map(function(item) { return item.物料流水号 }).join(',')]
param[5] = ['质检标志组', arrivalData.map(function(item) { return item.需要质检 ? 1 : 0 }).join(',')]
param[6] = ['采购合同', this.arrivalContractLabel]
param[7] = ['供应商流水号', this.arrivalSupplierName]
param[8] = ['入库单号', this.入库单号]
var Data = this.CreateData('12', '采购管理_到货内容_新增', param)
this.ExecDatabase(Data).then(response => {
if (response.data[0].result === '1') {
var message = '通知成功:'
if (toQualityCheck.length > 0) {
message += toQualityCheck.length + '个物料送质检部'
}
if (toWarehouse.length > 0) {
message += (toQualityCheck.length > 0 ? ',' : '') + toWarehouse.length + '个物料直接入库'
}
this.$message({
message: message,
type: 'success',
duration: 3000
})
this.searchArrivalDetail()
} else {
this.$message.error('通知失败')
}
}).catch(() => {
this.$message.error('操作失败,请重试')
})
}
}
}
</script>
<style scoped>
/* 修改人:Ld 修改时间:2026-07-29 15:27:40; 新增移动端自适应样式 */
.purchase-inbound-mobile,
.purchase-inbound-mobile * {
box-sizing: border-box;
}
.purchase-inbound-mobile {
width: 100%;
max-width: 100%;
min-height: calc(100vh - 84px);
overflow-x: hidden;
padding: 10px 12px 78px;
background: #f5f7fb;
}
.inbound-shell {
width: 100%;
max-width: 100%;
min-height: calc(100vh - 150px);
overflow: hidden;
border-radius: 6px;
}
.inbound-shell >>> .el-card__body {
width: 100%;
padding: 12px !important;
}
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.page-title {
font-size: 20px;
font-weight: 700;
color: #1f2d3d;
}
.page-subtitle {
max-width: 100%;
margin-top: 4px;
overflow: hidden;
font-size: 12px;
color: #8492a6;
text-overflow: ellipsis;
white-space: nowrap;
}
.query-panel {
display: grid;
grid-template-columns: minmax(180px, 1fr) minmax(180px, 1fr) 90px;
gap: 10px;
margin-bottom: 12px;
}
.query-control,
.query-button {
min-width: 0;
width: 100%;
}
.purchase-inbound-mobile >>> .el-select,
.purchase-inbound-mobile >>> .el-input-number,
.purchase-inbound-mobile >>> .el-input,
.purchase-inbound-mobile >>> .el-button {
max-width: 100%;
min-width: 0;
box-sizing: border-box;
}
.purchase-inbound-mobile >>> .el-select,
.purchase-inbound-mobile >>> .el-input-number,
.purchase-inbound-mobile >>> .el-input {
width: 100%;
}
.purchase-inbound-mobile >>> .el-input__inner {
min-width: 0;
}
.summary-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
margin-bottom: 12px;
}
.summary-item {
padding: 10px 12px;
border-radius: 6px;
border: 1px solid #dcdfe6;
background: #fff;
}
.summary-item span {
display: block;
margin-bottom: 6px;
font-size: 12px;
color: #606266;
}
.summary-item strong {
display: block;
min-width: 0;
overflow: hidden;
font-size: 18px;
color: #303133;
text-overflow: ellipsis;
white-space: nowrap;
}
.summary-blue {
background: #eff6ff;
border-color: #bfdbfe;
}
.summary-green {
background: #f0fdf4;
border-color: #bbf7d0;
}
.summary-orange {
background: #fff7ed;
border-color: #fed7aa;
}
.summary-cyan {
background: #ecfeff;
border-color: #a5f3fc;
}
.detail-list {
display: grid;
grid-template-columns: repeat(2, minmax(260px, 1fr));
gap: 12px;
width: 100%;
max-width: 100%;
}
.material-card {
min-width: 0;
padding: 12px;
border: 1px solid #dcdfe6;
border-radius: 6px;
background: #fff;
}
.material-main,
.card-actions {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.material-title {
min-width: 0;
overflow: hidden;
color: #303133;
font-size: 15px;
font-weight: 700;
text-overflow: ellipsis;
white-space: nowrap;
}
.material-meta {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
margin-top: 8px;
color: #606266;
font-size: 12px;
}
.material-meta span {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.quantity-row {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
margin-top: 10px;
}
.quantity-row div {
padding: 8px;
border-radius: 4px;
background: #f5f7fa;
}
.quantity-row span,
.arrival-input span,
.quality-switch span {
display: block;
margin-bottom: 4px;
color: #909399;
font-size: 12px;
}
.quantity-row strong {
color: #303133;
font-size: 16px;
}
.card-actions {
align-items: flex-end;
margin-top: 10px;
}
.arrival-input {
flex: 1;
}
.arrival-input >>> .el-input-number {
width: 150px;
}
.quality-switch {
min-width: 142px;
}
.bottom-submit {
position: fixed;
right: 20px;
bottom: 16px;
left: 200px;
z-index: 10;
display: flex;
justify-content: flex-end;
gap: 10px;
padding: 10px 16px;
border: 1px solid #dcdfe6;
border-radius: 6px;
background: #fff;
box-shadow: 0 4px 14px rgba(15, 23, 42, .12);
}
/* 修改人:Ld 修改时间:2026-07-30 11:27:07; 中等宽度下提前切换单列,避免 769px 以上仍被双列卡片撑宽 */
@media (max-width: 1100px) {
.query-panel {
grid-template-columns: 1fr 1fr;
}
.query-button {
grid-column: 1 / -1;
}
.detail-list {
grid-template-columns: 1fr;
}
.bottom-submit {
left: 20px;
}
}
@media (max-width: 768px) {
.purchase-inbound-mobile {
width: 100vw;
margin: 0;
padding: 8px 8px 76px;
}
.inbound-shell >>> .el-card__body {
padding: 10px !important;
}
.query-panel,
.summary-grid,
.detail-list,
.material-meta {
grid-template-columns: 1fr;
}
.summary-grid {
grid-template-columns: repeat(2, 1fr);
}
.page-header {
align-items: flex-start;
gap: 8px;
}
.page-header > div {
min-width: 0;
}
.material-main,
.card-actions {
align-items: stretch;
flex-direction: column;
}
.arrival-input >>> .el-input-number {
width: 100%;
}
.quality-switch {
min-width: 0;
}
.bottom-submit {
right: 8px;
bottom: 8px;
left: 8px;
width: auto;
max-width: calc(100vw - 16px);
padding: 8px;
}
.bottom-submit .el-button {
flex: 1;
min-height: 40px;
margin-left: 0;
}
}
/* 修改人:Ld 修改时间:2026-07-30 11:27:07; 小屏手机全部控件按视口宽度铺满 */
@media (max-width: 420px) {
.summary-grid,
.quantity-row {
grid-template-columns: 1fr;
}
.page-title {
font-size: 18px;
}
.material-card {
padding: 10px;
}
}
</style>
<style>
/* 修改人:Ld 修改时间:2026-07-30 13:41:07; 参考车间派工移动端组件,仅在本页面覆盖全局 main-container 固定最小宽度。 */
body.purchase-inbound-mobile-page #app .main-container,
body.purchase-inbound-mobile-page #app .app-main {
max-width: 100% !important;
min-width: 0 !important;
overflow-x: hidden !important;
}
body.purchase-inbound-mobile-page #app .app-main {
width: 100% !important;
}
body.purchase-inbound-mobile-page #app .mobile .main-container {
width: 100vw !important;
max-width: 100vw !important;
min-width: 0 !important;
margin-left: 0 !important;
}
body.purchase-inbound-mobile-page {
overflow-x: hidden;
}
</style>

View File

@@ -0,0 +1,263 @@
<template>
<div class="app-container">
<el-card style="height: 850px">
<div v-if="hasPermission">
<div style="margin-top: 7px; margin-bottom: 7px">
<!-- 修改人:Ld 修改时间:2026-07-27 12:00:00; 提成比例设置仅指定人员可维护。 -->
<el-select
v-model="commissionType"
size="small"
style="width: 210px"
clearable
filterable
placeholder="提成类型"
@change="searchTable">
<el-option v-for="item in commissionTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<el-button
icon="el-icon-search"
type="primary"
plain
size="small"
style="margin-left: 10px"
@click="searchTable">查询</el-button>
<el-button
icon="el-icon-circle-plus-outline"
type="success"
plain
size="small"
style="margin-left: 10px"
@click="addRate">新增</el-button>
</div>
<el-table
v-loading="loading"
:data="tableData"
border
stripe
size="small"
style="width: 900px; margin-top: 20px"
height="740px">
<el-table-column width="60px" label="序号" type="index" align="center" />
<el-table-column width="180px" label="提成类型" align="center" prop="提成类型" show-overflow-tooltip />
<el-table-column width="110px" label="提成比例" align="right">
<template slot-scope="scope">{{ formatPercent(scope.row.提成比例) }}</template>
</el-table-column>
<el-table-column width="90px" label="是否启用" align="center">
<template slot-scope="scope">
<el-tag :type="Number(scope.row.是否启用) === 1 ? 'success' : 'info'" size="mini">
{{ Number(scope.row.是否启用) === 1 ? '启用' : '停用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column width="220px" label="备注" align="center" prop="备注" show-overflow-tooltip />
<el-table-column width="150px" label="操作日期" align="center" prop="操作日期" />
<el-table-column width="90px" label="操作" align="center" fixed="right">
<template slot-scope="scope">
<el-tooltip :open-delay="1000" effect="dark" content="编辑" placement="top">
<el-button size="mini" type="text" class="el-icon-edit-outline" @click="editRate(scope.row)" />
</el-tooltip>
<el-tooltip :open-delay="1000" effect="dark" content="停用" placement="top">
<el-button size="mini" type="text" style="margin-left: 15px" class="el-icon-delete" @click="deleteRate(scope.row)" />
</el-tooltip>
</template>
</el-table-column>
</el-table>
<el-dialog v-el-drag-dialog :title="title" :visible.sync="dialogFormVisible" center width="520px">
<el-form ref="form" :model="form" :rules="rules" label-position="left" label-width="100px">
<el-form-item label="提成类型:" prop="提成类型">
<el-select
v-model="form.提成类型"
size="small"
style="width: 300px"
filterable
allow-create
default-first-option
placeholder="请选择提成类型">
<el-option v-for="item in commissionTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="提成比例:" prop="提成比例">
<el-input-number v-model="form.提成比例" :min="0" :precision="4" :step="0.1" size="small" style="width: 180px" />
<span style="margin-left: 8px">%</span>
</el-form-item>
<el-form-item label="是否启用:" prop="是否启用">
<el-switch v-model="form.是否启用" :active-value="1" :inactive-value="0" active-text="启用" inactive-text="停用" />
</el-form-item>
<el-form-item label="备注:" prop="备注">
<el-input v-model="form.备注" type="textarea" :rows="3" style="width: 300px" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button size="small" @click="dialogFormVisible = false">取消</el-button>
<el-button type="primary" size="small" @click="submit('form')">确定</el-button>
</div>
</el-dialog>
</div>
<el-alert
v-else
title="无权限查看提成比例设置"
type="warning"
show-icon
:closable="false" />
</el-card>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
data() {
return {
loading: false,
commissionType: '',
tableData: [],
dialogFormVisible: false,
title: '新增提成比例',
form: {
提成比例ID: '',
提成类型: '',
提成比例: 0,
是否启用: 1,
备注: ''
},
// 修改人:Ld 修改时间:2026-07-27 12:00:00; 初始化合同提成类别。
commissionTypeOptions: [
{ label: '首单提成(专机)', value: '首单提成(专机)' },
{ label: '首单提成(模块)', value: '首单提成(模块)' },
{ label: '转介绍提成(专机)', value: '转介绍提成(专机)' },
{ label: '转介绍提成(模块)', value: '转介绍提成(模块)' },
{ label: '复购提成', value: '复购提成' }
],
rules: {
提成类型: [{ required: true, message: '请选择提成类型', trigger: 'change' }],
提成比例: [{ required: true, message: '请输入提成比例', trigger: 'blur' }]
}
}
},
computed: {
...mapGetters(['id', 'userId']),
hasPermission() {
// 修改人:Ld 修改时间:2026-07-27 14:35:00; 提成比例设置改为按人员编号5和273授权。
const value = String(this.id || '').trim()
return value === '5' || value === '273'
}
},
mounted() {
if (this.hasPermission) {
this.searchTable()
} else {
this.$message.warning('无权限查看提成比例设置')
}
},
methods: {
buildQueryParam() {
var param = []
param[0] = ['提成类型_check', this.commissionType ? 1 : 0]
param[1] = ['提成类型', this.commissionType]
param[2] = ['人员编号', this.id]
return param
},
searchTable() {
if (!this.hasPermission) {
this.$message.warning('无权限查看提成比例设置')
return
}
this.loading = true
var Data = this.CreateData('11', '销售管理_提成比例设置_查询数据', this.buildQueryParam())
this.ExecDatabase(Data).then(response => {
if (response.data && response.data[0] && Number(response.data[0].result) === 0) {
this.$message.warning(response.data[0].msg || '无权限查看提成比例设置')
this.tableData = []
} else {
this.tableData = response.data || []
}
this.loading = false
}).catch(() => {
this.loading = false
this.$message.error('提成比例查询失败')
})
},
addRate() {
this.title = '新增提成比例'
this.form = {
提成比例ID: '',
提成类型: '',
提成比例: 0,
是否启用: 1,
备注: ''
}
this.dialogFormVisible = true
},
editRate(row) {
this.title = '编辑提成比例'
this.form = {
提成比例ID: row.提成比例ID,
提成类型: row.提成类型,
提成比例: Number(row.提成比例 || 0),
是否启用: Number(row.是否启用),
备注: row.备注
}
this.dialogFormVisible = true
},
submit(formName) {
this.$refs[formName].validate(valid => {
if (!valid) {
return
}
var param = []
param[0] = ['提成比例ID', this.form.提成比例ID]
param[1] = ['提成类型', this.form.提成类型]
param[2] = ['提成比例', this.form.提成比例]
param[3] = ['是否启用', this.form.是否启用]
param[4] = ['备注', this.form.备注]
param[5] = ['操作者', this.id]
param[6] = ['人员编号', this.id]
var Data = this.CreateData('12', '销售管理_提成比例设置_保存数据', param)
this.ExecDatabase(Data).then(response => {
if (response.data[0].result === '1' || Number(response.data[0].result) === 1) {
this.$message.success(response.data[0].msg || '保存成功')
this.dialogFormVisible = false
this.searchTable()
} else {
this.$message.warning(response.data[0].msg || '保存失败')
}
})
})
},
deleteRate(row) {
this.$confirm('是否停用该提成比例?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
var param = []
param[0] = ['提成比例ID', row.提成比例ID]
param[1] = ['操作者', this.id]
param[2] = ['人员编号', this.id]
var Data = this.CreateData('12', '销售管理_提成比例设置_删除数据', param)
this.ExecDatabase(Data).then(response => {
if (response.data[0].result === '1' || Number(response.data[0].result) === 1) {
this.$message.success(response.data[0].msg || '停用成功')
this.searchTable()
} else {
this.$message.warning(response.data[0].msg || '停用失败')
}
})
}).catch(() => {})
},
formatPercent(value) {
const num = Number(value || 0)
return num.toFixed(4) + '%'
}
}
}
</script>
<style scoped>
.app-container {
padding: 20px;
}
</style>

View File

@@ -188,6 +188,12 @@
{{ scope.row.合同备注 }}
</template>
</el-table-column>
<!-- 修改人:Ld 修改时间:2026-07-27 10:00:00; 合同查询提成类型列 -->
<el-table-column v-if="Number(token) === 11 || Number(token) === 2 || Number(token) === 3 || Number(token) === 9" align="center" label="提成类型" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.提成类型 }}
</template>
</el-table-column>
<el-table-column :width="setColumnWidth('日期')" align="center" label="签订日期">
<template slot-scope="scope">
{{ scope.row.签订日期 }}
@@ -1162,6 +1168,22 @@
<el-form-item label="税率" prop="税率">
<el-input v-model="form.税率" clearable size="small" style="width:200px;"/>
</el-form-item>
<!-- 修改人:Ld 修改时间:2026-07-31 08:43:08; 编辑合同信息最后一行增加提成类型修改 -->
<el-form-item label="提成类型" prop="提成类型">
<el-select
v-model="form.提成类型"
clearable
filterable
placeholder="请选择提成类型"
size="small"
style="width: 200px;margin: 10px 0 10px 2px">
<el-option
v-for="item in commissionTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"/>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button size="small" @click="callOffCustomers('form')">取消</el-button>
@@ -1223,15 +1245,25 @@ export default {
买方名称: '',
付款方式: '',
税率: '',
收货人: ''
收货人: '',
提成类型: '' // 修改人:Ld 修改时间:2026-07-31 08:43:08; 编辑合同信息提成类型
},
rules: {
交货期限: [{ required: true, message: '请输入交货期限', trigger: 'blur' }],
收货人: [{ required: true, message: '请输入收货人', trigger: 'blur' }],
税率: [{ required: true, message: '请输入税率', trigger: 'blur' }],
买方名称: [{ required: true, message: '请选择买方名称', trigger: 'change' }],
付款方式: [{ required: true, message: '请选择付款方式', trigger: 'change' }]
付款方式: [{ required: true, message: '请选择付款方式', trigger: 'change' }],
提成类型: [{ required: true, message: '请选择提成类型', trigger: 'change' }]
},
// 修改人:Ld 修改时间:2026-07-31 08:43:08; 编辑合同信息提成类型下拉选项
commissionTypeOptions: [
{ label: '首单提成(专机)', value: '首单提成(专机)' },
{ label: '首单提成(模块)', value: '首单提成(模块)' },
{ label: '转介绍提成(专机)', value: '转介绍提成(专机)' },
{ label: '转介绍提成(模块)', value: '转介绍提成(模块)' },
{ label: '复购提成', value: '复购提成' }
],
dialogVisibleQQ: false,
editCustomerNameContractNo: '',
modifyCustomerNameValue: '',
@@ -1597,7 +1629,7 @@ export default {
})
},
submitModifyCustomerNameValue(formName) {
if (this.form.买方名称 === '' || this.form.交货期限 === '' || this.form.付款方式 === '' || this.form.税率 === '' || this.form.收货人 === '') {
if (this.form.买方名称 === '' || this.form.交货期限 === '' || this.form.付款方式 === '' || this.form.税率 === '' || this.form.收货人 === '' || this.form.提成类型 === '') {
this.$message.error('信息不全!禁止修改!!')
} else {
var param = []
@@ -1607,6 +1639,8 @@ export default {
param[3] = ['交货期限', this.form.交货期限]
param[4] = ['付款方式流水号', this.form.付款方式]
param[5] = ['税率', this.form.税率]
// 修改人:Ld 修改时间:2026-07-31 08:43:08; 编辑合同信息保存提成类型
param[6] = ['提成类型', this.form.提成类型]
var Data = this.CreateData('12', 'PDM_项目名称_修改客户', param)
this.ExecDatabase(Data).then(response => {
if (response.data[0].result === '1') {
@@ -1629,6 +1663,7 @@ export default {
this.form.收货人 = ''
this.form.付款方式 = ''
this.form.税率 = ''
this.form.提成类型 = ''
this.$refs[formName].resetFields()
},
editCustomerName(row) {
@@ -1643,6 +1678,8 @@ export default {
this.form.付款方式 = Number(row.付款方式流水号)
this.form.税率 = row.税率小数
this.form.收货人 = row.收货人员
// 修改人:Ld 修改时间:2026-07-31 08:43:08; 编辑合同信息回填提成类型
this.form.提成类型 = row.提成类型 ? row.提成类型 : ''
this.dialogFormVisibleqq = true
},
companyInformationSearch() {

View File

@@ -180,6 +180,12 @@
{{ scope.row.合同备注 }}
</template>
</el-table-column>
<!-- 修改人:Ld 修改时间:2026-07-27 10:00:00; 合同查询提成类型列 -->
<el-table-column v-if="Number(token) === 11 || Number(token) === 2 || Number(token) === 3 || Number(token) === 8" align="center" label="提成类型" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.提成类型 }}
</template>
</el-table-column>
<el-table-column :width="setColumnWidth('日期')" label="签订日期" align="center">
<template slot-scope="scope">
{{ scope.row.签订日期 }}
@@ -2711,4 +2717,3 @@ a {
color: #999;
}
</style>

View File

@@ -85,9 +85,13 @@
{{ scope.row.发货备注 }}
</template>
</el-table-column>
<el-table-column width="117px" label="操作" align="center">
<el-table-column width="145px" label="操作" align="center">
<template slot-scope="scope">
<el-button type="text" icon="el-icon-top" size="mini" @click="uploadPicture(scope.row)">照片</el-button>
<!-- 修改人:Ld 修改时间:2026-08-03 13:30:22; 发货查询列表增加发货单打印入口。 -->
<el-tooltip :open-delay="500" effect="dark" content="打印发货单" placement="top">
<el-button type="text" icon="el-icon-printer" size="mini" @click="shipmentDocPrintQuery(scope.row)"/>
</el-tooltip>
<el-button v-show="Number(token)===8 || Number(token)===2" :disabled="scope.row.发货状态==='已发货'" size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"/>
<el-button type="text" icon="el-icon-edit" size="mini" @click="handleEdit(scope.row)"/>
<el-button size="mini" type="text" icon="el-icon-picture-outline" @click="handlePicture(scope.row)"/>
@@ -151,6 +155,79 @@
</el-table>
</el-col>
</el-card>
<!-- 修改人:Ld 修改时间:2026-08-03 13:30:22; 复用产品发货组件销售出库单模板作为发货查询打印内容。 -->
<el-card v-show="false" style="height: 850px">
<div style="width:900px;margin-left: 350px">
<el-card>
<div id="WGBLD" style="width: 880px;margin: 0 auto">
<div style="height: 65px;width: 660px;margin: 0 auto 10px">
<img src="@/assets/img/CompanyIcon.png" style="float: left; width: 160px;height: 60px;">
<img
src="@/assets/img/CompanyQRCode.jpg"
style="float: right; margin-right: 20px;width: 70px;height: 70px;">
<span
style="font-size: 19px">浙&nbsp;&nbsp;江&nbsp;&nbsp;景&nbsp;&nbsp;耀&nbsp;&nbsp;数&nbsp;&nbsp;控&nbsp;&nbsp;科&nbsp;&nbsp;技&nbsp;&nbsp;有&nbsp;&nbsp;限&nbsp;&nbsp;公&nbsp;&nbsp;司<br><span
style="font-size: 12px;">ZHEJIANG JING YAO NUMERICAL CONTROL TECHNOLOGY CO. LTD</span></span>
</div>
<div style="text-align: center;margin-bottom: 10px">
<span style="font-size: 14px">销售出库单</span>
</div>
<div style="margin-bottom: 10px">
<el-col :span="9">
<span style="float: left; margin-left: 20px;margin-top: 5px;font-size: 11px">收货单位:{{
customer
}}</span>
</el-col>
<el-col :span="7">
<span style="font-size: 11px;margin-left: 70px;">销售方式:现销</span>
</el-col>
<el-col :span="8">
<span style="float: right; font-size: 11px;margin-top: 5px;">编号:{{ number }}</span>
</el-col>
</div>
<div style="margin-bottom: 10px">
<span style="float: left;margin-left: 20px;font-size: 11px;">摘要:{{ remarks }}</span>
<span style="float: right;margin-right: 37px;font-size: 11px">日期:{{ date }}</span>
</div>
<table align="center" border="1 solid black" cellspacing="0px" style="font-size: 11px" width="100%">
<tr id="tablehead12" style="height: 35px">
<td colspan="1" style="text-align: center;width: 5%">序号</td>
<td colspan="4" style="text-align: center;width: 20%">产品名称</td>
<td colspan="5" style="text-align: center;width: 25%">辅助规格</td>
<td colspan="1" style="text-align: center;width: 5%">单位</td>
<td colspan="1" style="text-align: center;width: 5%">数量</td>
<td colspan="4" style="text-align: center;width: 20%">备注</td>
</tr>
<tr v-for="(list, index) in returns" :key="index" style="height: 35px">
<td colspan="1" style="text-align: center;width: 5%">{{ list.序号 }}</td>
<td colspan="4" style="text-align: center;width: 20%">{{ list.产品名称 }}</td>
<td colspan="5" style="text-align: center;width: 25%">{{ list.辅助规格 }}</td>
<td colspan="1" style="text-align: center;width: 5%">{{ list.单位 }}</td>
<td colspan="1" style="text-align: center;width: 5%">{{ list.数量 }}</td>
<td colspan="4" style="text-align: center;width: 20%">{{ list.备注 }}</td>
</tr>
<tr style="height: 35px">
<td colspan="1" style="text-align: center;width: 5%;font-size: 11px">合计</td>
<td colspan="19" style="text-align: center;width: 95%">
<div>
<span style="float: right;margin-right: 29.5%;font-size: 11px">{{ totalCount }}</span>
</div>
</td>
</tr>
</table>
<div style="margin-top: 10px;font-size: 11px">
注:以上货品请核对数量,如有质量问题,请在收货后3天内通知本公司,逾期恕不负责。
</div>
<div style="margin-top: 15px;font-size: 11px"><span style="font-size: 11px">审核:</span><span
style="margin-left: 80px;font-size: 11px">业务员:</span><span
style="margin-left: 80px;font-size: 11px">发货:</span><span
style="margin-left: 80px;font-size: 11px">保管:</span><span
style="margin-left: 80px;font-size: 11px">制单:</span><span
style="margin-left: 80px;font-size: 11px">收货:</span></div>
</div>
</el-card>
</div>
</el-card>
<el-dialog v-el-drag-dialog :visible.sync="dialogFormVisible" title="图片" center style="" width="600px">
<el-image v-for="url in urls" :key="url" :src="url" :preview-src-list="urls" lazy style="width: 500px; height: 500px"/>
</el-dialog>
@@ -198,10 +275,21 @@
import { mapGetters } from 'vuex'
import { url, MESUploadFileNew, MESDownloadFileNew, MESUploadFileNew_BasePath } from '@/utils/request'
import axios from 'axios'
// 修改人:Ld 修改时间:2026-08-03 13:30:22; 打印时复用产品发货组件的DOM打印方式。
import $ from 'jquery'
export default {
data() {
return {
Data: {},
// 修改人:Ld 修改时间:2026-08-03 13:30:22; 发货单打印模板绑定数据。
totalAmount: '',
totalCount: '',
totalAmountText: '',
customer: '',
number: '',
remarks: '',
date: '',
returns: [],
limit: 1000,
upload: url,
uploadSaving: false,
@@ -263,6 +351,62 @@ export default {
this.searchTable()
},
methods: {
exportTable() {
// 修改人:Ld 修改时间:2026-08-03 13:30:22; 仅将隐藏的发货单模板插入页面执行打印。
const htmlNode = $('#WGBLD').html()
const body = $('body')
body.children().hide()
const printNode = $(htmlNode)
body.append(printNode)
window.print()
body.children().not('script').show()
body.children().not('#app').hide()
printNode.remove()
},
shipmentDocPrintQuery(row) {
// 修改人:Ld 修改时间:2026-08-03 13:30:22; 按当前发货查询行获取打印明细并填充销售出库单模板。
this.returns = []
this.totalAmount = ''
this.totalAmountText = ''
this.totalCount = 0
this.customer = row.客户名称 || row.买方名称 || ''
this.number = row.订单号 || row.发货单号 || ''
this.remarks = row.发货备注 || ''
this.date = row.发货日期 || ''
var param = []
param[0] = ['发货单流水号', row.发货单流水号]
var Data = this.CreateData('11', '产品发货_发货单明细_打印发货单_查询数据', param)
this.ExecDatabase(Data).then(response => {
if (!response.data || response.data.length === 0) {
this.$message.warning('未查询到打印明细')
return
}
this.totalAmountText = response.data[0].总金额文本
this.totalAmount = response.data[0].总金额
this.customer = this.customer || response.data[0].买方名称 || ''
this.number = response.data[0].订单号 || this.number
for (let i = 0; i < response.data.length; i++) {
var currentRow = this.tableData1.find(item => item.发货单明细流水号 === response.data[i].发货单明细流水号)
var printNum = currentRow && currentRow.查询实际发量 !== '' && currentRow.查询实际发量 !== null && currentRow.查询实际发量 !== undefined ? currentRow.查询实际发量 : response.data[i].实际发量
this.returns.push({
序号: i + 1,
产品名称: response.data[i].产品名称,
单位: response.data[i].单位,
销售单价: response.data[i].单价,
辅助规格: response.data[i].产品详情,
数量: printNum,
备注: response.data[i].备注
})
this.totalCount += Number(printNum)
}
// 修改人:Ld 修改时间:2026-08-03 13:55:07; 等待隐藏打印模板完成明细渲染后再触发打印,避免打印空内容。
this.$nextTick(() => {
setTimeout(() => {
this.exportTable()
}, 100)
})
})
},
review(row) {
this.$confirm('是否通知审核?', '提示', {
confirmButtonText: '确定',

View File

@@ -152,6 +152,26 @@
</el-tooltip>
</el-col>
</el-row>
<el-row style="width: 1192px;margin-left: 160px">
<el-col :span="24">
<!-- 修改人:Ld 修改时间:2026-07-28 09:30:00; 老专机合同头部增加提成类型选择 -->
<span>&nbsp;提成类型:</span>
<el-select
v-model="commissionType"
clearable
filterable
placeholder="请选择提成类型"
size="small"
style="width:200px;margin: 10px 0 10px 3px"
@change="editContract">
<el-option
v-for="item in commissionTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"/>
</el-select>
</el-col>
</el-row>
<div style="margin-left: 160px">
<el-table
v-loading="loading"
@@ -1038,6 +1058,14 @@ export default {
},
people: [],
province: [],
// 修改人:Ld 修改时间:2026-07-28 09:30:00; 老专机合同提成类型下拉选项
commissionTypeOptions: [
{ label: '复购提成', value: '复购提成' },
{ label: '首单提成(专机)', value: '首单提成(专机)' },
{ label: '首单提成(模块)', value: '首单提成(模块)' },
{ label: '转介绍提成(专机)', value: '转介绍提成(专机)' },
{ label: '转介绍提成(模块)', value: '转介绍提成(模块)' }
],
rules: {
省份: [{ required: true, message: '请选择省份' }],
客户名称: [{ required: true, message: '请输入客户名称' }],
@@ -1068,6 +1096,7 @@ export default {
paymentMethodValue: '', // 付款方式值
customerRequirements: '', // 客户要求
contractRemarks: '', // 合同备注
commissionType: '', // 修改人:Ld 修改时间:2026-07-28 09:30:00; 提成类型
consignee: '',
productName: '',
MachineToolNumber: '',
@@ -1438,6 +1467,7 @@ export default {
this.deliveryDate = ''
this.customerRequirements = ''
this.contractRemarks = ''
this.commissionType = ''
this.MachineToolNumber = ''
var param1 = []
var Data1 = this.CreateData('11', 'PDM_项目名称_专机_查询数据', param1)
@@ -1742,6 +1772,8 @@ export default {
this.contractRemarks = response.data[0].合同备注
this.MachineToolNumber = response.data[0].机床流水号
this.contractMumber = response.data[0].合同编号
// 修改人:Ld 修改时间:2026-07-28 09:30:00; 选择老专机合同时回填提成类型
this.commissionType = response.data[0].提成类型 ? response.data[0].提成类型 : ''
this.searchMachine()
this.searchProduct()
})
@@ -1753,6 +1785,7 @@ export default {
this.deliveryDate = ''
this.customerRequirements = ''
this.contractRemarks = ''
this.commissionType = ''
this.MachineToolNumber = ''
this.contractMumber = ''
this.consignee = ''
@@ -1818,6 +1851,7 @@ export default {
this.deliveryDate = ''
this.customerRequirements = ''
this.contractRemarks = ''
this.commissionType = ''
this.MachineToolNumber = ''
var param1 = []
var Data1 = this.CreateData('11', 'PDM_项目名称_专机_查询数据', param1)
@@ -1861,8 +1895,10 @@ export default {
param[5] = ['交货期限', this.deliveryDate]
param[6] = ['客户要求', this.customerRequirements]
param[7] = ['合同备注', this.contractRemarks]
param[8] = ['操作者', this.id]
param[9] = ['收货人', this.consignee]
// 修改人:Ld 修改时间:2026-07-28 09:30:00; 老专机合同编辑保存提成类型
param[8] = ['提成类型', this.commissionType]
param[9] = ['操作者', this.id]
param[10] = ['收货人', this.consignee]
var Data = this.CreateData('12', 'PDM_项目名称_编辑数据', param)
this.ExecDatabase(Data).then(response => {
if (response.data[0].result === '0') {
@@ -1883,8 +1919,10 @@ export default {
param[5] = ['交货期限', this.deliveryDate]
param[6] = ['客户要求', this.customerRequirements]
param[7] = ['合同备注', this.contractRemarks]
param[8] = ['操作者', this.id]
param[9] = ['收货人', this.consignee]
// 修改人:Ld 修改时间:2026-07-28 09:30:00; 老专机合同编辑保存提成类型
param[8] = ['提成类型', this.commissionType]
param[9] = ['操作者', this.id]
param[10] = ['收货人', this.consignee]
console.log(this.consignee, 456)
var Data = this.CreateData('12', 'PDM_项目名称_编辑数据', param)
this.ExecDatabase(Data).then(response => {
@@ -2362,6 +2400,11 @@ export default {
},
submitContract() {
if (this.contractNoValue) {
// 修改人:Ld 修改时间:2026-07-28 09:30:00; 老专机合同提交前必须选择提成类型
if (!this.commissionType) {
this.$message.warning('请选择提成类型')
return
}
if (this.customerNameValue && this.paymentMethodValue && this.taxRate && this.tableData.length !== 0 && this.tableData1.length !== 0 && this.deliveryDate && this.signingDate) {
for (let i = 0; i < this.tableData1.length; i++) {
if (this.tableData1[i].产品名称 === null || this.tableData1[i].产品名称 === '') {
@@ -2417,6 +2460,7 @@ export default {
this.deliveryDate = ''
this.customerRequirements = ''
this.contractRemarks = ''
this.commissionType = ''
this.MachineToolNumber = ''
this.taxRate = ''
this.consignee = ''

View File

@@ -132,6 +132,26 @@
<el-input v-model="consignee" readonly size="small" style="width:200px;margin: 10px 0 10px 3px"/>
</el-col>
<el-col :span="6">
<!-- 修改人:Ld 修改时间:2026-07-27 10:00:00; 合同头部提成类型 -->
<span>&nbsp;提成类型:</span>
<el-select
v-model="commissionType"
clearable
filterable
placeholder="请选择提成类型"
size="small"
style="width:200px;margin: 10px 0 10px 3px"
@change="editContract">
<el-option
v-for="item in commissionTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"/>
</el-select>
</el-col>
</el-row>
<el-row style="width: 1192px;margin-left: 160px">
<el-col :span="24">
<span>&nbsp;合同备注:</span>
<el-tooltip :open-delay="500" :disabled="contractRemarks ? false : true" effect="dark" placement="top">
<div slot="content">{{ contractRemarks }}</div>
@@ -1012,6 +1032,14 @@ export default {
},
people: [],
province: [],
// 修改人:Ld 修改时间:2026-07-27 10:00:00; 合同提成类型下拉选项
commissionTypeOptions: [
{ label: '首单提成(专机)', value: '首单提成(专机)' },
{ label: '首单提成(模块)', value: '首单提成(模块)' },
{ label: '转介绍提成(专机)', value: '转介绍提成(专机)' },
{ label: '转介绍提成(模块)', value: '转介绍提成(模块)' },
{ label: '复购提成', value: '复购提成' }
],
rules: {
省份: [{ required: true, message: '请选择省份' }],
客户名称: [{ required: true, message: '请输入客户名称' }],
@@ -1042,6 +1070,7 @@ export default {
paymentMethodValue: '', // 付款方式值
customerRequirements: '', // 客户要求
contractRemarks: '', // 合同备注
commissionType: '', // 提成类型
consignee: '',
productName: '',
MachineToolNumber: '',
@@ -1412,6 +1441,7 @@ export default {
this.deliveryDate = ''
this.customerRequirements = ''
this.contractRemarks = ''
this.commissionType = ''
this.MachineToolNumber = ''
var param1 = []
var Data1 = this.CreateData('11', 'PDM_项目名称_新专机_查询数据', param1)
@@ -1700,6 +1730,7 @@ export default {
this.customerRequirements = response.data[0].客户要求
this.contractRemarks = response.data[0].合同备注
this.MachineToolNumber = response.data[0].机床流水号
this.commissionType = response.data[0].提成类型 ? response.data[0].提成类型 : ''
this.contractMumber = response.data[0].合同编号
this.searchMachine()
this.searchProduct()
@@ -1777,6 +1808,7 @@ export default {
this.deliveryDate = ''
this.customerRequirements = ''
this.contractRemarks = ''
this.commissionType = ''
this.MachineToolNumber = ''
var param1 = []
var Data1 = this.CreateData('11', 'PDM_项目名称_新专机_查询数据', param1)
@@ -1820,8 +1852,9 @@ export default {
param[5] = ['交货期限', this.deliveryDate]
param[6] = ['客户要求', this.customerRequirements]
param[7] = ['合同备注', this.contractRemarks]
param[8] = ['操作者', this.id]
param[9] = ['收货人', this.consignee]
param[8] = ['提成类型', this.commissionType]
param[9] = ['操作者', this.id]
param[10] = ['收货人', this.consignee]
var Data = this.CreateData('12', 'PDM_项目名称_编辑数据', param)
this.ExecDatabase(Data).then(response => {
if (response.data[0].result === '0') {
@@ -1842,8 +1875,9 @@ export default {
param[5] = ['交货期限', this.deliveryDate]
param[6] = ['客户要求', this.customerRequirements]
param[7] = ['合同备注', this.contractRemarks]
param[8] = ['操作者', this.id]
param[9] = ['收货人', this.consignee]
param[8] = ['提成类型', this.commissionType]
param[9] = ['操作者', this.id]
param[10] = ['收货人', this.consignee]
console.log(this.consignee, 456)
var Data = this.CreateData('12', 'PDM_项目名称_编辑数据', param)
this.ExecDatabase(Data).then(response => {
@@ -2316,6 +2350,11 @@ export default {
},
submitContract() {
if (this.contractNoValue) {
// 修改人:Ld 修改时间:2026-07-27 10:00:00; 提交前必须选择提成类型
if (!this.commissionType) {
this.$message.warning('请选择提成类型')
return
}
if (this.customerNameValue && this.paymentMethodValue && this.taxRate && this.tableData.length !== 0 && this.tableData1.length !== 0 && this.deliveryDate && this.signingDate) {
for (let i = 0; i < this.tableData1.length; i++) {
if (this.tableData1[i].产品名称 === null || this.tableData1[i].产品名称 === '') {
@@ -2371,6 +2410,7 @@ export default {
this.deliveryDate = ''
this.customerRequirements = ''
this.contractRemarks = ''
this.commissionType = ''
this.MachineToolNumber = ''
this.taxRate = ''
this.consignee = ''

View File

@@ -96,7 +96,7 @@
border
stripe
size="small"
style="width: 1651px"
style="width: 1791px"
height="280px"
@cell-dblclick="handleEdit"
@row-click="searchTable1">
@@ -138,6 +138,12 @@
{{ scope.row.订单编号 }}
</template>
</el-table-column>
<!-- 修改人:Ld 修改时间:2026-08-03 17:02:31; 显示订单挂靠的销售合同编号,便于识别补货订单来源。 -->
<el-table-column :width="setColumnWidth('合同编号')" label="合同编号" align="center" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.合同编号 }}
</template>
</el-table-column>
<el-table-column width="60px" label="收货人" align="center">
<template slot-scope="scope">
{{ scope.row.收货人 }}
@@ -3427,4 +3433,3 @@ a {
}
</style>

View File

@@ -152,6 +152,26 @@
</el-tooltip>
</el-col>
</el-row>
<el-row style="width: 1192px;margin-left: 170px">
<el-col :span="24">
<!-- 修改人:Ld 修改时间:2026-07-27 10:00:00; 合同头部提成类型 -->
<span>&nbsp;提成类型:</span>
<el-select
v-model="commissionType"
clearable
filterable
placeholder="请选择提成类型"
size="small"
style="width:200px;margin: 10px 0 10px 3px"
@change="editContract">
<el-option
v-for="item in commissionTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"/>
</el-select>
</el-col>
</el-row>
<div style="margin-left: 170px">
<el-table
v-loading="loading"
@@ -1167,6 +1187,15 @@ export default {
},
people: [],
province: [],
// 修改人:Ld 修改时间:2026-07-27 10:00:00; 合同提成类型下拉选项
commissionTypeOptions: [
{ label: '复购提成', value: '复购提成' },
{ label: '首单提成(专机)', value: '首单提成(专机)' },
{ label: '首单提成(模块)', value: '首单提成(模块)' },
{ label: '转介绍提成(专机)', value: '转介绍提成(专机)' },
{ label: '转介绍提成(模块)', value: '转介绍提成(模块)' }
],
rules: {
省份: [{ required: true, message: '请选择省份' }],
客户名称: [{ required: true, message: '请输入客户名称' }],
@@ -1199,6 +1228,7 @@ export default {
paymentMethodValue: '', // 付款方式值
customerRequirements: '', // 客户要求
contractRemarks: '', // 合同备注
commissionType: '', // 提成类型
MachineToolNumber: '',
multipleSelection: [],
multipleSelection_variable: [],
@@ -1951,6 +1981,7 @@ export default {
this.deliveryDate = ''
this.customerRequirements = ''
this.contractRemarks = ''
this.commissionType = ''
this.MachineToolNumber = ''
var param1 = []
var Data1 = this.CreateData('11', 'PDM_项目名称_查询数据', param1)
@@ -2127,6 +2158,7 @@ export default {
this.customerRequirements = response.data[0].客户要求
this.contractRemarks = response.data[0].合同备注
this.MachineToolNumber = response.data[0].机床流水号
this.commissionType = response.data[0].提成类型 ? response.data[0].提成类型 : ''
this.searchProduct()
})
} else {
@@ -2199,6 +2231,7 @@ export default {
this.deliveryDate = ''
this.customerRequirements = ''
this.contractRemarks = ''
this.commissionType = ''
this.MachineToolNumber = ''
var param1 = []
var Data1 = this.CreateData('11', 'PDM_项目名称_查询数据', param1)
@@ -2242,8 +2275,9 @@ export default {
param[5] = ['交货期限', this.deliveryDate]
param[6] = ['客户要求', this.customerRequirements]
param[7] = ['合同备注', this.contractRemarks]
param[8] = ['操作者', this.id]
param[9] = ['收货人', this.consignee]
param[8] = ['提成类型', this.commissionType]
param[9] = ['操作者', this.id]
param[10] = ['收货人', this.consignee]
var Data = this.CreateData('12', 'PDM_项目名称_编辑数据', param)
this.ExecDatabase(Data).then(response => {
if (response.data[0].result === '0') {
@@ -2264,8 +2298,9 @@ export default {
param[5] = ['交货期限', this.deliveryDate]
param[6] = ['客户要求', this.customerRequirements]
param[7] = ['合同备注', this.contractRemarks]
param[8] = ['操作者', this.id]
param[9] = ['收货人', this.consignee]
param[8] = ['提成类型', this.commissionType]
param[9] = ['操作者', this.id]
param[10] = ['收货人', this.consignee]
console.log(this.consignee, 456)
var Data = this.CreateData('12', 'PDM_项目名称_编辑数据', param)
this.ExecDatabase(Data).then(response => {
@@ -2460,6 +2495,11 @@ export default {
},
submitContract() {
if (this.contractNoValue) {
// 修改人:Ld 修改时间:2026-07-27 10:00:00; 提交前必须选择提成类型
if (!this.commissionType) {
this.$message.warning('请选择提成类型')
return
}
if (this.customerNameValue && this.paymentMethodValue && this.taxRate && this.tableData.length !== 0 && this.deliveryDate && this.signingDate) {
for (let i = 0; i < this.tableData.length; i++) {
if (this.tableData[i].产品名称 === null || this.tableData[i].产品名称 === '') {
@@ -2495,6 +2535,7 @@ export default {
this.deliveryDate = ''
this.customerRequirements = ''
this.contractRemarks = ''
this.commissionType = ''
this.MachineToolNumber = ''
this.taxRate = ''
this.consignee = ''

View File

@@ -0,0 +1,239 @@
<template>
<div class="app-container">
<el-card style="height: 850px">
<div style="margin-top: 7px; margin-bottom: 7px">
<!-- 修改人:Ld 修改时间:2026-07-27 12:00:00; 销售绩效按汇款月份查询。 -->
<el-date-picker
v-model="performanceMonth"
type="month"
value-format="yyyy-MM"
size="small"
style="width: 160px"
clearable
placeholder="绩效月份"
@change="searchTable" />
<el-input
v-model="salesman"
style="width: 160px; margin-left: 10px"
size="small"
clearable
placeholder="销售员"
@keyup.enter.native="searchTable" />
<el-select
v-model="commissionType"
size="small"
style="width: 190px; margin-left: 10px"
clearable
filterable
placeholder="提成类型"
@change="searchTable">
<el-option v-for="item in commissionTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<el-input
v-model="contractNo"
style="width: 180px; margin-left: 10px"
size="small"
clearable
placeholder="合同编号"
@keyup.enter.native="searchTable" />
<el-button
icon="el-icon-search"
type="primary"
plain
size="small"
style="margin-left: 10px"
@click="searchTable">查询</el-button>
<el-button
icon="el-icon-download"
type="success"
plain
size="small"
style="margin-left: 10px"
@click="exportExcel">导出</el-button>
</div>
<el-table
v-loading="loading"
:data="pageTableData"
border
stripe
size="small"
style="width: 100%; margin-top: 20px"
height="740px"
@expand-change="handleExpandChange">
<!-- 修改人:Ld 修改时间:2026-07-28 13:45:00; 销售绩效展开查看回款明细 -->
<el-table-column type="expand" width="45px">
<template slot-scope="scope">
<div style="padding: 8px 25px">
<el-table
v-loading="scope.row.detailLoading"
:data="scope.row.paymentDetails || []"
border
stripe
size="mini"
style="width: 620px">
<el-table-column width="180px" label="回款时间" align="center" prop="回款时间" />
<el-table-column width="130px" label="回款金额" align="right">
<template slot-scope="detailScope">{{ formatMoney(detailScope.row.回款金额) }}</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="备注" show-overflow-tooltip />
</el-table>
<div v-if="!scope.row.detailLoading && (!scope.row.paymentDetails || scope.row.paymentDetails.length === 0)" style="line-height: 32px;color: #909399">
暂无回款明细
</div>
</div>
</template>
</el-table-column>
<el-table-column width="60px" label="序号" type="index" align="center" />
<el-table-column width="100px" label="绩效月份" align="center" prop="绩效月份" />
<el-table-column width="100px" label="销售员" align="center" prop="销售员" show-overflow-tooltip />
<el-table-column width="160px" label="合同编号" align="center" prop="合同编号" show-overflow-tooltip />
<el-table-column width="220px" label="客户名称" align="center" prop="客户名称" show-overflow-tooltip />
<el-table-column width="120px" label="合同金额" align="right">
<template slot-scope="scope">{{ formatMoney(scope.row.合同金额) }}</template>
</el-table-column>
<el-table-column width="120px" label="累计回款金额" align="right">
<template slot-scope="scope">{{ formatMoney(scope.row.累计回款金额) }}</template>
</el-table-column>
<el-table-column width="120px" label="本月回款金额" align="right">
<template slot-scope="scope">{{ formatMoney(scope.row.本月回款金额) }}</template>
</el-table-column>
<el-table-column width="100px" label="回款比例" align="right">
<template slot-scope="scope">{{ formatPercent(scope.row.回款比例) }}</template>
</el-table-column>
<el-table-column width="170px" label="提成类型" align="center" prop="提成类型" show-overflow-tooltip />
<el-table-column width="100px" label="提成比例" align="right">
<template slot-scope="scope">{{ formatPercent(scope.row.提成比例) }}</template>
</el-table-column>
<el-table-column width="130px" label="本月绩效金额" align="right">
<template slot-scope="scope">{{ formatMoney(scope.row.本月绩效金额) }}</template>
</el-table-column>
</el-table>
<div class="block" style="margin-top: 10px">
<el-pagination
:current-page="pageCurrent"
:page-sizes="[10, 20, 30, 40, 100]"
:page-size="pageSize"
:total="tableData.length"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChanges"
@current-change="handleCurrentChanges" />
</div>
</el-card>
</div>
</template>
<script>
export default {
data() {
return {
loading: false,
performanceMonth: '',
salesman: '',
commissionType: '',
contractNo: '',
pageCurrent: 1,
pageSize: 100,
tableData: [],
// 修改人:Ld 修改时间:2026-07-27 12:00:00; 提成类型查询条件与合同录入保持一致。
commissionTypeOptions: [
{ label: '首单提成(专机)', value: '首单提成(专机)' },
{ label: '首单提成(模块)', value: '首单提成(模块)' },
{ label: '转介绍提成(专机)', value: '转介绍提成(专机)' },
{ label: '转介绍提成(模块)', value: '转介绍提成(模块)' },
{ label: '复购提成', value: '复购提成' }
]
}
},
computed: {
pageTableData() {
const start = (this.pageCurrent - 1) * this.pageSize
return this.tableData.slice(start, start + this.pageSize)
}
},
mounted() {
const date = new Date()
this.performanceMonth = date.getFullYear() + '-' + this.padMonth(date.getMonth() + 1)
this.searchTable()
},
methods: {
padMonth(value) {
return value < 10 ? '0' + value : String(value)
},
buildParam() {
var param = []
param[0] = ['绩效月份', this.performanceMonth]
param[1] = ['销售员_check', this.salesman ? 1 : 0]
param[2] = ['销售员', this.salesman]
param[3] = ['提成类型_check', this.commissionType ? 1 : 0]
param[4] = ['提成类型', this.commissionType]
param[5] = ['合同编号_check', this.contractNo ? 1 : 0]
param[6] = ['合同编号', this.contractNo]
return param
},
searchTable() {
this.loading = true
this.pageCurrent = 1
var Data = this.CreateData('11', '销售管理_销售绩效_查询数据', this.buildParam())
this.ExecDatabase(Data).then(response => {
this.tableData = response.data || []
this.loading = false
}).catch(() => {
this.loading = false
this.$message.error('销售绩效查询失败')
})
},
handleExpandChange(row, expandedRows) {
const isExpanded = expandedRows.some(item => item.项目流水号 === row.项目流水号)
if (!isExpanded || row.paymentDetails) {
return
}
this.searchPaymentDetails(row)
},
searchPaymentDetails(row) {
// 修改人:Ld 修改时间:2026-07-28 13:45:00; 展开绩效行时按合同查询回款明细
this.$set(row, 'detailLoading', true)
var param = []
param[0] = ['项目流水号', row.项目流水号]
var Data = this.CreateData('11', '销售管理_销售绩效_回款明细_查询数据', param)
this.ExecDatabase(Data).then(response => {
this.$set(row, 'paymentDetails', response.data || [])
this.$set(row, 'detailLoading', false)
}).catch(() => {
this.$set(row, 'detailLoading', false)
this.$message.error('回款明细查询失败')
})
},
exportExcel() {
if (this.tableData.length === 0) {
this.$message.warning('暂无数据')
return
}
var Data = this.CreateData('2001', '报表_销售管理_销售绩效_查询数据', this.buildParam())
this.exportExcel_NPOI(Data)
},
handleSizeChanges(val) {
this.pageSize = val
this.pageCurrent = 1
},
handleCurrentChanges(val) {
this.pageCurrent = val
},
formatMoney(value) {
const num = Number(value || 0)
return num.toFixed(2)
},
formatPercent(value) {
const num = Number(value || 0)
return num.toFixed(2) + '%'
}
}
}
</script>
<style scoped>
.app-container {
padding: 20px;
}
</style>

View File

@@ -23,6 +23,8 @@
<el-input v-model="queryForm.零件名称" clearable size="small" style="width: 150px" placeholder="零件名称" @keyup.enter.native="pageCurrent = 1;searchTable()" />
<el-input v-model="queryForm.图号" clearable size="small" style="width: 150px" placeholder="图号" @keyup.enter.native="pageCurrent = 1;searchTable()" />
<el-button icon="el-icon-search" type="primary" plain size="small" style="margin-left: 10px" @click="pageCurrent = 1;searchTable()">查询</el-button>
<!-- 修改人:Ld 修改时间:2026-08-03 14:24:48; 工序工价按当前查询条件导出测试库新增的导出过程数据 -->
<el-button type="success" plain icon="el-icon-download" size="small" @click="exportExcel()">导出</el-button>
<el-button :disabled="!queryForm.工艺计划流水号 || tableData.length === 0" icon="el-icon-collection" type="success" plain size="small" @click="handleSaveSource()">保存</el-button>
<el-button :disabled="!queryForm.工艺计划流水号" icon="el-icon-document-copy" type="warning" plain size="small" @click="openCopyDialog()">拷贝</el-button>
<el-tag v-if="savedSourceInfo" size="small" type="success" style="margin-left: 6px" closable @close="savedSourceInfo = null">已保存: {{ savedSourceInfo.零件名称 }}</el-tag>
@@ -92,7 +94,7 @@
</el-table-column>
<el-table-column label="总时间s" align="center" width="90">
<template slot-scope="scope">
{{ scope.row.总时间s }}
{{ getTotalTime(scope.row) }}
</template>
</el-table-column>
<el-table-column label="单装数量(件)" align="center" width="110">
@@ -165,7 +167,8 @@
<!-- 修改人:Ld 修改时间:2026-07-02 15:33:23 -->
<!-- 工价设置弹窗 -->
<el-dialog v-el-drag-dialog :visible.sync="dialogFormVisible" :title="dialogTitle" center width="960px">
<el-form ref="form" :model="form" :rules="rules" label-position="left" label-width="100px">
<!-- 修改人:Ld 修改时间:2026-08-04 09:39:18; 工价公式字段名称较长,放大标签宽度避免遮挡输入框 -->
<el-form ref="form" :model="form" :rules="rules" label-position="left" label-width="130px">
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="工艺名称" prop="工艺名称">
@@ -190,22 +193,22 @@
</el-form-item>
</el-col>
</el-row>
<!-- 修改人:Ld 修改时间:2026-07-03 08:02:29 -->
<!-- 按现场确认的 9 个工价字段维护 -->
<!-- 修改人:Ld 修改时间:2026-08-04 09:39:18; 设置弹窗补齐截图公式字段,计算字段随输入自动联动 -->
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="机动时间s" prop="机动时间s">
<el-input-number v-model="form.机动时间s" :min="0" :precision="2" :step="1" controls-position="right" style="width: 100%;" />
<el-form-item label="机动时间(秒)" prop="机动时间s">
<el-input-number v-model="form.机动时间s" :min="0" :precision="2" :step="1" controls-position="right" style="width: 100%;" @change="refreshTotalTime()" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="辅助时间s" prop="辅助时间s">
<el-input-number v-model="form.辅助时间s" :min="0" :precision="2" :step="1" controls-position="right" style="width: 100%;" />
<el-form-item label="辅助时间(秒)" prop="辅助时间s">
<el-input-number v-model="form.辅助时间s" :min="0" :precision="2" :step="1" controls-position="right" style="width: 100%;" @change="refreshTotalTime()" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="总时间s" prop="总时间s">
<el-input-number v-model="form.总时间s" :min="0" :precision="2" :step="1" controls-position="right" style="width: 100%;" />
<el-form-item label="总时间(秒)" prop="总时间s">
<!-- 修改人:Ld 修改时间:2026-08-03 14:40:10; 总时间由机动时间和辅助时间自动相加,不允许手工改写 -->
<el-input-number v-model="form.总时间s" :min="0" :precision="2" :step="1" controls-position="right" disabled style="width: 100%;" />
</el-form-item>
</el-col>
</el-row>
@@ -216,36 +219,52 @@
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="操作台数" prop="操作台数">
<el-form-item label="操作台数(台/人)" prop="操作台数">
<el-input-number v-model="form.操作台数" :min="0" :precision="2" :step="1" controls-position="right" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="日产能(件)" prop="日产能(件)">
<el-input-number v-model="form['日产能(件)']" :min="0" :precision="2" :step="1" controls-position="right" style="width: 100%;" />
<el-form-item label="工作时间(时)" prop="工作时间(时)">
<el-input-number v-model="form['工作时间(时)']" :min="0" :precision="2" :step="0.5" controls-position="right" style="width: 100%;" @change="refreshPriceFormula()" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="最终单价" prop="最终单价(元/件)">
<!-- 修改人:Ld 修改时间:2026-07-06 09:23:45; 最终单价输入框仅保留两位小数显示 -->
<el-input-number v-model="form['最终单价(元/件)']" :min="0" :precision="2" :step="0.1" controls-position="right" style="width: 100%;" />
<el-col :span="8">
<el-form-item label="宽放时间(时)" prop="宽放时间(时)">
<el-input-number v-model="form['宽放时间(时)']" :min="0" :precision="2" :step="0.5" controls-position="right" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-col :span="8">
<el-form-item label="日工资(元)" prop="日工资(元)">
<el-input-number v-model="form['日工资(元)']" :min="0" :precision="2" :step="1" controls-position="right" style="width: 100%;" @change="refreshPriceFormula()" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="标准产能(件/天)" prop="标准产能(件/天)">
<el-input-number v-model="form['标准产能(件/天)']" :min="0" :precision="2" :step="1" controls-position="right" disabled style="width: 100%;" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="工价定额" prop="工价定额">
<el-input-number v-model="form.工价定额" :min="0" :precision="2" :step="0.1" controls-position="right" disabled style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="生效日期" prop="生效日期">
<el-date-picker v-model="form.生效日期" type="date" value-format="yyyy-MM-dd" format="yyyy-MM-dd" clearable size="small" placeholder="选择生效日期" style="width: 100%;" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-col :span="8">
<el-form-item label="变更次数" prop="变更次数">
<el-input-number v-model="form.变更次数" :min="0" :precision="0" :step="1" controls-position="right" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="12">
</el-row>
<el-row :gutter="16">
<el-col :span="24">
<el-form-item label="启用状态" prop="是否启用">
<el-select v-model="form.是否启用" clearable filterable size="small" style="width: 100%;" placeholder="请选择启用状态">
<el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" />
@@ -428,6 +447,11 @@ export default {
总时间s: 0,
'单装数量(件)': 0,
操作台数: 0,
'工作时间(时)': 0,
'宽放时间(时)': 0,
'日工资(元)': 0,
'标准产能(件/天)': 0,
工价定额: 0,
'日产能(件)': 0,
'最终单价(元/件)': 0,
生效日期: '',
@@ -462,6 +486,34 @@ export default {
this.searchTable()
},
methods: {
// 修改人:Ld 修改时间:2026-08-03 14:40:10; 总时间统一按机动时间加辅助时间计算
getTotalTime(row) {
var total = Number(row.机动时间s || 0) + Number(row.辅助时间s || 0)
return Number(total.toFixed(2))
},
// 修改人:Ld 修改时间:2026-08-03 14:40:10; 编辑弹窗中保持总时间自动等于机动时间加辅助时间
refreshTotalTime() {
if (!this.form) {
return
}
this.form.总时间s = this.getTotalTime(this.form)
this.refreshPriceFormula()
},
// 修改人:Ld 修改时间:2026-08-04 09:39:18; 按截图公式计算标准产能和工价定额,并同步旧字段兼容后端编辑过程
refreshPriceFormula() {
if (!this.form) {
return
}
var totalTime = Number(this.form.总时间s || 0)
var workTime = Number(this.form['工作时间(时)'] || 0)
var dayWage = Number(this.form['日工资(元)'] || 0)
var capacity = totalTime === 0 ? 0 : workTime * 3600 / totalTime
var priceQuota = capacity === 0 ? 0 : dayWage / capacity
this.form['标准产能(件/天)'] = Number(capacity.toFixed(4))
this.form.工价定额 = Number(priceQuota.toFixed(4))
this.form['日产能(件)'] = this.form['标准产能(件/天)']
this.form['最终单价(元/件)'] = this.form.工价定额
},
// 修改人:Ld 修改时间:2026-07-17 16:30:55; 统一处理工时统计跳转参数,避免再次跳转时保留上一次查询条件
applyJumpQuery(query) {
if (!query || (!query.订单号 && !query.零件名称 && !query.图号 && !query.工序名称)) {
@@ -593,10 +645,8 @@ export default {
}
})
},
// 修改人:Ld 修改时间:2026-07-06 08:36:02
// 查询列表
searchTable() {
this.loading = true
// 修改人:Ld 修改时间:2026-08-03 14:24:48; 查询和导出共用参数,保持筛选口径一致
buildQueryParam() {
var param = []
param[0] = ['订单流水号', this.queryForm.订单流水号]
param[1] = ['订单流水号_check', this.queryForm.订单流水号 ? 1 : 0]
@@ -615,6 +665,13 @@ export default {
// 修改人:Ld 修改时间:2026-07-17 08:44:08; 工时统计跳转后按图号精确查询,避免同名零件匹配过宽
param[14] = ['图号', this.queryForm.图号]
param[15] = ['图号_check', this.queryForm.图号 ? 1 : 0]
return param
},
// 修改人:Ld 修改时间:2026-07-06 08:36:02
// 查询列表
searchTable() {
this.loading = true
var param = this.buildQueryParam()
var Data = this.CreateData('11', '车间生产管理工艺_工序工价_查询数据', param, this.pageSize, this.pageCurrent)
this.ExecDatabase(Data).then(response => {
this.tableData = response.data && response.data.rows ? response.data.rows : response.data
@@ -624,6 +681,11 @@ export default {
this.loading = false
})
},
// 修改人:Ld 修改时间:2026-08-03 14:24:48; 调用测试库工序工价导出过程,导出当前查询条件下的全部数据
exportExcel() {
var Data = this.CreateData('2001', '车间生产管理工艺_工序工价_导出表格_查询', this.buildQueryParam())
this.exportExcel_NPOI(Data)
},
// 修改人:Ld 修改时间:2026-07-08; 保存当前零件的工价信息,供拷贝时直接使用
handleSaveSource() {
if (!this.queryForm.工艺计划流水号 || !this.tableData || this.tableData.length === 0) {
@@ -762,17 +824,23 @@ export default {
图号: row.图号,
机动时间s: Number(row.机动时间s || 0),
辅助时间s: Number(row.辅助时间s || 0),
总时间s: Number(row.总时间s || 0),
总时间s: this.getTotalTime(row),
'单装数量(件)': Number(row['单装数量(件)'] || 0),
操作台数: Number(row.操作台数 || 0),
'日产能(件)': Number(row['日产能(件)'] || 0),
'最终单价(元/件)': Number(row['最终单价(元/件)'] || 0),
'工作时间(时)': Number(row['工作时间(时)'] || 0),
'宽放时间(时)': Number(row['宽放时间(时)'] || 0),
'日工资(元)': Number(row['日工资(元)'] || 0),
'标准产能(件/天)': Number(row['标准产能(件/天)'] || row['日产能(件)'] || 0),
工价定额: Number(row.工价定额 || row['最终单价(元/件)'] || 0),
'日产能(件)': Number(row['标准产能(件/天)'] || row['日产能(件)'] || 0),
'最终单价(元/件)': Number(row.工价定额 || row['最终单价(元/件)'] || 0),
生效日期: row.生效日期,
变更次数: Number(row.变更次数 || 0),
是否启用: row.是否启用 === '' || row.是否启用 === null || typeof row.是否启用 === 'undefined' ? 1 : Number(row.是否启用),
备注: row.备注,
工序流水号: row.工序流水号
}
this.refreshPriceFormula()
},
// 修改人:Ld 修改时间:2026-07-02 15:33:23
// 提交新增或编辑
@@ -781,6 +849,8 @@ export default {
if (!valid) {
return false
}
this.refreshTotalTime()
this.refreshPriceFormula()
var param = []
param[0] = ['工价流水号', this.form.工价流水号]
param[1] = ['工艺名称', this.form.工艺名称]
@@ -789,7 +859,7 @@ export default {
param[4] = ['图号', this.form.图号]
param[5] = ['机动时间s', this.form.机动时间s]
param[6] = ['辅助时间s', this.form.辅助时间s]
param[7] = ['总时间s', this.form.总时间s]
param[7] = ['总时间s', this.getTotalTime(this.form)]
// 修改人:Ld 修改时间:2026-07-03 08:02:29
// 带括号字段提交给存储过程时使用安全参数名,查询返回仍保持原字段名
param[8] = ['单装数量件', this.form['单装数量(件)']]
@@ -831,6 +901,11 @@ export default {
总时间s: 0,
'单装数量(件)': 0,
操作台数: 0,
'工作时间(时)': 0,
'宽放时间(时)': 0,
'日工资(元)': 0,
'标准产能(件/天)': 0,
工价定额: 0,
'日产能(件)': 0,
'最终单价(元/件)': 0,
生效日期: '',

View File

@@ -412,8 +412,18 @@ export default {
this.$message.error('完成数量必须为大于等于 0 的整数')
return
}
var finishQuantity = Number(this.editForm.完成数量)
var originalQuantity = Number(this.editRow.完成数量 || 0)
var currentFinishedQuantity = Number(this.editRow.已完成数 || 0)
var productionQuantity = Number(this.editRow.投产数量 || 0)
var finalFinishedQuantity = currentFinishedQuantity - originalQuantity + finishQuantity
// 修改完成数量后的累计结果不能超过投产数量;修改人:Ld 修改时间:2026-07-23 16:22:46;
if (productionQuantity > 0 && finalFinishedQuantity > productionQuantity) {
this.$message.error('修改后的已完成数不能超过投产数量')
return
}
this.submitAudit(this.editRow, '已审核', '修改完成数量和加工完成时间后通过', {
finishQuantity: Number(this.editForm.完成数量),
finishQuantity: finishQuantity,
priceType: this.editForm.计价方式,
startTime: this.editForm.加工开始时间,
finishTime: this.editForm.加工完成时间

View File

@@ -22,8 +22,10 @@
<span v-if="monthCompletionRate !== ''" style="margin-left: 20px; font-size: 14px; color: #606266">
本月完成率:<el-tag :type="monthCompletionRateTag" size="medium" effect="dark">{{ monthCompletionRate }}</el-tag>
</span>
<!-- 修改人:Ld 修改时间:2026-08-05 09:38:16; 按上传生产计划表模板新增导出入口。 -->
<el-button icon="el-icon-download" type="success" plain size="small" style="margin-left: 10px" @click="exportProductionPlan()">导出</el-button>
</div>
<el-table :data="filteredTableData" height="750px" style="width: 2200px" size="mini" highlight-current-row border>
<el-table :data="filteredTableData" height="750px" style="width: 2340px" size="mini" highlight-current-row border>
<el-table-column width="50px" align="center" label="序号" show-overflow-tooltip fixed>
<template slot-scope="scope">
{{ scope.$index + 1 }}
@@ -36,6 +38,12 @@
</el-tag>
</template>
</el-table-column>
<!-- 修改人:Ld 修改时间:2026-08-04 14:57:36; 订单编号左侧增加合同编号列,优先显示方案一真实关联合同号。 -->
<el-table-column width="140px" align="center" label="合同编号" show-overflow-tooltip fixed>
<template slot-scope="scope">
{{ getProductionPlanContractNo(scope.row) }}
</template>
</el-table-column>
<el-table-column width="140px" align="center" label="订单编号" show-overflow-tooltip fixed>
<template slot-scope="scope">
{{ scope.row.MK订单编号 || scope.row.订单号 }}
@@ -43,7 +51,7 @@
</el-table-column>
<el-table-column width="90px" align="center" label="收货人" show-overflow-tooltip fixed>
<template slot-scope="scope">
{{ scope.row.收货人 || '仓库'}}
{{ scope.row.收货人 || '仓库' }}
</template>
</el-table-column>
<el-table-column width="90px" align="center" label="投产日期" show-overflow-tooltip>
@@ -88,68 +96,74 @@
</el-table-column>
<el-table-column width="100px" align="center" label="当前状态" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.设备 }}
<!-- 修改人:Ld 修改时间:2026-08-04 09:07:29; 机床名称可点击查看该机床后续已派工任务。 -->
<el-button v-if="scope.row.设备" class="machine-task-link" type="text" size="mini" @click.stop="openMachineTaskDialog(scope.row)">
{{ scope.row.设备 }}
</el-button>
<span v-else/>
</template>
</el-table-column>
<el-table-column width="60px" align="center" label="OP010" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.OP010 }}
<!-- 修改人:Ld 修改时间:2026-08-04 08:56:51; 已完成OP工序单元格标绿,页面布局不变。 -->
<span :class="getProcessCellClass(scope.row, 'OP010')">{{ scope.row.OP010 }}</span>
</template>
</el-table-column>
<el-table-column width="60px" align="center" label="OP020" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.OP020 }}
<span :class="getProcessCellClass(scope.row, 'OP020')">{{ scope.row.OP020 }}</span>
</template>
</el-table-column>
<el-table-column width="60px" align="center" label="OP030" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.OP030 }}
<span :class="getProcessCellClass(scope.row, 'OP030')">{{ scope.row.OP030 }}</span>
</template>
</el-table-column>
<el-table-column width="60px" align="center" label="OP040" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.OP040 }}
<span :class="getProcessCellClass(scope.row, 'OP040')">{{ scope.row.OP040 }}</span>
</template>
</el-table-column>
<el-table-column width="60px" align="center" label="OP050" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.OP050 }}
<span :class="getProcessCellClass(scope.row, 'OP050')">{{ scope.row.OP050 }}</span>
</template>
</el-table-column>
<el-table-column width="60px" align="center" label="OP060" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.OP060 }}
<span :class="getProcessCellClass(scope.row, 'OP060')">{{ scope.row.OP060 }}</span>
</template>
</el-table-column>
<el-table-column width="60px" align="center" label="OP070" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.OP070 }}
<span :class="getProcessCellClass(scope.row, 'OP070')">{{ scope.row.OP070 }}</span>
</template>
</el-table-column>
<el-table-column width="60px" align="center" label="OP080" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.OP080 }}
<span :class="getProcessCellClass(scope.row, 'OP080')">{{ scope.row.OP080 }}</span>
</template>
</el-table-column>
<el-table-column width="60px" align="center" label="OP090" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.OP090 }}
<span :class="getProcessCellClass(scope.row, 'OP090')">{{ scope.row.OP090 }}</span>
</template>
</el-table-column>
<el-table-column width="60px" align="center" label="OP100" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.OP100 }}
<span :class="getProcessCellClass(scope.row, 'OP100')">{{ scope.row.OP100 }}</span>
</template>
</el-table-column>
<el-table-column width="60px" align="center" label="OP110" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.OP110 }}
<span :class="getProcessCellClass(scope.row, 'OP110')">{{ scope.row.OP110 }}</span>
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog title="生产计划可视化看板" :visible.sync="dashboardVisible" width="1200px" top="30px" :close-on-click-modal="false" @close="closeDashboard">
<!-- 修改人:Ld 修改时间:2026-08-04 08:56:51; 调整弹窗属性顺序以通过单文件校验。 -->
<el-dialog :visible.sync="dashboardVisible" :close-on-click-modal="false" title="生产计划可视化看板" width="1200px" top="30px" @close="closeDashboard">
<el-row :gutter="10" style="margin-bottom: 15px">
<el-col :span="6">
<el-card shadow="hover" style="text-align: center; padding: 10px 0; cursor: pointer" @click.native="cardViewMode = cardViewMode === 'status' ? 'orderType' : 'status'">
@@ -214,12 +228,90 @@
</el-col>
</el-row>
</el-dialog>
<!-- 修改人:Ld 修改时间:2026-08-04 09:16:54; 弹窗改为APS排产格式,并按照操作者分组展示。 -->
<el-dialog :visible.sync="machineTaskVisible" :close-on-click-modal="false" :title="machineTaskTitle" width="1200px" top="50px">
<div v-loading="machineTaskLoading" class="machine-aps">
<div class="machine-aps-toolbar">
<span class="machine-aps-toolbar-label">时间筛选</span>
<el-date-picker
v-model="machineTaskDateRange"
:default-time="['00:00:00', '23:59:59']"
end-placeholder="结束日期"
range-separator="至"
size="small"
start-placeholder="开始日期"
style="width: 310px"
type="daterange"
value-format="yyyy-MM-dd"
@change="changeMachineTaskDateRange"/>
<el-button size="small" plain icon="el-icon-refresh-left" style="margin-left: 10px" @click="resetMachineTaskDateRange">重置</el-button>
<span class="machine-aps-toolbar-tip">按任务派工与完工时间区间筛选</span>
</div>
<div v-if="machineTaskDisplayData.length === 0 && !machineTaskLoading" class="machine-aps-empty">暂无后续已派工任务</div>
<div v-else class="machine-aps-scroll">
<div :style="{ width: machineApsInnerWidth + 'px' }" class="machine-aps-inner">
<div class="machine-aps-header">
<div class="machine-aps-person-header">操作者</div>
<div class="machine-aps-time-header">
<div
v-for="day in machineApsDays"
:key="day.key"
:style="{ width: machineApsDayWidth + 'px' }"
class="machine-aps-day">
{{ day.label }}
</div>
</div>
</div>
<div
v-for="person in machineApsGroups"
:key="person.name"
:style="{ height: person.height + 'px' }"
class="machine-aps-row">
<div class="machine-aps-person">
<div class="machine-aps-person-name">{{ person.name }}</div>
<div class="machine-aps-person-count">任务数:{{ person.tasks.length }}</div>
</div>
<div :style="{ width: machineApsTimelineWidth + 'px' }" class="machine-aps-lane">
<div
v-for="day in machineApsDays"
:key="person.name + '_' + day.key"
:style="{ left: day.left + 'px' }"
class="machine-aps-grid-line"/>
<el-tooltip
v-for="task in person.tasks"
:key="task._apsKey"
effect="dark"
placement="top">
<div slot="content">
<div>{{ task.订单号 }}</div>
<div>{{ task.零件名称 }} / {{ task.零件图号 }}</div>
<div>{{ task.工序顺序 }}-{{ task.工序 }} {{ task.数量 }}/{{ task.完成数 }}</div>
<div>{{ formatApsDateText(task.分配时间) }} 至 {{ formatApsDateText(task.精工期限) }}</div>
</div>
<div
:class="task._apsColorClass"
:style="{ left: task._apsLeft + 'px', width: task._apsWidth + 'px', top: task._apsTop + 'px' }"
class="machine-aps-task">
<div class="machine-aps-order">{{ task.订单号 }}</div>
<div class="machine-aps-part">{{ task.零件名称 }} / {{ task.工序 }}</div>
<div class="machine-aps-count">{{ task.完成数 }} / {{ task.数量 }}</div>
<div class="machine-aps-date">{{ formatApsDateText(task.精工期限) }}</div>
</div>
</el-tooltip>
</div>
</div>
</div>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import { getNowShotTime } from '@/utils/tool'
import XLSX from 'xlsx-style'
import FileSaver from 'file-saver'
export default {
data() {
return {
@@ -243,7 +335,17 @@ export default {
completionBarChart: null,
processStackChart: null,
pieViewMode: 'status',
cardViewMode: 'status'
cardViewMode: 'status',
// 修改人:Ld 修改时间:2026-08-04 09:07:29; 当前机床后续已派工任务弹窗数据。
machineTaskVisible: false,
machineTaskLoading: false,
machineTaskTitle: '机床后续已派工任务',
machineTaskData: [],
machineTaskDateRange: [],
// 修改人:Ld 修改时间:2026-08-04 09:16:54; APS排产弹窗的固定轴尺寸,保持展示稳定。
machineApsDayWidth: 88,
machineApsPersonWidth: 118,
machineApsMaxDays: 60
}
},
computed: {
@@ -314,6 +416,115 @@ export default {
salesProducing: salesProducing, restockProducing: restockProducing,
salesCompleted: salesCompleted, restockCompleted: restockCompleted
}
},
// 修改人:Ld 修改时间:2026-08-04 09:16:54; 根据已派工任务日期生成APS时间轴。
machineApsStartDate() {
var dates = []
this.machineTaskDisplayData.forEach(row => {
var startDate = this.parseApsDate(row.分配时间)
var endDate = this.parseApsDate(row.精工期限)
if (startDate) dates.push(startDate)
if (endDate) dates.push(endDate)
})
if (dates.length === 0) return this.clearApsDate(new Date())
dates.sort(function(a, b) {
return a.getTime() - b.getTime()
})
return this.clearApsDate(dates[0])
},
machineApsEndDate() {
var startDate = this.machineApsStartDate
var dates = []
this.machineTaskDisplayData.forEach(row => {
var start = this.parseApsDate(row.分配时间)
var end = this.parseApsDate(row.精工期限)
if (start) dates.push(start)
if (end) dates.push(end)
})
if (dates.length === 0) return this.addApsDays(startDate, 6)
dates.sort(function(a, b) {
return b.getTime() - a.getTime()
})
var endDate = this.clearApsDate(dates[0])
var diffDays = this.getApsDayDiff(startDate, endDate)
if (diffDays > this.machineApsMaxDays - 1) {
return this.addApsDays(startDate, this.machineApsMaxDays - 1)
}
return endDate
},
machineApsDays() {
var days = []
var totalDays = this.getApsDayDiff(this.machineApsStartDate, this.machineApsEndDate) + 1
if (totalDays < 7) totalDays = 7
for (let i = 0; i < totalDays; i++) {
var date = this.addApsDays(this.machineApsStartDate, i)
days.push({
key: this.formatApsDateKey(date),
label: this.formatApsDateKey(date),
left: i * this.machineApsDayWidth
})
}
return days
},
machineApsTimelineWidth() {
return this.machineApsDays.length * this.machineApsDayWidth
},
machineApsInnerWidth() {
return this.machineApsPersonWidth + this.machineApsTimelineWidth
},
machineApsGroups() {
var colorClasses = ['aps-task-blue', 'aps-task-green', 'aps-task-yellow', 'aps-task-purple', 'aps-task-cyan', 'aps-task-pink']
var grouped = {}
this.machineTaskDisplayData.forEach((row, index) => {
var personName = row.姓名 || '未指定'
if (!grouped[personName]) grouped[personName] = []
var startDate = this.parseApsDate(row.分配时间) || this.parseApsDate(row.精工期限) || this.addApsDays(this.machineApsStartDate, index)
var endDate = this.parseApsDate(row.精工期限) || startDate
if (endDate.getTime() < startDate.getTime()) endDate = startDate
var leftDays = this.getApsDayDiff(this.machineApsStartDate, this.clearApsDate(startDate))
var durationDays = this.getApsDayDiff(this.clearApsDate(startDate), this.clearApsDate(endDate)) + 1
if (leftDays < 0) leftDays = 0
if (leftDays > this.machineApsDays.length - 1) leftDays = this.machineApsDays.length - 1
if (leftDays + durationDays > this.machineApsDays.length) durationDays = this.machineApsDays.length - leftDays
if (durationDays < 1) durationDays = 1
grouped[personName].push(Object.assign({}, row, {
_apsKey: personName + '_' + index + '_' + row.工艺任务流水号,
_apsLeft: leftDays * this.machineApsDayWidth + 4,
_apsWidth: durationDays * this.machineApsDayWidth - 8,
_apsTop: 8 + grouped[personName].length * 58,
_apsColorClass: colorClasses[index % colorClasses.length]
}))
})
return Object.keys(grouped).map(name => {
return {
name: name,
tasks: grouped[name],
height: Math.max(76, grouped[name].length * 58 + 16)
}
})
},
// 修改人:Ld 修改时间:2026-08-04 14:30:24; 弹窗时间筛选后的任务集合,按派工时间与完工期限区间过滤。
machineTaskDisplayData() {
if (!this.machineTaskDateRange || this.machineTaskDateRange.length !== 2) {
return this.machineTaskData
}
var startDate = this.parseApsDate(this.machineTaskDateRange[0])
var endDate = this.parseApsDate(this.machineTaskDateRange[1])
if (!startDate || !endDate) {
return this.machineTaskData
}
if (endDate.getTime() < startDate.getTime()) {
var tempDate = startDate
startDate = endDate
endDate = tempDate
}
return this.machineTaskData.filter(row => {
var rowStart = this.parseApsDate(row.分配时间) || this.parseApsDate(row.精工期限)
var rowEnd = this.parseApsDate(row.精工期限) || rowStart
if (!rowStart) return false
if (!rowEnd) rowEnd = rowStart
return rowStart.getTime() <= endDate.getTime() && rowEnd.getTime() >= startDate.getTime()
})
}
},
created() {
@@ -376,6 +587,7 @@ export default {
return {
订单号: item.订单号,
MK订单编号: item.MK订单编号,
关联合同编号: item.关联合同编号,
收货人: item.MK订单收货人,
产品名称: item.产品名称,
零件名称: item.零件名称,
@@ -385,12 +597,16 @@ export default {
剩余数: item.剩余数,
状态: item.状态,
完成率: '',
总工序: 0,
实际工序: 0,
投产时间: item.投产时间,
精工期限: item.精工期限,
设备: item.设备,
材料: item.材料,
_totalProcesses: 0,
_completedProcesses: 0,
// 修改人:Ld 修改时间:2026-08-04 08:56:51; 记录每个OP工序是否完成,用于单元格标绿。
_completedOpMap: {},
...this.initializeProcessFields()
}
},
@@ -418,8 +634,119 @@ export default {
if (opIndex !== null) {
const opKey = this.processConfig.processNamePattern.replace('{index}', opIndex)
group[opKey] = item.工序
// 修改人:Ld 修改时间:2026-08-04 08:56:51; 按现有完成率口径判定单道OP是否完成。
group._completedOpMap[opKey] = remainingCount <= 0
}
},
// 修改人:Ld 修改时间:2026-08-04 08:56:51; 返回OP单元格样式,未完成保持原样。
getProcessCellClass(row, opKey) {
if (!row || !row[opKey]) return ''
if (row._completedOpMap && row._completedOpMap[opKey]) {
return 'op-process-completed'
}
return ''
},
// 修改人:Ld 修改时间:2026-08-04 14:57:36; 合同编号优先取方案一真实关联合同号,没有时保留原提取关联值。
getProductionPlanContractNo(row) {
if (!row) return ''
return row.关联合同编号 || row.合同编号 || row.MK订单编号 || row.订单号 || ''
},
// 修改人:Ld 修改时间:2026-08-04 09:07:29; 复用工况分页查询,按当前机床查看后续未完成的已派工任务。
openMachineTaskDialog(row) {
if (!row || !row.设备) {
this.$message.warning('当前行暂无机床信息')
return
}
var machineName = row.设备
var machineQueryValue = this.getMachineTaskQueryValue(machineName)
var param = []
param[0] = ['人员编号', '']
param[1] = ['人员编号_check', 0]
param[2] = ['设备流水号', machineQueryValue]
param[3] = ['设备流水号_check', 1]
param[4] = ['零件名称_check', 0]
param[5] = ['零件名称', '']
param[6] = ['排序名称', 0]
param[7] = ['排序方式', '']
param[8] = ['开始时间', '']
param[9] = ['结束时间', '']
param[10] = ['时间_check', 0]
param[11] = ['PageCurrent', 1]
param[12] = ['PageSize', 100]
param[13] = ['PageCount', '1111', 'int', '1']
param[14] = ['ItemCount', '1111', 'int', '1']
this.machineTaskTitle = machineName + ' 后续已派工任务'
this.machineTaskData = []
this.machineTaskVisible = true
this.machineTaskLoading = true
this.machineTaskDateRange = []
var Data = this.CreateData('11', '精工车间_工况_分页查询', param)
this.ExecDatabase(Data).then(response => {
if (response.data && response.data.result) {
this.machineTaskData = response.data.result
} else {
this.machineTaskData = []
}
}).finally(() => {
this.machineTaskLoading = false
})
},
// 修改人:Ld 修改时间:2026-08-04 09:07:29; 生产计划设备为“机床号:名称”,工况设备为“名称_机床号”,查询时优先取机床号。
getMachineTaskQueryValue(machineName) {
if (!machineName) return ''
var value = String(machineName)
if (value.indexOf(':') > -1) {
return value.split(':')[0]
}
if (value.indexOf(':') > -1) {
return value.split(':')[0]
}
return value
},
// 修改人:Ld 修改时间:2026-08-04 14:30:24; 切换弹窗时间范围后刷新APS排产展示。
changeMachineTaskDateRange() {
this.$forceUpdate()
},
resetMachineTaskDateRange() {
this.machineTaskDateRange = []
this.$forceUpdate()
},
// 修改人:Ld 修改时间:2026-08-04 09:16:54; APS排产视图日期解析,兼容后端日期字符串。
parseApsDate(value) {
if (!value) return null
var text = String(value).replace(/\//g, '-')
if (text.length > 10) text = text.substring(0, 10)
var parts = text.split('-')
if (parts.length < 3) return null
var year = parseInt(parts[0], 10)
var month = parseInt(parts[1], 10)
var day = parseInt(parts[2], 10)
if (isNaN(year) || isNaN(month) || isNaN(day)) return null
return new Date(year, month - 1, day)
},
clearApsDate(date) {
if (!date) return null
return new Date(date.getFullYear(), date.getMonth(), date.getDate())
},
addApsDays(date, days) {
var result = this.clearApsDate(date)
result.setDate(result.getDate() + days)
return result
},
getApsDayDiff(startDate, endDate) {
if (!startDate || !endDate) return 0
var oneDay = 24 * 60 * 60 * 1000
return Math.round((this.clearApsDate(endDate).getTime() - this.clearApsDate(startDate).getTime()) / oneDay)
},
formatApsDateKey(date) {
if (!date) return ''
return date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate()
},
formatApsDateText(value) {
var date = this.parseApsDate(value)
if (!date) return ''
return this.formatApsDateKey(date)
},
// 计算订单状态
calculateOrderStatus(group) {
var rate = 0
@@ -427,6 +754,8 @@ export default {
rate = Math.round(group._completedProcesses / group._totalProcesses * 100)
}
group.完成率 = rate + '%'
group.总工序 = group._totalProcesses
group.实际工序 = group._completedProcesses
if (rate === this.processConfig.statusRules.completed) {
group.状态 = '已完成'
} else if (rate === this.processConfig.statusRules.dispatching) {
@@ -461,6 +790,186 @@ export default {
})
return groupedData
},
// 修改人:Ld 修改时间:2026-08-05 09:38:16; 生产计划按上传模板样式导出,数据沿用页面筛选和分组显示规则。
exportProductionPlan() {
if (!this.filteredTableData || this.filteredTableData.length === 0) {
this.$message.warning('暂无数据可导出')
return
}
var headers = this.getProductionPlanExportHeaders()
var data = []
data.push([this.getProductionPlanExportTitle()])
data.push(headers)
this.filteredTableData.forEach((row, index) => {
data.push(this.buildProductionPlanExportRow(row, index))
})
var ws = XLSX.utils.aoa_to_sheet(data)
var range = XLSX.utils.decode_range(ws['!ref'])
ws['!merges'] = [{ s: { r: 0, c: 0 }, e: { r: 0, c: headers.length - 1 }}]
ws['!cols'] = this.getProductionPlanExportCols()
ws['!rows'] = this.getProductionPlanExportRows(this.filteredTableData.length)
ws['!freeze'] = { xSplit: 0, ySplit: 2 }
for (let rowIndex = range.s.r; rowIndex <= range.e.r; rowIndex++) {
for (let colIndex = range.s.c; colIndex <= range.e.c; colIndex++) {
var cellAddress = XLSX.utils.encode_cell({ r: rowIndex, c: colIndex })
if (!ws[cellAddress]) ws[cellAddress] = { t: 's', v: '' }
ws[cellAddress].s = this.getProductionPlanExportCellStyle(rowIndex, colIndex, ws[cellAddress].v)
if (rowIndex >= 2 && colIndex >= 16) {
var exportRow = this.filteredTableData[rowIndex - 2]
var opKey = headers[colIndex]
if (exportRow && exportRow._completedOpMap && exportRow._completedOpMap[opKey]) {
ws[cellAddress].s = this.getProductionPlanCompletedOpExportStyle()
}
}
}
}
ws['!autofilter'] = { ref: XLSX.utils.encode_range({ s: { r: 1, c: 0 }, e: { r: Math.max(1, range.e.r), c: headers.length - 1 }}) }
var wb = XLSX.utils.book_new()
XLSX.utils.book_append_sheet(wb, ws, this.getProductionPlanExportSheetName())
var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: false, type: 'array' })
FileSaver.saveAs(new Blob([wbout], { type: 'application/octet-stream' }), this.getProductionPlanExportFileName())
this.$message.success('导出成功')
},
getProductionPlanExportHeaders() {
return ['序号', '状态', '合同编号', '订单编号', '收货人', '投产日期', '订单交货日期', '数量', '总工序', '实际 工序', '产品名称', '零件名称', '零件图号', '材料', '完成率', '当前状态或设备', 'OP010', 'OP020', 'OP030', 'OP040', 'OP050', 'OP060', 'OP070', 'OP080', 'OP090', 'OP100', 'OP110']
},
buildProductionPlanExportRow(row, index) {
var opKeys = ['OP010', 'OP020', 'OP030', 'OP040', 'OP050', 'OP060', 'OP070', 'OP080', 'OP090', 'OP100', 'OP110']
var exportRow = [
index + 1,
row.状态 || '',
this.getProductionPlanContractNo(row),
row.MK订单编号 || row.订单号 || '',
row.收货人 || '仓库',
this.formatProductionPlanExportDate(row.投产时间),
this.formatProductionPlanExportDate(row.精工期限),
row.计划数 || '',
row.总工序 || 0,
row.实际工序 || 0,
row.产品名称 || '',
row.零件名称 || '',
row.零件图号 || '',
row.材料 || '',
this.getProductionPlanProgressText(row),
row.设备 || ''
]
opKeys.forEach(key => {
exportRow.push(row[key] || '')
})
return exportRow
},
getProductionPlanProgressText(row) {
var total = Number(row.总工序) || 0
var actual = Number(row.实际工序) || 0
if (total <= 0) return row.完成率 || '0%'
var percent = Math.round(actual / total * 100)
var barCount = Math.round(percent / 4)
var barText = ''
for (let i = 0; i < barCount; i++) {
barText += '▊'
}
return barText + percent + '%'
},
formatProductionPlanExportDate(value) {
if (!value) return ''
var text = String(value)
if (text.indexOf('-') > -1) {
var parts = text.substring(0, 10).split('-')
if (parts.length >= 3) {
return Number(parts[1]) + '.' + parts[2]
}
}
return text
},
getProductionPlanExportTitle() {
var month = this.monthValue || ''
if (month.indexOf('-') > -1) {
month = month.split('-')[1]
}
return ' ' + (month || '') + '月份生产计划表'
},
getProductionPlanExportSheetName() {
var month = this.monthValue || ''
if (month.indexOf('-') > -1) {
month = month.split('-')[1]
}
return (month || '生产') + '月生产计划表'
},
getProductionPlanExportFileName() {
var month = this.monthValue || ''
if (month.indexOf('-') > -1) {
month = month.split('-')[1]
}
return (month || '') + '月生产计划表.xlsx'
},
getProductionPlanExportCols() {
return [
{ wch: 7.5 }, { wch: 9 }, { wch: 18 }, { wch: 19.5 }, { wch: 10 },
{ wch: 9 }, { wch: 13 }, { wch: 6 }, { wch: 7 }, { wch: 10 },
{ wch: 16 }, { wch: 20 }, { wch: 22 }, { wch: 10 }, { wch: 31 },
{ wch: 13 }, { wch: 13 }, { wch: 13 }, { wch: 13 }, { wch: 13 },
{ wch: 13 }, { wch: 13 }, { wch: 13 }, { wch: 13 }, { wch: 13 },
{ wch: 13 }, { wch: 13 }
]
},
getProductionPlanExportRows(rowCount) {
var rows = [{ hpt: 42 }, { hpt: 25 }]
for (let i = 0; i < rowCount; i++) {
rows.push({ hpt: 25 })
}
return rows
},
getProductionPlanExportCellStyle(rowIndex, colIndex, value) {
var baseStyle = {
font: { name: '微软雅黑', sz: rowIndex === 0 ? 18 : 10, bold: false, color: { rgb: '000000' }},
alignment: { horizontal: 'center', vertical: 'center', wrapText: true },
border: rowIndex === 0 ? {} : {
top: { style: 'thin', color: { rgb: '000000' }},
bottom: { style: 'thin', color: { rgb: '000000' }},
left: { style: 'thin', color: { rgb: '000000' }},
right: { style: 'thin', color: { rgb: '000000' }}
}
}
if (rowIndex === 0) {
return baseStyle
}
if (rowIndex === 1) {
baseStyle.font.bold = false
baseStyle.fill = { fgColor: { rgb: 'FFFFFF' }}
return baseStyle
}
if (colIndex === 11 || colIndex === 12) {
baseStyle.alignment.horizontal = 'left'
}
if (colIndex === 14) {
baseStyle.font.bold = true
baseStyle.font.color = { rgb: '00B050' }
baseStyle.alignment.horizontal = 'left'
}
if (colIndex === 1) {
if (value === '已完成') {
baseStyle.font.color = { rgb: '909399' }
} else if (value === '生产中') {
baseStyle.font.color = { rgb: '67C23A' }
} else {
baseStyle.font.color = { rgb: '409EFF' }
}
}
return baseStyle
},
getProductionPlanCompletedOpExportStyle() {
return {
font: { name: '微软雅黑', sz: 10, bold: false, color: { rgb: 'FFFFFF' }},
fill: { fgColor: { rgb: '67C23A' }},
alignment: { horizontal: 'center', vertical: 'center', wrapText: true },
border: {
top: { style: 'thin', color: { rgb: '000000' }},
bottom: { style: 'thin', color: { rgb: '000000' }},
left: { style: 'thin', color: { rgb: '000000' }},
right: { style: 'thin', color: { rgb: '000000' }}
}
}
},
openDashboard() {
if (this.tableData2.length === 0) {
this.$message.warning('暂无数据,请先查询')
@@ -757,4 +1266,201 @@ export default {
:deep(.el-table__fixed) {
height: calc(100% - 18px) !important;
}
/* 修改人:Ld 修改时间:2026-08-04 08:56:51; 已完成OP工序绿色标识,不改变原表格布局。 */
.op-process-completed {
display: inline-block;
width: 100%;
min-height: 20px;
line-height: 20px;
color: #fff;
background-color: #67C23A;
border-radius: 2px;
}
/* 修改人:Ld 修改时间:2026-08-04 09:07:29; 保持当前状态列宽不变,仅增加机床可点击提示。 */
.machine-task-link {
width: 100%;
padding: 0;
font-size: 12px;
line-height: 20px;
white-space: normal;
}
/* 修改人:Ld 修改时间:2026-08-04 09:16:54; APS排产弹窗样式,按人名分组并保留现有系统的简洁表格风格。 */
.machine-aps {
min-height: 460px;
border: 1px solid #DCDFE6;
background: #fff;
}
.machine-aps-toolbar {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
border-bottom: 1px solid #DCDFE6;
background: #FAFBFC;
}
.machine-aps-toolbar-label {
color: #303133;
font-size: 12px;
font-weight: bold;
}
.machine-aps-toolbar-tip {
margin-left: 4px;
color: #909399;
font-size: 12px;
}
.machine-aps-empty {
height: 460px;
line-height: 460px;
text-align: center;
color: #909399;
font-size: 13px;
}
.machine-aps-scroll {
width: 100%;
height: 520px;
overflow: auto;
}
.machine-aps-inner {
min-width: 100%;
}
.machine-aps-header {
position: sticky;
top: 0;
z-index: 5;
display: flex;
height: 46px;
color: #303133;
background: #F5F7FA;
border-bottom: 1px solid #DCDFE6;
}
.machine-aps-person-header {
flex: 0 0 118px;
width: 118px;
line-height: 46px;
text-align: center;
font-weight: bold;
border-right: 1px solid #DCDFE6;
}
.machine-aps-time-header {
display: flex;
}
.machine-aps-day {
height: 46px;
line-height: 46px;
text-align: center;
font-size: 12px;
border-right: 1px solid #DCDFE6;
box-sizing: border-box;
}
.machine-aps-row {
display: flex;
min-height: 76px;
border-bottom: 1px solid #DCDFE6;
}
.machine-aps-person {
flex: 0 0 118px;
width: 118px;
padding: 12px 6px;
color: #303133;
background: #EEF3FF;
border-right: 1px solid #DCDFE6;
box-sizing: border-box;
}
.machine-aps-person-name {
overflow: hidden;
font-size: 13px;
font-weight: bold;
line-height: 20px;
text-overflow: ellipsis;
white-space: nowrap;
}
.machine-aps-person-count {
margin-top: 4px;
color: #606266;
font-size: 12px;
}
.machine-aps-lane {
position: relative;
min-height: 76px;
background: repeating-linear-gradient(
90deg,
#ffffff 0,
#ffffff 21px,
#F7FAFC 21px,
#F7FAFC 22px
);
}
.machine-aps-grid-line {
position: absolute;
top: 0;
bottom: 0;
width: 1px;
background: #D7E3EA;
}
.machine-aps-task {
position: absolute;
height: 48px;
padding: 3px 6px;
overflow: hidden;
color: #1F2D3D;
border: 1px solid #606266;
border-radius: 2px;
box-sizing: border-box;
cursor: pointer;
}
.machine-aps-order,
.machine-aps-part,
.machine-aps-count,
.machine-aps-date {
overflow: hidden;
font-size: 11px;
line-height: 12px;
text-overflow: ellipsis;
white-space: nowrap;
}
.aps-task-blue {
background: #C7D4FF;
}
.aps-task-green {
background: #B7E8B5;
}
.aps-task-yellow {
background: #FFF7B0;
}
.aps-task-purple {
background: #D8C7F0;
}
.aps-task-cyan {
background: #C8DDE4;
}
.aps-task-pink {
background: #F7B6BB;
}
</style>

View File

@@ -55,7 +55,7 @@
<!-- 修改人:Ld 修改时间:2026-07-06 09:12:38; 员工汇总显示按工序工价计算的总价 -->
<el-table-column width="90px" label="总价" align="center" show-overflow-tooltip prop="总价">
<template slot-scope="scope">
{{ scope.row.总价 }}
{{ formatTotalPrice(scope.row.总价) }}
</template>
</el-table-column>
</el-table>
@@ -133,7 +133,7 @@
</el-table-column>
<el-table-column v-if="Number(token) === 2" width="90px" label="总价" align="center" show-overflow-tooltip prop="总价">
<template slot-scope="scope">
{{ scope.row.总价 }}
{{ formatTotalPrice(scope.row.总价) }}
</template>
</el-table-column>
<el-table-column :width="setColumnWidth('加工工时M')" label="加工工时M" align="center" show-overflow-tooltip prop="加工时长">
@@ -234,7 +234,7 @@
<!-- 修改人:Ld 修改时间:2026-07-06 09:12:38; 设备汇总显示按工序工价计算的总价 -->
<el-table-column width="90px" label="总价" align="center" show-overflow-tooltip prop="总价">
<template slot-scope="scope">
{{ scope.row.总价 }}
{{ formatTotalPrice(scope.row.总价) }}
</template>
</el-table-column>
</el-table>
@@ -310,11 +310,11 @@
<span v-else>{{ scope.row.单价 }}</span>
</template>
</el-table-column>
<el-table-column v-if="Number(token) === 2" width="90px" label="总价" align="center" show-overflow-tooltip prop="总价">
<template slot-scope="scope">
{{ scope.row.总价 }}
</template>
</el-table-column>
<el-table-column v-if="Number(token) === 2" width="90px" label="总价" align="center" show-overflow-tooltip prop="总价">
<template slot-scope="scope">
{{ formatTotalPrice(scope.row.总价) }}
</template>
</el-table-column>
<el-table-column :width="setColumnWidth('加工工时M')" label="加工工时M" align="center" show-overflow-tooltip prop="加工时长">
<template slot-scope="scope">
{{ scope.row.加工时长 }}
@@ -446,6 +446,13 @@ export default {
}
})
},
// 修改人:Ld 修改时间:2026-08-04 16:30:55; 总价统一保留一位小数,零值也显示为 0.0
formatTotalPrice(value) {
if (value === '' || value === null || typeof value === 'undefined') {
return ''
}
return Number(value).toFixed(1)
},
// 修改人:Ld 修改时间:2026-07-09; 操作者筛选后刷新表格布局
filterOperator() {
this.$nextTick(function() {

View File

@@ -38,6 +38,16 @@
style="margin-left:10px"
@click="pageCurrent=1;searchTable()">查询
</el-button>
<el-button
v-if="Number(token)===2"
type="info"
plain
icon="el-icon-view"
size="small"
style="margin-left:10px"
@click="switchDisabledMaterial">
{{ showDisabledMaterial ? '查看启用物料' : '查看禁用物料' }}
</el-button>
<el-button v-if="Number(token)===2" type="distribution" icon="el-icon-plus" size="small" style="margin-left:10px" @click="materialPlus">
物料
</el-button>
@@ -176,6 +186,14 @@
{{ scope.row.曾用物料编码 }}
</template>
</el-table-column>
<!-- 修改人:Ld 修改时间:2026-08-03 07:55:23; 禁用物料查询时显示当前启用状态 -->
<el-table-column width="90px" label="启用状态" align="center" prop="是否禁用">
<template slot-scope="scope">
<el-tag :type="Number(scope.row.是否禁用) === 1 ? 'info' : 'success'" size="mini">
{{ Number(scope.row.是否禁用) === 1 ? '禁用' : '启用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column :width="setColumnWidth('日期时间')" label="最近修改" align="center" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.修改日期 }}
@@ -201,7 +219,7 @@
{{ scope.row.Expr1 }}
</template>
</el-table-column>
<el-table-column label="操作" align="center" fixed="right" width="200px">
<el-table-column label="操作" align="center" fixed="right" width="230px">
<template slot-scope="scope">
<el-button
type="text"
@@ -209,8 +227,17 @@
size="mini"
style="margin-right: 10px"
@click="handleEdit(scope.row)"/>
<!-- 修改人:Ld 修改时间:2026-08-03 08:15:00; 禁用物料列表提供启用操作 -->
<el-button
:disabled="Number(token ) !== 2"
v-if="showDisabledMaterial"
:disabled="Number(token ) !== 2"
type="text"
icon="el-icon-refresh-left"
size="mini"
style="margin-right: 10px;color:#67c23a"
@click="handleEnable(scope.row)"/>
<el-button
:disabled="Number(token ) !== 2"
type="text"
icon="el-icon-delete"
size="mini"
@@ -763,6 +790,7 @@ export default {
], // 类型数组
loading: false, // 数据加载
loading3: false,
showDisabledMaterial: false, // 修改人:Ld 修改时间:2026-08-03 07:55:23; 控制查询启用或禁用物料
total: 0, // 分页总数
total1: 0, // 分页总数
total3: 0, // 分页总数
@@ -887,6 +915,8 @@ export default {
param[14] = ['ItemCount', '1111', 'int', '1']
param[15] = ['物料编码_check', materialCodeValue_check] // 备注:修改人:Ld 修改时间:2026-06-29 14:18:00
param[16] = ['物料编码', this.materialCodeValue] // 备注:修改人:Ld 修改时间:2026-06-29 14:18:00
param[17] = ['是否禁用_check', 1] // 修改人:Ld 修改时间:2026-08-03 07:55:23; 导出跟随当前启用/禁用查询口径
param[18] = ['是否禁用', this.showDisabledMaterial ? 1 : 0] // 修改人:Ld 修改时间:2026-08-03 07:55:23; 查看禁用物料时导出禁用数据
var Data = this.CreateData('2001', '物料管理_查询数据_分页', param)
this.exportExcel_NPOI(Data)
} else {
@@ -1329,20 +1359,22 @@ export default {
})
},
handleDelete(row) {
this.$confirm('是否删除?', '提示', {
var isDisabledMaterial = Number(row.是否禁用) === 1
var message = isDisabledMaterial ? '该物料已禁用,此操作将永久删除该物料,是否继续?' : '是否删除?'
this.$confirm(message, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
var param = []
param[0] = ['物料流水号', row.物料流水号]
var Data = this.CreateData('12', '物料管理_删除', param)
var Data = this.CreateData('12', isDisabledMaterial ? '物料管理_物理删除' : '物料管理_删除', param) // 修改人:Ld 修改时间:2026-08-03 08:35:00; 已禁用物料确认后执行物理删除
this.ExecDatabase(Data).then(response => {
if (response.data[0].result === '1') {
this.$message.success('删除成功')
this.searchTable()
} else {
this.$message.error('删除失败')
this.$message.error(response.data[0].msg || '删除失败')
}
})
}).catch(() => {
@@ -1352,6 +1384,31 @@ export default {
})
})
},
handleEnable(row) {
this.$confirm('是否启用该物料?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
var param = []
param[0] = ['物料流水号', row.物料流水号]
param[1] = ['操作者', this.id] // 修改人:Ld 修改时间:2026-08-03 08:15:00; 记录禁用物料启用操作人
var Data = this.CreateData('12', '物料管理_启用', param)
this.ExecDatabase(Data).then(response => {
if (response.data[0].result === '1') {
this.$message.success('启用成功')
this.searchTable()
} else {
this.$message.error(response.data[0].msg || '启用失败')
}
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消启用'
})
})
},
// searchTableCS() {
// let materialToolValue_check, materialNameValue_check, materialTypeValue_check, dateRange_check
// this.materialToolValue ? materialToolValue_check = 1 : materialToolValue_check = 0
@@ -1377,6 +1434,11 @@ export default {
// this.total = response.data
// })
// },
switchDisabledMaterial() {
this.showDisabledMaterial = !this.showDisabledMaterial // 修改人:Ld 修改时间:2026-08-03 07:55:23; 点击按钮切换禁用物料查询口径
this.pageCurrent = 1
this.searchTable()
},
searchTable() {
this.tableData = []
let materialToolValue_check, materialCodeValue_check, materialNameValue_check, materialTypeValue_check, dateRange_check, checked_check
@@ -1410,6 +1472,8 @@ export default {
param[14] = ['ItemCount', '1111', 'int', '1']
param[15] = ['物料编码_check', materialCodeValue_check]
param[16] = ['物料编码', this.materialCodeValue]
param[17] = ['是否禁用_check', 1] // 修改人:Ld 修改时间:2026-08-03 07:55:23; 查询启用/禁用物料
param[18] = ['是否禁用', this.showDisabledMaterial ? 1 : 0] // 修改人:Ld 修改时间:2026-08-03 07:55:23; 查看禁用物料按钮传入禁用状态
var Data = this.CreateData('11', '物料管理_查询数据_分页', param)
this.ExecDatabase(Data).then(response => {
this.tableData = response.data.result

View File

@@ -9,6 +9,8 @@
<el-input v-model="LocationName" style="width: 100px " size="small" clearable placeholder="库位"/>
<el-button style="margin-left: 7px;width: 80px" type="primary" plain size="small" @click="pageCurrent=1;searchTable()">查询</el-button>
<el-button type="primary" plain icon="el-icon-upload2" size="small" style="margin-left: 7px" @click="handleExcel()">导入查询</el-button>
<!-- 修改人:Ld 修改时间:2026-07-23 09:02:58; 新增库存盘点导入预校验与批量提交入口。 -->
<el-button type="warning" plain icon="el-icon-upload" size="small" style="margin-left: 7px" @click="openInventoryImportDialog()">导入盘点</el-button>
<el-button v-if="Number(token) === 2" type="success" plain icon="el-icon-download" size="small" style="margin-left: 7px" @click="exportExcel()">导出</el-button>
<el-button type="distribution" size="small" @click="addMaterial()">增加物料存货</el-button>
<el-button type="primary" icon="el-icon-printer" style="margin-left: 20px" plain size="small" @click="Pronters()">批量打印</el-button>
@@ -181,6 +183,48 @@
<el-button type="primary" size="small" icon="el-icon-search" @click="importExcelSearch">查询</el-button>
</div>
</el-dialog>
<!-- 修改人:Ld 修改时间:2026-07-23 09:02:58; 导入盘点变化信息展示和确认提交弹窗。 -->
<el-dialog
v-el-drag-dialog
:visible.sync="dialogFormVisibleInventoryImport"
title="导入盘点"
center
width="1280px">
<upload-excel-component @on-selected-file="selectedInventoryImport"/>
<div style="margin: 10px 0 0 45px">
<span v-show="inventoryImportWorksheet.length > 1" style="cursor: pointer;width: 50px;" @click="removeAllInventoryImport"><i class="el-icon-close"/></span>
<el-upload :on-remove="handleRemoveInventoryImport" :file-list="inventoryImportItemFile" style="width: 260px" action=""/>
</div>
<div style="margin: 12px 0">
<el-button type="primary" size="small" icon="el-icon-search" @click="previewInventoryImport">预校验</el-button>
<el-button
:loading="inventoryImportSubmitting"
:disabled="inventoryImportData.length === 0"
type="success"
size="small"
icon="el-icon-check"
@click="submitInventoryImport">提交盘点</el-button>
<span style="margin-left: 12px;font-size: 13px;color: #606266">{{ inventoryImportSummary }}</span>
</div>
<el-table :data="inventoryImportData" border stripe size="mini" height="450px">
<el-table-column prop="导入序号" label="行号" width="60px" align="center"/>
<el-table-column prop="物料编码" label="物料编号" width="130px" align="center" show-overflow-tooltip/>
<el-table-column prop="物料名称" label="物料名称" width="160px" align="center" show-overflow-tooltip/>
<el-table-column prop="图号或型号" label="图号型号" width="150px" align="center" show-overflow-tooltip/>
<el-table-column prop="原货位名称" label="原库位" width="100px" align="center" show-overflow-tooltip/>
<el-table-column prop="调整后库位" label="调整后库位" width="120px" align="center" show-overflow-tooltip/>
<el-table-column prop="原库存" label="原库存" width="90px" align="center"/>
<el-table-column prop="导入库存" label="导入库存" width="90px" align="center"/>
<el-table-column prop="盘点库存" label="盘点库存" width="90px" align="center"/>
<el-table-column prop="库存变化" label="库存变化" width="90px" align="center"/>
<el-table-column prop="库位变化" label="库位变化" width="80px" align="center"/>
<el-table-column prop="处理结果" label="处理结果" width="100px" align="center"/>
<el-table-column prop="错误原因" label="错误原因" align="center" show-overflow-tooltip/>
</el-table>
<div slot="footer" class="dialog-footer">
<el-button size="small" @click="dialogFormVisibleInventoryImport=false">关闭</el-button>
</div>
</el-dialog>
<el-dialog v-el-drag-dialog :visible.sync="transferDialogVisible" title="库存调拨" center width="520px">
<el-form label-position="left" label-width="100px" style="margin: auto">
<el-row>
@@ -329,6 +373,13 @@ export default {
multipleSelection: [],
itemFile: [],
worksheet: [],
// 修改人:Ld 修改时间:2026-07-23 09:02:58; 导入盘点独立缓存,避免影响原导入查询功能。
dialogFormVisibleInventoryImport: false,
inventoryImportItemFile: [],
inventoryImportWorksheet: [],
inventoryImportData: [],
inventoryImportDetailChunks: [],
inventoryImportSubmitting: false,
rules: {
入库数: [{ required: true, message: '请输入入库数' }],
产品名称: [{ required: true, message: '请选择产品名称' }]
@@ -351,7 +402,33 @@ export default {
...mapGetters([
'id',
'token'
])
]),
inventoryImportSummary() {
var total = this.inventoryImportData.length
var success = 0
var fail = 0
var needCreate = 0
var stockChange = 0
var locationChange = 0
for (let i = 0; i < this.inventoryImportData.length; i++) {
var row = this.inventoryImportData[i]
if (row.处理结果 === '可修改' || row.处理结果 === '修改成功' || row.处理结果 === '成功' || row.处理结果 === '需新建库位') {
success++
} else if (row.处理结果) {
fail++
}
if (row.处理结果 === '需新建库位') {
needCreate++
}
if (row.库存变化 === '是') {
stockChange++
}
if (row.库位变化 === '是') {
locationChange++
}
}
return '总行数:' + total + ' 成功:' + success + ' 失败:' + fail + ' 需新建库位:' + needCreate + ' 库存变化:' + stockChange + ' 库位变化:' + locationChange
}
},
updated() {
this.$nextTick(() => {
@@ -501,6 +578,254 @@ export default {
handleExcel() {
this.dialogFormVisibleExcel = true
},
// 修改人:Ld 修改时间:2026-07-23 09:02:58; 打开导入盘点弹窗并保留上次预览结果供复核。
openInventoryImportDialog() {
this.dialogFormVisibleInventoryImport = true
},
selectedInventoryImport(data) {
this.inventoryImportWorksheet = data.worksheet
this.inventoryImportItemFile = data.itemFile
this.inventoryImportData = []
this.inventoryImportDetailChunks = []
},
handleRemoveInventoryImport(file) {
for (let i = 0; i < this.inventoryImportItemFile.length; i++) {
if (this.inventoryImportItemFile[i].name === file.name) {
this.inventoryImportWorksheet.splice(i, 1)
this.inventoryImportItemFile.splice(i, 1)
}
}
this.inventoryImportData = []
this.inventoryImportDetailChunks = []
},
removeAllInventoryImport() {
this.inventoryImportWorksheet = []
this.inventoryImportItemFile = []
this.inventoryImportData = []
this.inventoryImportDetailChunks = []
},
getInventoryImportColumns(sheet) {
var cols = [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
]
var result = {
headerRow: 1,
codeCol: '',
nameCol: '',
drawingCol: '',
locationCol: '',
stockCol: '',
checkStockCol: '',
remarkCol: ''
}
for (let row = 1; row <= 10; row++) {
var temp = {
headerRow: row,
codeCol: '',
nameCol: '',
drawingCol: '',
locationCol: '',
stockCol: '',
checkStockCol: '',
remarkCol: ''
}
for (let i = 0; i < cols.length; i++) {
var title = this.getExcelCellValue(sheet, cols[i], row).replace(/\s/g, '')
if (title === '物料编号' || title === '物料编码') {
temp.codeCol = cols[i]
}
if (title === '物料名称' || title === '名称' || title === '零件名称') {
temp.nameCol = cols[i]
}
if (title === '图号型号' || title === '图号' || title === '图号或型号' || title === '图号/型号' || title === '规格型号') {
temp.drawingCol = cols[i]
}
if (title === '调整后库位' || title === '库位') {
temp.locationCol = cols[i]
}
if (title === '库存' || title === '库存数') {
temp.stockCol = cols[i]
}
if (title === '盘点库存') {
temp.checkStockCol = cols[i]
}
if (title === '备注') {
temp.remarkCol = cols[i]
}
}
if ((temp.codeCol || temp.nameCol || temp.drawingCol) && temp.locationCol && temp.stockCol) {
return temp
}
if (temp.codeCol || temp.nameCol || temp.drawingCol || temp.locationCol || temp.stockCol) {
result = temp
}
}
return result
},
getInventoryImportNumber(value) {
var number = Number(String(value || '').replace(/,/g, ''))
if (isNaN(number)) {
return 0
}
return number
},
getInventoryImportDetail() {
var detail = []
for (let j = 0; j < this.inventoryImportWorksheet.length; j++) {
var sheet = this.inventoryImportWorksheet[j]
var columns = this.getInventoryImportColumns(sheet)
var emptyCount = 0
for (let row = columns.headerRow + 1; row <= 6000; row++) {
var materialCode = columns.codeCol ? this.getExcelCellValue(sheet, columns.codeCol, row) : ''
var materialName = columns.nameCol ? this.getExcelCellValue(sheet, columns.nameCol, row) : ''
var drawing = columns.drawingCol ? this.getExcelCellValue(sheet, columns.drawingCol, row) : ''
var location = columns.locationCol ? this.getExcelCellValue(sheet, columns.locationCol, row) : ''
var stockText = columns.stockCol ? this.getExcelCellValue(sheet, columns.stockCol, row) : ''
var checkStockText = columns.checkStockCol ? this.getExcelCellValue(sheet, columns.checkStockCol, row) : ''
var remark = columns.remarkCol ? this.getExcelCellValue(sheet, columns.remarkCol, row) : ''
if (!materialCode && !materialName && !drawing && !location && !stockText) {
emptyCount++
if (emptyCount >= 30) {
break
}
continue
}
emptyCount = 0
detail.push({
导入序号: row,
物料编码: materialCode,
物料名称: materialName,
图号或型号: drawing,
调整后库位: location,
库存: this.getInventoryImportNumber(stockText),
盘点库存: this.getInventoryImportNumber(checkStockText),
备注: remark
})
}
}
return detail
},
getInventoryImportBestDetail(detail) {
var detailMap = {}
var result = []
for (let i = 0; i < detail.length; i++) {
var row = detail[i]
var code = String(row.物料编码 || '').trim()
var name = String(row.物料名称 || '').trim()
var drawing = String(row.图号或型号 || '').trim()
var key = code ? 'code:' + code : 'name:' + name + '^' + drawing
if (!detailMap[key]) {
detailMap[key] = row
result.push(row)
continue
}
if (Number(row.库存 || 0) > Number(detailMap[key].库存 || 0)) {
var index = result.indexOf(detailMap[key])
detailMap[key] = row
if (index >= 0) {
result.splice(index, 1, row)
}
}
}
return result
},
buildInventoryImportDetailChunks(detail) {
var chunks = []
var rows = []
for (let i = 0; i < detail.length; i++) {
rows.push(this.formatInventoryImportRow(detail[i]))
if (rows.length >= 500) {
chunks.push(rows.join('||'))
rows = []
}
}
if (rows.length > 0) {
chunks.push(rows.join('||'))
}
return chunks
},
formatInventoryImportRow(row) {
var values = [
row.导入序号,
row.物料编码,
row.物料名称,
row.图号或型号,
row.调整后库位,
row.库存,
row.盘点库存,
row.备注
]
for (let i = 0; i < values.length; i++) {
values[i] = String(values[i] === undefined || values[i] === null ? '' : values[i]).replace(/\|\|/g, ' ').replace(/\^/g, ' ')
}
return values.join('^')
},
requestInventoryImportPreview(index, result) {
if (index >= this.inventoryImportDetailChunks.length) {
this.inventoryImportData = result
this.$message.success('导入盘点预校验完成')
return
}
var param = []
param[0] = ['导入明细', this.inventoryImportDetailChunks[index]]
var Data = this.CreateData('11', '仓储管理_库存盘点_导入盘点_预校验', param)
this.ExecDatabase(Data).then(response => {
var rows = response.data.rows || response.data || []
result = result.concat(rows)
this.requestInventoryImportPreview(index + 1, result)
}).catch(() => {
this.$message.error('导入盘点预校验失败')
})
},
previewInventoryImport() {
var detail = this.getInventoryImportDetail()
detail = this.getInventoryImportBestDetail(detail)
if (detail.length === 0) {
this.$message.warning('请导入包含物料编号、调整后库位和库存的表格')
return
}
this.inventoryImportData = []
this.inventoryImportDetailChunks = this.buildInventoryImportDetailChunks(detail)
this.requestInventoryImportPreview(0, [])
},
requestInventoryImportSubmit(index, result) {
if (index >= this.inventoryImportDetailChunks.length) {
this.inventoryImportData = result
this.inventoryImportSubmitting = false
this.getLocateName()
this.searchTable()
this.$message.success('导入盘点提交完成')
return
}
var param = []
param[0] = ['导入明细', this.inventoryImportDetailChunks[index]]
param[1] = ['操作者', this.id]
var Data = this.CreateData('12', '仓储管理_库存盘点_导入盘点_批量提交', param)
this.ExecDatabase(Data).then(response => {
var rows = response.data.rows || response.data || []
result = result.concat(rows)
this.requestInventoryImportSubmit(index + 1, result)
}).catch(() => {
this.inventoryImportSubmitting = false
this.$message.error('导入盘点提交失败')
})
},
submitInventoryImport() {
if (this.inventoryImportDetailChunks.length === 0) {
this.$message.warning('请先预校验导入盘点数据')
return
}
this.$confirm('确认按预校验数据修改库存和库位吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.inventoryImportSubmitting = true
this.requestInventoryImportSubmit(0, [])
}).catch(() => {
})
},
selected(data) {
this.worksheet = data.worksheet
this.itemFile = data.itemFile

View File

@@ -1,4 +1,4 @@
<template>
<template>
<div class="app-container">
<el-card style="height: 850px ;display:flex">
<el-col style="width: 930px">
@@ -7,6 +7,8 @@
<el-input v-model="specificationsValue" style="width:200px" placeholder="名称/规格/型号" size="small" clearable @keyup.enter.native="pageCurrent=1;updateCheck()"/>
<!-- <el-button :disabled="disabled1" icon="el-icon-edit" type="primary" style="margin-left: 10px" plain size="small" @click="setUpInventory()">最低库存</el-button> -->
<el-button :disabled="disabled" type="distribution" icon="el-icon-check" size="small" @click="openOrder()">提交补货</el-button>
<!-- 修改人:Ld 修改时间:2026-08-03 16:35:25; 新增关联合同补货入口,原提交补货按钮不变。 -->
<el-button :disabled="disabled" type="warning" plain icon="el-icon-connection" size="small" @click="openLinkedOrder()">关联合同补货</el-button>
<el-checkbox v-model="checked" style="margin-left: 40px" @change="updateCheck">自制补货</el-checkbox>
<el-badge :value="numberReturnedItems" class="item">
<el-button type="text" size="small" style="margin-left: 70px" @click="viewReturnedContracts()">打回通知</el-button>
@@ -68,7 +70,8 @@
width="400"
trigger="click"
@show="getDemandDetail(scope.row)">
<el-table :data="demandDetailData" border stripe size="mini" max-height="300" v-loading="demandDetailLoading">
<!-- 修改人:Ld 修改时间:2026-08-03 16:44:10; 调整属性顺序以通过单文件模板校验。 -->
<el-table v-loading="demandDetailLoading" :data="demandDetailData" border stripe size="mini" max-height="300">
<el-table-column prop="订单编号" label="订单号" align="center" show-overflow-tooltip/>
<el-table-column prop="最终需求量" label="需求量" align="center"/>
<el-table-column prop="简称" label="客户" align="center"/>
@@ -207,6 +210,84 @@
<el-button type="primary" @click="submitOrder()">确 定</el-button>
</div>
</el-dialog>
<!-- 修改人:Ld 修改时间:2026-08-03 16:35:25; 新增合同缺件/仓库备货补货来源弹窗。 -->
<el-dialog v-el-drag-dialog :visible.sync="dialogFormVisibleLink" title="关联合同补货" center width="760px">
<el-form label-position="right" label-width="95px" size="small">
<el-form-item label="补货来源">
<el-radio-group v-model="linkForm.来源类型" @change="changeLinkSource">
<el-radio-button label="合同缺件">合同零件不足</el-radio-button>
<el-radio-button label="仓库备货">仓库备货</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-if="linkForm.来源类型 === '合同缺件'" label="合同查询">
<el-input v-model="linkForm.关键字" clearable placeholder="合同编号 / 客户 / 订单编号" style="width: 360px" @keyup.enter.native="searchLinkContract"/>
<el-button type="primary" plain icon="el-icon-search" style="margin-left: 8px" @click="searchLinkContract">查询</el-button>
</el-form-item>
<el-form-item v-if="linkForm.来源类型 === '合同缺件'" label="查询结果">
<el-table
v-loading="linkContractLoading"
:data="linkContractList"
border
highlight-current-row
size="mini"
max-height="220"
style="width: 620px"
@row-click="selectLinkContract">
<el-table-column width="130px" label="合同编号" align="center" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.合同编号 }}
</template>
</el-table-column>
<el-table-column width="150px" label="客户" align="center" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.客户名称 || scope.row.客户简称 }}
</template>
</el-table-column>
<el-table-column width="150px" label="订单编号" align="center" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.订单编号 }}
</template>
</el-table-column>
<el-table-column label="交货日期" align="center">
<template slot-scope="scope">
{{ scope.row.交货日期 }}
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item v-if="linkForm.来源类型 === '合同缺件'" label="已选择">
<el-tag v-if="linkForm.项目流水号" type="success">
{{ linkForm.合同编号 }} / {{ linkForm.客户名称 }} / {{ linkForm.订单编号 || '未选订单' }}
</el-tag>
<span v-else style="color: #909399">请选择要关联的销售合同或订单</span>
</el-form-item>
<el-form-item v-if="linkForm.来源类型 === '仓库备货'" label="备货合同">
<!-- 修改人:Ld 修改时间:2026-08-04 08:29:13; 仓库备货改为提交时自动生成CKBH前缀合同。 -->
<el-tag type="warning">自动生成CKBH合同</el-tag>
<span style="margin-left: 10px;color: #909399">提交后生成独立仓库备货合同,收货人为仓库、单价为0</span>
</el-form-item>
<el-form-item label="补货期限">
<el-date-picker
v-model="linkForm.补货期限"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
placeholder="选择日期"
style="width: 220px"/>
</el-form-item>
<el-form-item label="订单备注">
<el-input
:rows="3"
v-model="linkForm.订单备注"
type="textarea"
placeholder="请输入补货原因或备货说明"
style="width: 520px"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button size="small" @click="dialogFormVisibleLink=false">取 消</el-button>
<el-button type="primary" size="small" @click="submitLinkedOrder">确 定</el-button>
</div>
</el-dialog>
<el-dialog v-el-drag-dialog :visible.sync="dialogFormVisible2" title="上传图片" center style="height: 800px" width="30%">
<el-upload
id="invoiceScan"
@@ -319,6 +400,21 @@ export default {
pageSize: 20, // 分页每页显示条数
orderName: '', // 排序列名
order: '', // 排序方式
// 修改人:Ld 修改时间:2026-08-03 16:35:25; 关联合同补货弹窗数据,独立于原补货提交。
dialogFormVisibleLink: false,
linkContractLoading: false,
linkContractList: [],
linkForm: {
来源类型: '合同缺件',
关键字: '',
项目流水号: '',
订单流水号: '',
合同编号: '',
客户名称: '',
订单编号: '',
补货期限: '',
订单备注: ''
},
demandDetailData: [],
demandDetailLoading: false
}
@@ -456,6 +552,67 @@ export default {
this.finishTime = ''
this.dialogFormVisible1 = true
},
// 修改人:Ld 修改时间:2026-08-03 16:35:25; 打开关联合同补货弹窗,不影响原 openOrder。
openLinkedOrder() {
this.resetLinkForm()
this.dialogFormVisibleLink = true
},
// 修改人:Ld 修改时间:2026-08-03 16:35:25; 重置关联合同补货表单。
resetLinkForm() {
this.linkContractList = []
this.linkContractLoading = false
this.linkForm = {
来源类型: '合同缺件',
关键字: '',
项目流水号: '',
订单流水号: '',
合同编号: '',
客户名称: '',
订单编号: '',
补货期限: '',
订单备注: ''
}
},
// 修改人:Ld 修改时间:2026-08-03 16:35:25; 切换补货来源时清理已选择合同。
changeLinkSource() {
this.linkContractList = []
this.linkForm.关键字 = ''
this.linkForm.项目流水号 = ''
this.linkForm.订单流水号 = ''
this.linkForm.合同编号 = ''
this.linkForm.客户名称 = ''
this.linkForm.订单编号 = ''
},
// 修改人:Ld 修改时间:2026-08-03 16:35:25; 查询可关联销售合同/订单。
searchLinkContract() {
this.linkContractLoading = true
var param = []
// 修改人:Ld 修改时间:2026-08-03 17:01:30; 后端通用入口按过程参数解析,查询过程入参全部传递,避免返回 result=0。
param[0] = ['关键字', this.linkForm.关键字]
param[1] = ['合同编号', '']
param[2] = ['客户', '']
param[3] = ['订单编号', '']
var Data = this.CreateData('11', '仓储管理_补货关联合同_查询数据', param)
this.ExecDatabase(Data).then(response => {
if (response.data[0] && response.data[0].result === '0') {
this.linkContractList = []
this.$message.error('合同查询失败,请确认当前为测试环境')
} else {
this.linkContractList = response.data
}
this.linkContractLoading = false
}).catch(() => {
this.linkContractLoading = false
})
},
// 修改人:Ld 修改时间:2026-08-03 16:35:25; 选择补货要挂靠的销售合同/订单。
selectLinkContract(row) {
this.linkForm.项目流水号 = row.项目流水号
this.linkForm.订单流水号 = row.订单流水号 || ''
this.linkForm.合同编号 = row.合同编号 || ''
this.linkForm.客户名称 = row.客户名称 || row.客户简称 || ''
this.linkForm.订单编号 = row.订单编号 || ''
},
handlePicture(row) {
this.dialogFormVisible2 = true
this.replenishmentOrderId = row.补货单明细中间表流水号
@@ -498,6 +655,41 @@ export default {
this.$message.warning('请选择补货期限')
}
},
// 修改人:Ld 修改时间:2026-08-03 16:35:25; 提交带合同/仓库备货来源的补货单,原 submitOrder 不变。
submitLinkedOrder() {
if (this.linkForm.来源类型 === '合同缺件' && !this.linkForm.项目流水号) {
this.$message.warning('请选择关联销售合同')
return
}
if (!this.linkForm.补货期限) {
this.$message.warning('请选择补货期限')
return
}
if (this.linkForm.来源类型 === '仓库备货' && !this.linkForm.订单备注) {
this.$message.warning('请填写仓库备货说明')
return
}
let check
this.checked ? check = 0 : check = 1
var param = []
param[0] = ['是否外购', check]
param[1] = ['操作者', this.id]
param[2] = ['补货期限', this.linkForm.补货期限]
param[3] = ['订单备注', this.linkForm.订单备注]
param[4] = ['来源类型', this.linkForm.来源类型]
param[5] = ['项目流水号', this.linkForm.项目流水号 || 0]
param[6] = ['订单流水号', this.linkForm.订单流水号 || 0]
var Data = this.CreateData('12', '报缺补货_提交_关联合同', param)
this.ExecDatabase(Data).then(response => {
if (response.data[0].result === '1') {
this.$message.success('提交成功')
this.dialogFormVisibleLink = false
this.updateCheck()
} else {
this.$message.error(response.data[0].message || '提交失败')
}
})
},
selectIn(row) {
if (row.补货数 !== 0 && row.补货数 !== undefined) {
let check

File diff suppressed because it is too large Load Diff

View File

@@ -139,7 +139,7 @@
</div>
<!-- 立库可视化区域 -->
<div v-loading="loading" style="height: 600px; overflow: auto; border: 1px solid #e4e7ed; border-radius: 4px; padding: 15px; background: #f5f7fa">
<div v-loading="loading" style="height: 600px; overflow:hidden; border: 1px solid #e4e7ed; border-radius: 4px; padding: 15px; background: #f5f7fa">
<!-- 数据为空提示 -->
<div v-if="warehouseData.length === 0" style="text-align: center; padding: 100px; color: #909399">
<!-- <el-empty description="暂无立库数据">
@@ -155,7 +155,7 @@
</div>
<!-- 立库表格 -->
<div style="overflow-x: auto; margin-bottom: 30px">
<div style=" margin-bottom: 30px">
<table class="warehouse-table">
<!-- 列标题 -->
<thead>

View File

@@ -642,11 +642,11 @@ export default {
if (this.multipleSelection.length !== 1) {
for (let i = 0; i < this.multipleSelection.length; i++) {
if (i === 0) {
time = this.multipleSelection[i].入库日期
// time = this.multipleSelection[i].入库日期
number = this.multipleSelection[i].供应商
caigou = this.multipleSelection[i].采购合同编号
} else {
if (time !== this.multipleSelection[i].入库日期 || number !== this.multipleSelection[i].供应商 || caigou !== this.multipleSelection[i].采购合同编号) {
if ( number !== this.multipleSelection[i].供应商 || caigou !== this.multipleSelection[i].采购合同编号) {
return 1
}
}

View File

@@ -1,6 +1,35 @@
<template>
<el-card style="min-height:calc(100vh - 84px);background: rgb(236,243,250);background-size:100% 100%">
<div class="dashboard-container">
<!-- 修改人:Ld 修改时间:2026-07-30 13:45:14; 移动端首页只展示已适配移动端的功能入口,侧边栏保持原逻辑不变。 -->
<div v-if="isMobileDashboard" class="mobile-dashboard-container">
<div class="mobile-user-card">
<svg-icon icon-class="username" class="mobile-user-icon"/>
<div>
<div class="mobile-user-name">{{ name }}</div>
<div class="mobile-user-subtitle">移动端功能</div>
</div>
</div>
<div class="mobile-module-grid">
<router-link
v-for="item in mobileModules"
:key="item.id"
:to="item.path"
class="mobile-module-card">
<div class="mobile-module-icon">
<svg-icon :icon-class="item.icon || 'doc'"/>
</div>
<div class="mobile-module-content">
<strong>{{ item.title }}</strong>
<span>{{ item.desc }}</span>
</div>
<i class="el-icon-arrow-right"/>
</router-link>
</div>
<div v-if="mobileModules.length === 0" class="mobile-empty">
当前角色暂无已适配移动端的功能
</div>
</div>
<div v-else class="dashboard-container">
<div class="sudoku_row" >
<svg-icon icon-class="人员" style="width: 35px;height: 35px"/>
<div class="dashboard-text" style="color:black">/{{ name }}</div>
@@ -51,8 +80,27 @@ export default {
computed: {
...mapGetters([
'name',
'token'
])
'token',
'device'
]),
// 修改人:Ld 修改时间:2026-07-30 13:45:14; 根据 Layout 的设备判断切换移动端首页内容。
isMobileDashboard() {
return this.device === 'mobile'
},
// 修改人:Ld 修改时间:2026-07-30 13:45:14; 仅展示当前角色菜单中已经做了移动端页面的入口。
mobileModules() {
var mobileModuleDesc = {
'SeikoWorkshop/WorkshopAssignmentMobile': '车间现场派工、取消派工和工序查看',
'PurchasingManagement/PurchaseInboundCreateMobile': '采购合同到货录入和入库单提交'
}
return this.sons.filter(function(item) {
return mobileModuleDesc[item.path] || item.title.indexOf('移动端') > -1 || item.path.indexOf('Mobile') > -1
}).map(function(item) {
return Object.assign({}, item, {
desc: mobileModuleDesc[item.path] || '移动端自适应页面'
})
})
}
},
mounted() {
this.getFileList()
@@ -232,6 +280,111 @@ export default {
line-height: 46px;
}
}
/* 修改人:Ld 修改时间:2026-07-30 13:45:14; 首页移动端功能入口样式,避免沿用桌面宫格宽度。 */
.mobile-dashboard-container {
min-height: calc(100vh - 84px);
padding: 12px;
background: #f4f7fb;
}
.mobile-user-card {
display: flex;
align-items: center;
gap: 10px;
padding: 12px;
border: 1px solid #d8e1ec;
border-radius: 8px;
background: #fff;
}
.mobile-user-icon {
width: 32px;
height: 32px;
color: #409eff;
}
.mobile-user-name {
color: #1f2d3d;
font-size: 18px;
font-weight: 700;
}
.mobile-user-subtitle {
margin-top: 4px;
color: #8492a6;
font-size: 12px;
}
.mobile-module-grid {
display: grid;
gap: 10px;
margin-top: 12px;
}
.mobile-module-card {
display: flex;
align-items: center;
gap: 10px;
min-width: 0;
padding: 12px;
border: 1px solid #d8e1ec;
border-radius: 8px;
background: #fff;
color: inherit;
text-decoration: none;
}
.mobile-module-icon {
display: flex;
flex: 0 0 40px;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 8px;
background: #ecf5ff;
color: #409eff;
}
.mobile-module-icon .svg-icon {
width: 24px;
height: 24px;
}
.mobile-module-content {
min-width: 0;
flex: 1;
}
.mobile-module-content strong {
display: block;
overflow: hidden;
color: #1f2d3d;
font-size: 15px;
text-overflow: ellipsis;
white-space: nowrap;
}
.mobile-module-content span {
display: block;
margin-top: 5px;
overflow: hidden;
color: #8492a6;
font-size: 12px;
text-overflow: ellipsis;
white-space: nowrap;
}
.mobile-empty {
margin-top: 12px;
padding: 24px 12px;
border: 1px dashed #c0c4cc;
border-radius: 8px;
background: #fff;
color: #909399;
text-align: center;
}
</style>
<style>
.el-badge__content {