feat(order): 新增订单详情抽屉组件并优化导出逻辑- 添加 OrderDetailDrawer.vue 抽屉组件,支持订单详情展示与编辑

-优化订单导出逻辑,使用 window.location.href 直接下载文件
- 调整订单提交成功提示文案及逻辑处理- 完善订单详情页的表单验证规则和字段初始化
- 增加合同文件上传、预览、下载和删除功能
- 支持订单审批流程和合同版本管理展示- 集成项目选择、客户选择、合作伙伴选择等子组件
- 实现付款方式联动计算及付款条件自动填充
- 添加字典数据加载和动态选项渲染
- 修复订单详情中版本号为空时的默认值处理
dev_1.0.0
chenhao 2025-11-17 10:10:39 +08:00
parent b128535cfc
commit 87e199ab4b
7 changed files with 1161 additions and 4 deletions

View File

@ -0,0 +1,103 @@
<template>
<el-dialog title="选择项目" :visible.sync="internalVisible" width="800px" height="600px" append-to-body @close="handleClose">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="100px">
<el-form-item label="项目编号" prop="projectCode">
<el-input v-model="queryParams.projectCode" placeholder="请输入项目编号" clearable size="small" @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="项目名称" prop="projectName">
<el-input v-model="queryParams.projectName" placeholder="请输入项目名称" clearable size="small" @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="projectList" @row-click="handleRowClick" height="400">
<el-table-column width="55" align="center">
<template slot-scope="scope">
<el-radio :label="scope.row.id" v-model="selectedProjectId">&nbsp;</el-radio>
</template>
</el-table-column>
<el-table-column label="项目编号" align="center" prop="projectCode"/>
<el-table-column label="项目名称" align="center" prop="projectName"/>
<el-table-column label="最终客户" align="center" prop="customerName"/>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"/>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="handleConfirm"> </el-button>
<el-button @click="handleClose"> </el-button>
</div>
</el-dialog>
</template>
<script>
import { listProject } from "@/api/project/info";
export default {
name: "SelectProject",
props: {
visible: {
type: Boolean,
default: false,
},
},
data() {
return {
internalVisible: this.visible,
loading: true,
projectList: [],
total: 0,
selectedProjectId: null,
selectedProject: null,
queryParams: {
pageNum: 1,
pageSize: 10,
projectCode: null,
projectName: null,
canGenerate: true,
},
};
},
watch: {
visible(val) {
this.internalVisible = val;
if (val) {
this.getList();
}
},
},
methods: {
getList() {
this.loading = true;
listProject(this.queryParams).then(response => {
this.projectList = response.rows;
this.total = response.total;
this.loading = false;
});
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
handleClose() {
this.$emit("update:visible", false);
},
handleRowClick(row) {
this.selectedProjectId = row.id;
this.selectedProject = row;
},
handleConfirm() {
if (!this.selectedProject) {
this.msgError("请选择一个项目");
return;
}
this.$emit("project-selected", this.selectedProject);
this.handleClose();
},
},
};
</script>

View File

@ -787,8 +787,8 @@ export default {
_performSubmit() {
const action = this.isEdit ? updateOrder : addOrder;
action(this.form).then(response => {
this.msgSuccess(this.form.orderStatus === '0' ? "保存成功" : "提交成功");
if (!this.isEdit && this.form.orderStatus === '0') {
this.$modal.msgSuccess(this.isEdit ? "保存成功" : "提交成功");
if (this.isEdit ) {
// If it was a new draft, update the form to allow file uploads etc.
this.form.id = response.data.id;
this.isEdit = true;

View File

@ -0,0 +1,916 @@
<template>
<div>
<!-- 添加或修改订单管理对话框 -->
<el-drawer :title="title" :visible.sync="internalVisible" direction="rtl" size="1400px" @close="handleClose">
<div style="padding: 20px;">
<el-form ref="form" :model="form" :rules="rules" label-width="120px" :disabled="true">
<el-tabs v-model="activeTab">
<el-tab-pane label="基础信息" name="basic">
<div style="max-height: 80vh; overflow-y: auto; padding: 15px;">
<el-row>
<el-col :span="16">
<el-form-item label="项目名称" prop="projectName">
<el-input v-model="form.projectName" placeholder="选择项目后带入" readonly>
<el-button slot="append" icon="el-icon-search" @click="handleSelectProject"></el-button>
</el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="版本号" prop="versionCode">
<el-input v-model="form.versionCode" :min="1" readonly label="版本号"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目编号" prop="projectCode">
<el-input v-model="form.projectCode" placeholder="选择项目后带入" readonly/>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="最终客户" prop="customerName">
<el-input v-model="form.customerName" placeholder="选择项目后带入" readonly/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="BG" prop="bgProperty">
<el-select v-model="form.bgProperty" placeholder="请选择BG" @change="handleBgChange">
<el-option v-for="dict in bgOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="行业" prop="industryType">
<el-select v-model="form.industryType" placeholder="请先选择BG">
<el-option v-for="dict in industryOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="代表处" prop="agentName">
<el-input v-model="form.agentName" placeholder="选择项目后带入" readonly/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="进货商接口人" prop="businessPerson">
<el-input v-model="form.businessPerson" placeholder="请输入进货商接口人"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Email" prop="businessEmail">
<el-input v-model="form.businessEmail" placeholder="请输入Email"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="联系方式" prop="businessPhone">
<el-input v-model="form.businessPhone" placeholder="请输入联系方式"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="合同编号" prop="orderCode">
<el-input v-model="form.orderCode" placeholder="自动生成" readonly/>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="执行单截止时间" prop="orderEndTime">
<el-date-picker v-model="form.orderEndTime" type="date" value-format="yyyy-MM-dd" placeholder="审批完成后自动计算" disabled></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="币种" prop="currencyType">
<el-select v-model="form.currencyType" placeholder="请选择币种">
<el-option v-for="dict in currencyOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col
v-if="(form.processTemplate=='1' ||(form.processTemplate!='1' &&( form.orderStatus=='1'||form.orderStatus=='2')))"
:span="8">
<el-form-item label="总代进货金额" prop="actualPurchaseAmount">
<el-input v-model="form.actualPurchaseAmount" readonly/>
</el-form-item>
</el-col>
<el-col :span="(form.processTemplate=='1' ||(form.processTemplate!='1' &&( form.orderStatus=='1'||form.orderStatus=='2')))?8:16"
>
<el-form-item label="总代出货金额" prop="shipmentAmount">
<el-input v-model="form.shipmentAmount" placeholder="请输入金额"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="要求到货时间" prop="deliveryTime">
<el-date-picker clearable v-model="form.deliveryTime" type="date" value-format="yyyy-MM-dd"
placeholder="选择要求到货时间">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="公司直发" prop="companyDelivery">
<el-select v-model="form.companyDelivery" placeholder="请选择">
<el-option v-for="dict in companyDeliveryOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="下单通路" prop="orderChannel">
<el-select v-model="form.orderChannel" placeholder="请选择" @change="handleChannelChange">
<el-option label="总代" value="1"></el-option>
<el-option label="直签" value="2"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8" v-if="form.orderChannel == '1'">
<el-form-item label="总代" prop="zd">
<el-input value="广州佳都技术有限公司" readonly/>
</el-form-item>
</el-col>
<el-col :span="form.orderChannel == '2' ? 16 : 8">
<el-form-item label="供货商" prop="supplier">
<el-input v-model="form.supplier"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="汇智责任人" prop="dutyName">
<el-input v-model="form.dutyName" placeholder="请选择责任人" @click.native=" openSelectPeople()">
<el-button slot="append" icon="el-icon-search" @click.native=" openSelectPeople()"></el-button>
</el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Email" prop="dutyEmail">
<el-input v-model="form.dutyEmail" placeholder="请输入Email"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="联系方式" prop="dutyPhone">
<el-input v-model="form.dutyPhone" placeholder="请输入联系方式"/>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="进货商" prop="partnerName">
<el-input v-model="form.partnerName" placeholder="请选择进货商" @click.native="openSelectPartner">
<el-button slot="append" icon="el-icon-search" @click.native="openSelectPartner"></el-button>
</el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="进货商类型" prop="level">
<el-select v-model="form.level" placeholder="选择后带入" disabled>
<el-option v-for="dict in partnerLevelOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="进货商联系人" prop="partnerUserName">
<el-input v-model="form.partnerUserName" placeholder="请输入进货商联系人"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Email" prop="partnerEmail">
<el-input v-model="form.partnerEmail" placeholder="请输入Email"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="联系方式" prop="partnerPhone">
<el-input v-model="form.partnerPhone" placeholder="请输入联系方式"/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="收货地址" prop="notifierAddress">
<el-input v-model="form.notifierAddress" placeholder="请输入收货地址"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="收货人" prop="notifier">
<el-input v-model="form.notifier" placeholder="请输入收货人"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="Email" prop="notifierEmail">
<el-input v-model="form.notifierEmail" placeholder="请输入Email"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="联系方式" prop="notifierPhone">
<el-input v-model="form.notifierPhone" placeholder="请输入联系方式"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="付款方式" prop="paymentMethod">
<el-select v-model="form.paymentMethod" placeholder="请选择付款方式" @change="handlePaymentMethodChange">
<el-option v-for="item in paymentMethodOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="付款比例" prop="paymentRatio">
<el-input-number v-model="form.paymentRatio" :min="0" :max="100" placeholder="请输入付款比例" @change="updatePaymentDescription"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="付款条件" prop="paymentDescription">
<el-input v-model="form.paymentDescription" type="textarea" :rows="3" readonly/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="其他特别说明" prop="remark">
<el-input v-model="form.remark" placeholder="请输入其他特别说明"/>
</el-form-item>
</el-col>
</el-row>
</div>
</el-tab-pane>
<el-tab-pane label="配置信息" name="config">
<div style="max-height: 80vh; overflow-y: auto; padding: 15px;">
<product-config v-model="form" :disabled="true" />
</div>
</el-tab-pane>
<el-tab-pane label="流转过程" name="flow">
<div style="max-height: 80vh; overflow-y: auto; padding: 15px;">
<el-tabs v-model="activeVersionTab" type="card" v-if="uniqueVersions.length > 0">
<el-tab-pane
v-for="version in uniqueVersions"
:key="version"
:label="'版本号Rev.' + version"
:name="version">
<el-timeline>
<el-timeline-item
v-for="log in groupedApproveLogs[version]"
:key="log.id"
:timestamp="log.approveTime"
placement="top">
<el-card>
<h4>{{ log.approveOpinion }}</h4>
<p><b>操作人:</b> {{ log.approveUserName }} ({{ log.roleName }})</p>
<p><b>接收人:</b> {{ log.nextAllApproveUserName }}</p>
<p><b>审批状态:</b> <el-tag :type="log.approveStatus == '3' ? 'success' : log.approveStatus == '2' ? 'danger' : 'info'">{{ formatApproveStatus(log.approveStatus) }}</el-tag></p>
</el-card>
</el-timeline-item>
</el-timeline>
</el-tab-pane>
</el-tabs>
<div v-else></div>
</div>
</el-tab-pane>
<el-tab-pane label="合同信息" name="contract">
<div style="max-height: 80vh; overflow-y: auto; padding: 15px;">
<div class="row">
<div class="col-sm-12">
<div class="tabs-container">
<div class="col-xs-12" style="display: flex; justify-content: flex-end; padding: 5px 20px;" v-if="showFileFlag">
<el-button type="text" icon="el-icon-download" @click="downloadTem" :disabled="false" style="margin-bottom: 5px;">
下载模板
</el-button>
</div>
<el-tabs v-model="activeContractVersionTab" type="card" v-if="uniqueContractVersions.length > 0">
<el-tab-pane
v-for="version in uniqueContractVersions"
:key="version"
:label="'版本号Rev.' + version"
:name="version">
</el-tab-pane>
</el-tabs>
<div v-if="uniqueContractVersions.length > 0">
<div v-if="currentContractBakFile"
style="display: flex; justify-content: space-between; padding: 5px 20px;">
<h3>历史订单记录</h3>
<span class="file-view"
@click="previewFile(currentContractBakFile.filePath, currentContractBakFile.fileName)">
{{ form.projectName + 'Rev.' + activeContractVersionTab }}
</span>
</div>
<div class="panel-body" v-if="showFileFlag">
<h3 style="margin-bottom: 5px">附件信息</h3>
<el-table :data="currentContractFiles" style="width: 100%;def-border-radius: 8px;overflow: hidden;margin-top: 10px;">
<el-table-column label="序号" type="index" width="50"></el-table-column>
<el-table-column label="类型" width="150">
<template slot-scope="scope">
{{ scope.$index + 1 == 1 ? '商务折扣审批' : scope.$index + 1 == 2 ? '合同' : '补充附件' }}
</template>
</el-table-column>
<el-table-column label="附件名称">
<template slot-scope="scope">
<span v-if="scope.row.id !== -1">{{ scope.row.fileName }}</span>
<span v-else>{{ file_log_arr[scope.$index] }}</span>
</template>
</el-table-column>
<el-table-column label="上传人" prop="uploadUserName" width="120"></el-table-column>
<el-table-column label="上传时间" prop="uploadTime" width="180"></el-table-column>
<el-table-column label="操作" width="200">
<template slot-scope="scope">
<!-- <el-button-->
<!-- v-if="scope.row.id === -1 && ((canUpdate && scope.row.fileSort !== '3') || (uploadFinalFile && scope.row.fileSort === '3'))"-->
<!-- type="text"-->
<!-- icon="el-icon-upload"-->
<!-- @click="importList(scope.$index)"-->
<!-- :disabled="isOrderApprovedOrInReview"-->
<!-- >上传-->
<!-- </el-button>-->
<el-button
v-if="scope.row.id !== -1"
type="text"
icon="el-icon-view"
:disabled="false"
@click="previewFile(scope.row.filePath, scope.row.fileName)"
>预览
</el-button>
<el-button
v-if="scope.row.id !== -1"
type="text"
icon="el-icon-download"
:disabled="false"
@click="downFile(scope.row.filePath, scope.row.fileName)"
>下载
</el-button>
<el-button
v-if="scope.row.id !== -1 && activeContractVersionTab == form.versionCode && ((canUpdate && scope.row.fileSort !== '3') || (uploadFinalFile && scope.row.fileSort === '3'))"
type="text"
icon="el-icon-delete"
@click="delUploadRow(scope.$index, scope.row.id)"
:disabled="isOrderApprovedOrInReview"
>删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<div v-else></div>
</div>
</div>
<input id="uploadInput" type="file" accept=".pdf,.jpg,.png" style="display: none" @change="handleUploadFile"/>
<input id="uploadInput1" type="file" accept=".pdf,.jpg,.png" style="display: none" @change="handleUploadFile"/>
<input id="uploadInput2" type="file" accept=".zip,.rar,.jpg,.png" style="display: none" @change="handleUploadFile"/>
<input id="fileSort" type="hidden" v-model="fileSort"/>
</div>
</div>
</el-tab-pane>
</el-tabs>
</el-form>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="cancel"> </el-button>
</div>
</el-drawer>
<select-agent :visible.sync="selectAgentVisible" @agent-selected="handleAgentSelected"/>
<select-customer :visible.sync="selectCustomerVisible" @customer-selected="handleCustomerSelected"/>
<select-partner :visible.sync="selectPartnerVisible" @partner-selected="handlePartnerSelected"/>
<select-user :visible.sync="selectUserVisible" @user-selected="handleUserSelected"/>
</div>
</template>
<style scoped>
.el-form-item .el-select,
.el-form-item .el-date-picker {
width: 100%;
}
</style>
<script>
import { getOrder, addOrder, updateOrder, delContractFile, uploadContractFile } from "@/api/project/order";
import { getDicts } from "@/api/system/dict/data";
import ProductConfig from '@/views/project/info/ProductConfig.vue';
import SelectAgent from "@/views/system/agent/selectAgent.vue";
import SelectCustomer from "@/views/system/customer/selectCustomer.vue";
import SelectPartner from "@/views/system/partner/selectPartner.vue";
import SelectUser from "@/views/system/user/selectUser.vue";
export default {
name: "OrderDetailDrawer",
components: {
SelectAgent,
SelectCustomer,
SelectPartner,
SelectUser,
ProductConfig,
},
props: {
visible: {
type: Boolean,
default: false
},
title: {
type: String,
default: ""
},
orderId: {
type: Number,
default: null
}
},
data() {
return {
//
form: {},
approveLogList: [],
activeVersionTab: null,
activeContractVersionTab: null, // Tab
showFileFlag: false, //
uploadInput: null, //
fileSort: null, //
file_log_arr: [ "(请上传商务折扣审批邮件信息).pdf/.jpg/.png","(请上传合同信息).pdf/.jpg/.png", "(补充附件).zip/.rar/.jpg/.png","(请上传已盖章合同信息).pdf/.jpg/.png"],
//
internalVisible: this.visible,
selectAgentVisible: false,
selectCustomerVisible: false,
selectPartnerVisible: false,
selectUserVisible: false,
canUpdate: false, // canUpdate
uploadFinalFile: false, // uploadFinalFile
updateFile: false, // updateFile
// Tab
activeTab: 'basic',
//
bgOptions: [],
industryOptions: [],
currencyOptions: [],
companyDeliveryOptions: [],
partnerLevelOptions: [],
paymentMethodOptions: [],
//
rules: {
projectName: [{ required: true, message: "项目名称不能为空", trigger: "blur" }],
versionCode: [{ required: true, message: "版本号不能为空", trigger: "blur" }],
projectCode: [{ required: true, message: "项目编号不能为空", trigger: "blur" }],
customerName: [{ required: true, message: "最终客户不能为空", trigger: "blur" }],
bgProperty: [{ required: true, message: "BG不能为空", trigger: "change" }],
industryType: [{ required: true, message: "行业不能为空", trigger: "change" }],
agentName: [{ required: true, message: "代表处不能为空", trigger: "blur" }],
businessPerson: [{ required: true, message: "进货商接口人不能为空", trigger: "blur" }],
businessPhone: [{ required: true, message: "联系方式不能为空", trigger: "blur" }],
currencyType: [{ required: true, message: "币种不能为空", trigger: "change" }],
shipmentAmount: [{ required: true, message: "总代出货金额不能为空", trigger: "blur" }],
deliveryTime: [{ required: true, message: "要求到货时间不能为空", trigger: "blur" }],
orderChannel: [{ required: true, message: "下单通路不能为空", trigger: "change" }],
supplier: [{ required: true, message: "供货商不能为空", trigger: "blur" }],
dutyPhone: [{ required: true, message: "联系方式不能为空", trigger: "blur" }],
partnerName: [{ required: true, message: "进货商不能为空", trigger: "blur" }],
level: [{ required: true, message: "进货商类型不能为空", trigger: "change" }],
partnerPhone: [{ required: true, message: "联系方式不能为空", trigger: "blur" }],
notifierAddress: [{ required: true, message: "收货地址不能为空", trigger: "blur" }],
notifierPhone: [{ required: true, message: "联系方式不能为空", trigger: "blur" }],
paymentMethod: [{ required: true, message: "付款方式不能为空", trigger: "change" }],
paymentRatio: [{ required: true, message: "付款比例不能为空", trigger: "blur" }],
}
};
},
computed: {
isEdit() {
return this.orderId != null;
},
isOrderApprovedOrInReview() {
return this.form.orderStatus === '1' || this.form.orderStatus === '2';
},
uniqueVersions() {
if (!this.approveLogList || this.approveLogList.length === 0) {
return [];
}
const versions = [...new Set(this.approveLogList.map(log => log.extendField1))];
return versions.sort((a, b) => b - a); //
},
groupedApproveLogs() {
if (!this.approveLogList || this.approveLogList.length === 0) {
return {};
}
return this.approveLogList.reduce((acc, log) => {
const version = log.extendField1;
if (!acc[version]) {
acc[version] = [];
}
acc[version].push(log);
return acc;
}, {});
},
uniqueContractVersions() {
const versions = new Set();
if (this.form.contractTableData) {
Object.keys(this.form.contractTableData).forEach(version => {
if (version) versions.add(String(version));
});
}
if (this.orderBakFile) {
Object.keys(this.orderBakFile).forEach(version => {
if (version) versions.add(String(version));
});
}
//
if (this.form.versionCode) {
versions.add(String(this.form.versionCode));
}
return Array.from(versions).sort((a, b) => Number(b) - Number(a)); //
},
groupedContractFiles() {
const grouped = {};
if (this.form.contractTableData) {
for (const version in this.form.contractTableData) {
if (!grouped[version]) {
grouped[version] = { files: [], bakFile: null };
}
grouped[version].files = this.form.contractTableData[version];
}
}
if (this.orderBakFile) {
for (const version in this.orderBakFile) {
if (!grouped[version]) {
grouped[version] = { files: [], bakFile: null };
}
grouped[version].bakFile = this.orderBakFile[version];
}
}
return grouped;
},
currentContractFiles() {
if (!this.activeContractVersionTab || !this.groupedContractFiles[this.activeContractVersionTab]) {
return [];
}
return this.groupedContractFiles[this.activeContractVersionTab].files;
},
currentContractBakFile() {
if (!this.activeContractVersionTab || !this.groupedContractFiles[this.activeContractVersionTab]) {
return null;
}
return this.groupedContractFiles[this.activeContractVersionTab].bakFile;
}
},
watch: {
visible(val) {
this.internalVisible = val;
if (val) {
this.handleOpen();
}
}
},
created() {
this.getDicts("bg_type").then(response => { this.bgOptions = response.data; });
this.getDicts("currency_type").then(response => { this.currencyOptions = response.data; });
this.getDicts("company_delivery").then(response => { this.companyDeliveryOptions = response.data; });
this.getDicts("identify_level").then(response => { this.partnerLevelOptions = response.data; });
},
methods: {
handleAgentSelected(agent) {
this.form.agentName = agent.agentName;
this.form.agentCode = agent.agentCode;
this.selectAgentVisible = false;
},
openSelectCustomer() {
this.selectCustomerVisible = true;
},
handleCustomerSelected(customer) {
this.form.customerName = customer.customerName;
this.form.customerCode = customer.customerCode;
this.form.customerUserName = customer.contactPerson;
this.form.customerPhone = customer.contactPhone;
this.selectCustomerVisible = false;
},
openSelectPartner() {
this.selectPartnerVisible = true;
},
handlePartnerSelected(partner) {
this.form.partnerName = partner.partnerName;
this.form.partnerCode = partner.partnerCode;
this.form.partnerUserName = partner.contactPerson;
this.form.level = partner.level;
this.form.partnerPhone = partner.contactPhone;
this.form.partnerEmail = partner.contactEmail;
this.selectPartnerVisible = false;
},
openSelectPeople() {
this.selectUserVisible = true;
},
handleUserSelected(user) {
this.form.dutyName = user.userName;
this.form.duty = user.userId;
this.form.dutyPhone = user.phonenumber;
this.form.dutyEmail = user.email;
this.selectUserVisible = false;
},
//
handleOpen() {
this.reset();
if (this.isEdit) {
getOrder(this.orderId).then(response => {
this.form = {...response.data.projectOrderInfo}
//
if (!this.form.versionCode) {
this.form.versionCode = 1;
}
this.approveLogList=response.data.approveLog;
this.orderBakFile = response.data.orderBakFile || {};
this.showFileFlag = response.data.showFileFlag || false;
this.canUpdate = response.data.canUpdate || false; // response.data
this.uploadFinalFile = response.data.uploadFinalFile || false; // response.data
this.updateFile = response.data.updateFile || false; // response.data
//
if (!this.form.contractTableData) {
this.form.contractTableData = {};
}
const currentVersion = String(this.form.versionCode);
if (!this.form.contractTableData[currentVersion]) {
this.$set(this.form.contractTableData, currentVersion, []);
}
// Add placeholders for uploading if permitted and not already present
const files = this.form.contractTableData[currentVersion];
const existingSorts = new Set(files.map(f => String(f.fileSort)));
if (this.canUpdate) {
if (!existingSorts.has('0')) files.push({id: -1, fileSort: 0});
if (!existingSorts.has('1')) files.push({id: -1, fileSort: 1});
if (!existingSorts.has('2')) files.push({id: -1, fileSort: 2});
}
if (this.uploadFinalFile) {
if (!existingSorts.has('3')) files.push({id: -1, fileSort: 3});
}
if (this.uniqueVersions.length > 0) {
this.activeVersionTab = String(this.uniqueVersions[0]); //
}
if (this.uniqueContractVersions.length > 0) {
this.activeContractVersionTab = String(this.uniqueContractVersions[0]); //
}
//
this.handleBgChange(this.form.bgProperty);
this.handleChannelChange(this.form.orderChannel);
// change
if (response.data.projectOrderInfo.paymentMethod) {
this.form.paymentMethod = response.data.projectOrderInfo.paymentMethod;
this.handlePaymentMethodChange(response.data.projectOrderInfo.paymentMethod);
}
// handlePaymentMethodChange
if (response.data.projectOrderInfo.paymentRatio) {
this.form.paymentRatio = response.data.projectOrderInfo.paymentRatio;
}
if (response.data.projectOrderInfo.paymentDescription) {
this.form.paymentDescription = response.data.projectOrderInfo.paymentDescription;
}
});
} else {
//
this.form.dutyName = this.$store.state.user.name;
this.form.dutyEmail = this.$store.state.user.email;
this.form.dutyPhone = this.$store.state.user.phonenumber;
}
},
//
handleClose() {
this.$emit('update:visible', false);
},
//
cancel() {
this.handleClose();
},
//
reset() {
this.form = {
id: null,
projectName: null,
versionCode: 1,
projectCode: null,
customerName: null,
bgProperty: null,
industryType: null,
agentName: null,
businessPerson: null,
businessEmail: null,
businessPhone: null,
orderCode: null,
orderEndTime: null,
currencyType: null,
actualPurchaseAmount: null,
shipmentAmount: null,
deliveryTime: null,
companyDelivery: '0',
orderChannel: null,
supplier: null,
dutyName: null,
dutyEmail: null,
dutyPhone: null,
partnerName: null,
level: null,
partnerUserName: null,
partnerEmail: null,
partnerPhone: null,
notifierAddress: null,
notifier: null,
notifierEmail: null,
notifierPhone: null,
paymentMethod: null,
paymentRatio: 0,
paymentDescription: null,
remark: null,
softwareProjectProductInfoList: [],
hardwareProjectProductInfoList: [],
maintenanceProjectProductInfoList: []
};
this.orderBakFile = {};
this.activeTab = 'basic';
this.activeContractVersionTab = null;
this.showFileFlag = false;
this.resetForm("form");
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
const action = this.isEdit ? updateOrder : addOrder;
action(this.form).then(response => {
this.msgSuccess(this.isEdit ? "修改成功" : "新增成功");
this.handleClose();
this.$emit('success');
});
}
});
},
/** BG改变事件 */
handleBgChange(value) {
this.form.industryType = null;
const dictType = value === 'YYS' ? 'bg_yys' : 'bg_hysy';
getDicts(dictType).then(response => {
this.industryOptions = response.data;
});
},
/** 下单通路改变事件 */
handleChannelChange(value) {
this.form.supplier = value === '1' ? '广州佳都技术有限公司' : '紫光汇智信息技术有限公司';
this.form.paymentMethod = null;
this.form.paymentRatio = 0;
this.form.paymentDescription = null;
if (value === '1') { //
this.paymentMethodOptions = [
{ label: '全款支付,无需预付款', value: '1-1' },
{ label: '全款支付,需单独备货生产,预付订单总货款百分比', value: '1-2' }
];
} else if (value === '2') { //
this.paymentMethodOptions = [
{ label: '全款支付', value: '2-1' },
{ label: '全款支付,需单独备货生产,预付订单总货款百分比', value: '2-2' },
{ label: '商业汇票支付,预付订单总货款百分比', value: '2-3' }
];
} else {
this.paymentMethodOptions = [];
}
},
/** 付款方式改变事件 */
handlePaymentMethodChange(value) {
const descriptionTemplates = {
'1-2': '总代预付{ratio}%订单金额作为备货押金后开始备货生产备货完成供货商发起付款通知后总代需1个月内支付尾款完成提货否则备货押金不予退还。',
'2-2': '进货商预付{ratio}%订单金额作为备货押金后开始备货生产备货完成供货商发起付款通知后进货商需3个工作日内付全部剩余款项即可享受订单约定的现金折扣。',
'2-3': '进货商预付{ratio}%订单金额作为备货押金后开始备货生产备货完成供货商发起付款通知后供货商需在1个月内提交剩余款项额度的商业汇票完成提货否则备货押金不予退还。'
};
let description = '';
let paymentRatio = 0;
switch (value) {
case '1-1':
description = '备货完成供货商发起付款通知后,总代按照订单金额支付全款。';
paymentRatio = 100;
break;
case '1-2':
paymentRatio = 30;
description = descriptionTemplates['1-2'].replace('{ratio}', paymentRatio);
break;
case '2-1':
description = '备货完成供货商发起付款通知后进货商需3个工作日内付订单全部款项即可享受订单约定的现金折扣。';
paymentRatio = 100;
break;
case '2-2':
paymentRatio = 30;
description = descriptionTemplates['2-2'].replace('{ratio}', paymentRatio);
break;
case '2-3':
paymentRatio = 30;
description = descriptionTemplates['2-3'].replace('{ratio}', paymentRatio);
break;
}
this.form.paymentDescription = description;
this.form.paymentRatio = paymentRatio;
},
/** 更新付款条件描述 */
updatePaymentDescription() {
const paymentMethod = this.form.paymentMethod;
const ratio = this.form.paymentRatio;
const descriptionTemplates = {
'1-2': '总代预付{ratio}%订单金额作为备货押金后开始备货生产备货完成供货商发起付款通知后总代需1个月内支付尾款完成提货否则备货押金不予退还。',
'2-2': '进货商预付{ratio}%订单金额作为备货押金后开始备货生产备货完成供货商发起付款通知后进货商需3个工作日内付全部剩余款项即可享受订单约定的现金折扣。',
'2-3': '进货商预付{ratio}%订单金额作为备货押金后开始备货生产备货完成供货商发起付款通知后供货商需在1个月内提交剩余款项额度的商业汇票完成提货否则备货押金不予退还。'
};
if (descriptionTemplates[paymentMethod]) {
this.form.paymentDescription = descriptionTemplates[paymentMethod].replace('{ratio}', ratio);
}
},
/** 选择项目按钮操作 */
handleSelectProject() {
this.msgWarning("选择项目功能待实现");
},
/** 选择用户按钮操作 */
handleSelectUser() {
this.msgWarning("选择用户功能待实现");
},
/** 选择合作伙伴按钮操作 */
handleSelectPartner() {
this.msgWarning("选择合作伙伴功能待实现");
},
formatApproveStatus(status) {
const statusMap = {
'1': '提交审批',
'2': '驳回',
'3': '批准'
};
return statusMap[status] || '提交审批';
},
downloadTem() {
if (!this.form.orderChannel) {
this.$modal.alertWarning("请先选择下单通路");
return;
}
const orderId = this.form.id;
window.location.href = process.env.VUE__APP_BASE_API + `/project/order/contract/export?orderId=${orderId}`;
},
previewFile(filePath, fileName) {
if (filePath.endsWith(".png") || filePath.endsWith(".jpg") || filePath.endsWith(".jpeg") || filePath.endsWith(".pdf")) {
const url = process.env.VUE_APP_BASE_API + `/project/order/file/view?filePath=${encodeURIComponent(filePath)}&fileName=${encodeURIComponent(fileName)}`;
window.open(url);
} else {
this.downFile(filePath, fileName);
}
},
downFile(filePath, fileName) {
window.location.href = process.env.VUE_APP_BASE_API + `/project/order/file/download?filePath=${encodeURIComponent(filePath)}&fileName=${encodeURIComponent(fileName)}`;
},
handleUploadFile(event) {
const file = event.target.files[0];
if (!file) return;
const formData = new FormData();
formData.append('file', file);
formData.append('orderId', this.form.id);
formData.append('versionCode', this.form.versionCode);
formData.append('fileSort', this.fileSort);
uploadContractFile(formData).then(response => {
this.$modal.msgSuccess('导入成功');
this.addFile(response.data);
// 便
event.target.value = '';
}).catch(() => {
this.$modal.msgError('导入失败');
event.target.value = '';
});
},
importList(sortNum) {
this.fileSort = sortNum;
if (sortNum === 0) {
document.getElementById('uploadInput').click();
} else if (sortNum === 1) {
document.getElementById('uploadInput1').click();
} else {
document.getElementById('uploadInput2').click();
}
},
addFile(data) {
const sortNum = data.fileSort;
if (!this.groupedContractFiles[String(this.form.versionCode)]) {
this.$set(this.groupedContractFiles, String(this.form.versionCode), {files: [], bakFile: null});
}
const currentVersionFiles = this.groupedContractFiles[String(this.form.versionCode)].files;
const fileIndex = currentVersionFiles.findIndex(file => file.fileSort === sortNum);
if (fileIndex !== -1) {
this.$set(currentVersionFiles, fileIndex, data);
} else {
currentVersionFiles.push(data);
}
},
delUploadRow(sortNum, id) {
this.$modal.confirm("确定删除该文件吗?").then(() => {
delContractFile(id).then(() => {
this.$modal.msgSuccess("删除成功");
//
const currentVersionFiles = this.groupedContractFiles[String(this.activeContractVersionTab)].files;
const fileIndex = currentVersionFiles.findIndex(file => file.id === id);
if (fileIndex !== -1) {
this.$set(currentVersionFiles, fileIndex, {
id: -1,
fileSort: sortNum,
fileName: this.file_log_arr[sortNum],
uploadUserName: '',
uploadTime: '',
filePath: ''
});
}
}).catch(() => {
this.$modal.msgError("删除失败");
});
}).catch(() => {});
},
}
};
</script>

View File

@ -0,0 +1,130 @@
<template>
<el-dialog title="确认并提交订单" :visible.sync="dialogVisible" width="520px" @close="handleClose">
<el-form :model="form" ref="form" label-width="80px">
<el-form-item label="合同类型" prop="processTemplate" :rules="{ required: true, message: '请选择合同类型', trigger: 'change' }">
<el-select v-model="form.processTemplate" placeholder="请选择" @change="handleTemplateChange">
<el-option
v-for="item in templateOptions"
:key="item.v"
:label="item.n"
:value="item.v">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="流程类型" prop="processType" :rules="{ required: true, message: '请选择流程类型', trigger: 'change' }">
<el-select v-model="form.processType" placeholder="请选择">
<el-option
v-for="item in typeOptions"
:key="item.v"
:label="item.n"
:value="item.v">
</el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="handleClose"> </el-button>
<el-button type="primary" @click="handleSubmit"> </el-button>
</div>
</el-dialog>
</template>
<script>
export default {
name: "SelectCommitType",
props: {
visible: {
type: Boolean,
default: false,
},
orderChannel: {
type: String,
default: null,
},
},
data() {
return {
form: {
processTemplate: null,
processType: null,
},
allOptions: [
{
n: '销售合同',
v: '0',
s: [{ n: '电子订单', v: '0' }, { n: '纸质合同', v: '1' }]
},
{
n: '定制开发合同',
v: '2',
s: [{ n: '纸质合同', v: '1' }]
}
],
totalAgentOptions: [{
n: '总代合同',
v: '1',
s: [{ n: '电子订单', v: '0' }, { n: '纸质合同', v: '1' }]
}],
templateOptions: [],
typeOptions: [],
};
},
computed: {
dialogVisible: {
get() {
return this.visible;
},
set(val) {
this.$emit('update:visible', val);
},
},
},
watch: {
visible(val) {
if (val) {
this.resetForm();
this.initOptions();
}
},
},
methods: {
initOptions() {
if (this.orderChannel === '1') {
this.templateOptions = this.totalAgentOptions;
} else {
this.templateOptions = this.allOptions;
}
},
handleTemplateChange(value) {
this.form.processType = null;
const selectedTemplate = this.templateOptions.find(opt => opt.v === value);
this.typeOptions = selectedTemplate ? selectedTemplate.s : [];
},
handleSubmit() {
this.$refs.form.validate(valid => {
if (valid) {
this.$emit('commit-type-selected', this.form);
this.dialogVisible = false;
}
});
},
handleClose() {
this.dialogVisible = false;
},
resetForm() {
this.form.processTemplate = null;
this.form.processType = null;
this.typeOptions = [];
if (this.$refs.form) {
this.$refs.form.resetFields();
}
}
}
};
</script>
<style scoped>
.el-select {
width: 100%;
}
</style>

View File

@ -286,8 +286,11 @@ export default {
this.exportLoading = true;
return exportOrder(queryParams);
}).then(response => {
this.download(response.msg);
this.exportLoading = false;
console.log("response:", response)
const fileName = response.msg;
window.location.href = process.env.VUE_APP_BASE_API + "/common/download?fileName=" + encodeURIComponent(fileName) + "&delete=" + true;
})
},
/** 排序触发事件 */

View File

@ -193,4 +193,6 @@ public class ProjectInfo extends BaseEntity
private List<ProjectWorkProgress> projectWorkProgressList;
private ProjectPocInfo projectPocInfo;
private Boolean availableForOrder;
}

View File

@ -173,6 +173,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="serverConfiguration != null and serverConfiguration != ''"> and t1.server_configuration = #{serverConfiguration}</if>
<if test="keyProblem != null and keyProblem != ''"> and t1.key_problem = #{keyProblem}</if>
<if test="projectDesc != null and projectDesc != ''"> and t1.project_desc = #{projectDesc}</if>
<if test="canGenerate != null and canGenerate == true">
and not exists (select 1 from project_order_info t6 where t6.project_id = t1.id)
</if>
${params.dataScope}
</where>
order by t1.project_code desc