feat(project): 添加订单管理功能并优化项目详情页面- 在项目信息页面增加订单详情对话框支持

- 实现订单查看和创建功能,包括从项目跳转到订单
- 增加订单详情抽屉组件用于展示订单信息
- 更新产品配置组件以支持项目选择后的数据填充
- 优化订单详情表单逻辑,增强项目与订单关联性- 改进合同文件上传控制,确保只有在订单保存后才允许上传
- 修复订单详情页面取消按钮行为,使其能正确返回上一页
master
chenhao 2025-11-14 15:17:45 +08:00
parent ec0523cbea
commit 3f4004c349
5 changed files with 175 additions and 35 deletions

View File

@ -87,6 +87,19 @@ export const constantRoutes = [
meta: { title: '个人中心', icon: 'user' } meta: { title: '个人中心', icon: 'user' }
} }
] ]
},
{
path: '/project/order',
component: Layout,
hidden: true,
children: [
{
path: '',
component: () => import('@/views/project/order/index'),
name: 'ProjectOrder',
meta: { title: '订单管理', icon: 'order' }
}
]
} }
] ]

View File

@ -520,7 +520,6 @@ export default {
})) }))
}; };
this.$emit('input', data); this.$emit('input', data);
this.$emit('change', data);
}, },
getData() { getData() {
return { return {

View File

@ -235,6 +235,9 @@
:project-id="selectedProjectId" :project-id="selectedProjectId"
@success="handleFormSuccess" @success="handleFormSuccess"
/> />
<!-- 订单详情对话框 -->
<order-detail :visible.sync="openOrderDialog" :title="orderDialogTitle" :order-id="currentOrderIdForDialog" :project-id="currentProjectIdForDialog" @success="handleOrderFormSuccess"></order-detail>
</div> </div>
</template> </template>
@ -242,12 +245,14 @@
import { listProject, delProject, exportProject } from "@/api/project/info"; import { listProject, delProject, exportProject } from "@/api/project/info";
import ProjectDetailDrawer from "./ProjectDetailDrawer.vue"; import ProjectDetailDrawer from "./ProjectDetailDrawer.vue";
import ProjectForm from "./ProjectForm.vue"; import ProjectForm from "./ProjectForm.vue";
import OrderDetail from "../order/OrderDetail.vue";
export default { export default {
name: "Project", name: "Project",
components: { components: {
ProjectDetailDrawer, ProjectDetailDrawer,
ProjectForm, ProjectForm,
OrderDetail,
}, },
dicts: ['bg_type', 'bg_yys', 'bg_hysy', 'project_stage'], dicts: ['bg_type', 'bg_yys', 'bg_hysy', 'project_stage'],
data() { data() {
@ -269,9 +274,15 @@ export default {
// //
drawerVisible: false, drawerVisible: false,
currentProjectId: null, currentProjectId: null,
currentProjectIdForOrder: null,
// //
projectFormVisible: false, projectFormVisible: false,
selectedProjectId: null, selectedProjectId: null,
//
openOrderDialog: false,
orderDialogTitle: "",
currentOrderIdForDialog: null,
currentProjectIdForDialog: null,
// //
queryParams: { queryParams: {
pageNum: 1, pageNum: 1,
@ -433,7 +444,15 @@ export default {
this.$modal.alertWarning("该项目已存在订单"); this.$modal.alertWarning("该项目已存在订单");
return; return;
} }
this.$modal.alert("生成订单项目ID: " + id); this.currentOrderIdForDialog = null;
this.currentProjectIdForDialog = id;
this.orderDialogTitle = "添加订单";
this.openOrderDialog = true;
},
/** 订单表单提交成功 */
handleOrderFormSuccess() {
this.openOrderDialog = false;
this.getList();
}, },
} }
}; };

View File

@ -9,7 +9,7 @@
<el-row> <el-row>
<el-col :span="16"> <el-col :span="16">
<el-form-item label="项目名称" prop="projectName"> <el-form-item label="项目名称" prop="projectName">
<el-input v-model="form.projectName" placeholder="选择项目后带入" readonly> <el-input v-model="form.projectName" placeholder="选择项目后带入" @click.native="handleSelectProject" >
<el-button slot="append" icon="el-icon-search" @click="handleSelectProject"></el-button> <el-button slot="append" icon="el-icon-search" @click="handleSelectProject"></el-button>
</el-input> </el-input>
</el-form-item> </el-form-item>
@ -218,7 +218,7 @@
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="配置信息" name="config"> <el-tab-pane label="配置信息" name="config">
<div style="max-height: 60vh; overflow-y: auto; padding: 15px;"> <div style="max-height: 60vh; overflow-y: auto; padding: 15px;">
<product-config v-model="form" :disabled="!isEdit || isOrderApprovedOrInReview" /> <product-config :value="form" @input="handleProductConfigInput" :disabled="!isProjectSelected || isOrderApprovedOrInReview" />
</div> </div>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="流转过程" name="flow"> <el-tab-pane label="流转过程" name="flow">
@ -302,15 +302,14 @@
<el-table-column label="上传时间" prop="uploadTime" width="180"></el-table-column> <el-table-column label="上传时间" prop="uploadTime" width="180"></el-table-column>
<el-table-column label="操作" width="200"> <el-table-column label="操作" width="200">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button <el-button
v-if="scope.row.id === -1 && ((canUpdate && scope.row.fileSort !== '3') || (uploadFinalFile && scope.row.fileSort === '3'))" v-if="scope.row.id === -1 && ((canUpdate && scope.row.fileSort !== '3') || (uploadFinalFile && scope.row.fileSort === '3'))"
type="text" type="text"
icon="el-icon-upload" icon="el-icon-upload"
@click="importList(scope.$index)" @click="importList(scope.$index)"
:disabled="isOrderApprovedOrInReview" :disabled="isOrderApprovedOrInReview || !form.id"
>上传 >上传
</el-button> </el-button> <el-button
<el-button
v-if="scope.row.id !== -1" v-if="scope.row.id !== -1"
type="text" type="text"
icon="el-icon-view" icon="el-icon-view"
@ -361,6 +360,7 @@
<select-customer :visible.sync="selectCustomerVisible" @customer-selected="handleCustomerSelected"/> <select-customer :visible.sync="selectCustomerVisible" @customer-selected="handleCustomerSelected"/>
<select-partner :visible.sync="selectPartnerVisible" @partner-selected="handlePartnerSelected"/> <select-partner :visible.sync="selectPartnerVisible" @partner-selected="handlePartnerSelected"/>
<select-user :visible.sync="selectUserVisible" @user-selected="handleUserSelected"/> <select-user :visible.sync="selectUserVisible" @user-selected="handleUserSelected"/>
<select-project :visible.sync="selectProjectVisible" @project-selected="handleProjectSelected"/>
</div> </div>
</template> </template>
@ -373,12 +373,14 @@
<script> <script>
import { getOrder, addOrder, updateOrder, delContractFile, uploadContractFile } from "@/api/project/order"; import { getOrder, addOrder, updateOrder, delContractFile, uploadContractFile } from "@/api/project/order";
import { getProject } from "@/api/project/info";
import { getDicts } from "@/api/system/dict/data"; import { getDicts } from "@/api/system/dict/data";
import ProductConfig from '@/views/project/info/ProductConfig.vue'; import ProductConfig from '@/views/project/info/ProductConfig.vue';
import SelectAgent from "@/views/system/agent/selectAgent.vue"; import SelectAgent from "@/views/system/agent/selectAgent.vue";
import SelectCustomer from "@/views/system/customer/selectCustomer.vue"; import SelectCustomer from "@/views/system/customer/selectCustomer.vue";
import SelectPartner from "@/views/system/partner/selectPartner.vue"; import SelectPartner from "@/views/system/partner/selectPartner.vue";
import SelectUser from "@/views/system/user/selectUser.vue"; import SelectUser from "@/views/system/user/selectUser.vue";
import SelectProject from "@/views/project/info/SelectProject.vue";
export default { export default {
name: "OrderDetail", name: "OrderDetail",
@ -388,6 +390,7 @@ export default {
SelectPartner, SelectPartner,
SelectUser, SelectUser,
ProductConfig, ProductConfig,
SelectProject,
}, },
props: { props: {
visible: { visible: {
@ -401,6 +404,10 @@ export default {
orderId: { orderId: {
type: Number, type: Number,
default: null default: null
},
projectId: {
type: Number,
default: null
} }
}, },
data() { data() {
@ -420,6 +427,8 @@ export default {
selectCustomerVisible: false, selectCustomerVisible: false,
selectPartnerVisible: false, selectPartnerVisible: false,
selectUserVisible: false, selectUserVisible: false,
selectProjectVisible: false,
isProjectSelected: false,
canUpdate: false, // canUpdate canUpdate: false, // canUpdate
uploadFinalFile: false, // uploadFinalFile uploadFinalFile: false, // uploadFinalFile
updateFile: false, // updateFile updateFile: false, // updateFile
@ -550,6 +559,11 @@ export default {
this.getDicts("currency_type").then(response => { this.currencyOptions = response.data; }); this.getDicts("currency_type").then(response => { this.currencyOptions = response.data; });
this.getDicts("company_delivery").then(response => { this.companyDeliveryOptions = response.data; }); this.getDicts("company_delivery").then(response => { this.companyDeliveryOptions = response.data; });
this.getDicts("identify_level").then(response => { this.partnerLevelOptions = response.data; }); this.getDicts("identify_level").then(response => { this.partnerLevelOptions = response.data; });
// If projectId is passed and we are in add mode (orderId is null), call handleOpen immediately
if (this.projectId && this.orderId === null) {
this.handleOpen();
}
}, },
methods: { methods: {
handleAgentSelected(agent) { handleAgentSelected(agent) {
@ -595,6 +609,7 @@ export default {
if (this.isEdit) { if (this.isEdit) {
getOrder(this.orderId).then(response => { getOrder(this.orderId).then(response => {
this.form = response.data.projectOrderInfo; this.form = response.data.projectOrderInfo;
this.isProjectSelected = true;
// //
if (!this.form.versionCode) { if (!this.form.versionCode) {
this.form.versionCode = 1; this.form.versionCode = 1;
@ -608,17 +623,25 @@ export default {
// //
if (!this.form.contractTableData) { if (!this.form.contractTableData) {
this.form.contractTableData = { this.form.contractTableData = {};
[this.form.versionCode]: [] }
};
const files = this.form.contractTableData[this.form.versionCode]; const currentVersion = String(this.form.versionCode);
const placeholders = ['商务折扣审批', '合同', '补充附件']; if (!this.form.contractTableData[currentVersion]) {
if (this.form.uploadFinalFile) { this.$set(this.form.contractTableData, currentVersion, []);
placeholders.push('已盖章合同'); }
}
placeholders.forEach((_, index) => { // Add placeholders for uploading if permitted and not already present
files.push({id: -1, fileSort: index}); 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) { if (this.uniqueVersions.length > 0) {
@ -637,6 +660,26 @@ export default {
this.form.dutyName = this.$store.state.user.name; this.form.dutyName = this.$store.state.user.name;
this.form.dutyEmail = this.$store.state.user.email; this.form.dutyEmail = this.$store.state.user.email;
this.form.dutyPhone = this.$store.state.user.phonenumber; this.form.dutyPhone = this.$store.state.user.phonenumber;
//
this.showFileFlag = true;
this.canUpdate = true;
const currentVersion = String(this.form.versionCode);
this.$set(this.form, 'contractTableData', {
[currentVersion]: [
{ id: -1, fileSort: 0 },
{ id: -1, fileSort: 1 },
{ id: -1, fileSort: 2 }
]
});
this.activeContractVersionTab = currentVersion;
// ID
if (this.projectId) {
getProject(this.projectId).then(response => {
this.handleProjectSelected(response.data.project);
}).catch(error => {
console.error('OrderDetail.vue: Error fetching project data:', error);
});
}
} }
}, },
// //
@ -645,7 +688,11 @@ export default {
}, },
// //
cancel() { cancel() {
this.handleClose(); if (this.projectId && this.orderId === null) {
this.$router.go(-1); // Navigate back to the previous page (project info)
} else {
this.handleClose();
}
}, },
// //
reset() { reset() {
@ -667,7 +714,7 @@ export default {
actualPurchaseAmount: null, actualPurchaseAmount: null,
shipmentAmount: null, shipmentAmount: null,
deliveryTime: null, deliveryTime: null,
companyDelivery: '0', companyDelivery: null,
orderChannel: null, orderChannel: null,
supplier: null, supplier: null,
dutyName: null, dutyName: null,
@ -694,6 +741,7 @@ export default {
this.activeTab = 'basic'; this.activeTab = 'basic';
this.activeContractVersionTab = null; this.activeContractVersionTab = null;
this.showFileFlag = false; this.showFileFlag = false;
this.isProjectSelected = false;
this.resetForm("form"); this.resetForm("form");
}, },
/** 提交按钮 */ /** 提交按钮 */
@ -703,8 +751,16 @@ export default {
const action = this.isEdit ? updateOrder : addOrder; const action = this.isEdit ? updateOrder : addOrder;
action(this.form).then(response => { action(this.form).then(response => {
this.msgSuccess(this.isEdit ? "修改成功" : "新增成功"); this.msgSuccess(this.isEdit ? "修改成功" : "新增成功");
this.handleClose(); if (!this.isEdit) {
this.$emit('success'); this.form.id = response.data.id; // Assuming backend returns the new order ID in response.data.id
this.isEdit = true; // Mark as edit mode
this.title = "修改订单"; // Change title
this.activeTab = 'contract'; // Switch to contract tab
this.$emit('success'); // Refresh parent list
} else {
this.handleClose();
this.$emit('success');
}
}); });
} }
}); });
@ -713,7 +769,7 @@ export default {
handleBgChange(value) { handleBgChange(value) {
this.form.industryType = null; this.form.industryType = null;
const dictType = value === 'YYS' ? 'bg_yys' : 'bg_hysy'; const dictType = value === 'YYS' ? 'bg_yys' : 'bg_hysy';
getDicts(dictType).then(response => { return getDicts(dictType).then(response => {
this.industryOptions = response.data; this.industryOptions = response.data;
}); });
}, },
@ -791,7 +847,35 @@ export default {
}, },
/** 选择项目按钮操作 */ /** 选择项目按钮操作 */
handleSelectProject() { handleSelectProject() {
this.msgWarning("选择项目功能待实现"); this.selectProjectVisible = true;
},
handleProjectSelected(projectData) {
this.form.projectName = projectData.projectName;
this.form.projectCode = projectData.projectCode;
this.form.projectId = projectData.id;
this.form.customerName = projectData.customerName;
this.form.notifier = projectData.customerUserName;
this.form.notifierPhone = projectData.customerPhone;
this.form.notifierAddress = projectData.customerAddress;
this.form.bgProperty = projectData.bgProperty;
this.form.agentName = projectData.agentName;
this.form.agentCode = projectData.agentCode;
this.form.businessPerson = projectData.contactPerson;
this.form.businessEmail = projectData.contactEmail;
this.form.businessPhone = projectData.contactPhone;
this.form.softwareProjectProductInfoList = projectData.softwareProjectProductInfoList || [];
this.form.hardwareProjectProductInfoList = projectData.hardwareProjectProductInfoList || [];
this.form.maintenanceProjectProductInfoList = projectData.maintenanceProjectProductInfoList || [];
// Handle BG change and then industry type
this.handleBgChange(projectData.bgProperty).then(() => {
this.form.industryType = projectData.industryType;
});
this.isProjectSelected = true;
this.selectProjectVisible = false;
}, },
/** 选择用户按钮操作 */ /** 选择用户按钮操作 */
handleSelectUser() { handleSelectUser() {
@ -850,6 +934,10 @@ export default {
}); });
}, },
importList(sortNum) { importList(sortNum) {
if (!this.form.id) {
this.$modal.alertWarning("请先保存订单,再上传合同信息");
return;
}
this.fileSort = sortNum; this.fileSort = sortNum;
if (sortNum === 0) { if (sortNum === 0) {
document.getElementById('uploadInput').click(); document.getElementById('uploadInput').click();
@ -895,6 +983,11 @@ export default {
}); });
}).catch(() => {}); }).catch(() => {});
}, },
handleProductConfigInput(productData) {
this.form.softwareProjectProductInfoList = productData.softwareProjectProductInfoList;
this.form.hardwareProjectProductInfoList = productData.hardwareProjectProductInfoList;
this.form.maintenanceProjectProductInfoList = productData.maintenanceProjectProductInfoList;
}
} }
}; };
</script> </script>

View File

@ -76,7 +76,7 @@
</el-table-column> </el-table-column>
<el-table-column label="合同编号" align="center" prop="orderCode" width="200" :show-overflow-tooltip="true"> <el-table-column label="合同编号" align="center" prop="orderCode" width="200" :show-overflow-tooltip="true">
<template slot-scope="scope"> <template slot-scope="scope">
<span class="link-type" @click="handleUpdate(scope.row)">{{ scope.row.orderCode }}</span> <span class="link-type" @click="handleViewOrder(scope.row)">{{ scope.row.orderCode }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="最终客户" align="center" prop="customerName" width="200" :show-overflow-tooltip="true"/> <el-table-column label="最终客户" align="center" prop="customerName" width="200" :show-overflow-tooltip="true"/>
@ -127,23 +127,28 @@
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"/> <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"/>
<!-- 订单详情对话框 --> <!-- 订单详情对话框 -->
<order-detail :visible.sync="open" :title="title" :order-id="currentOrderId" @success="getList"></order-detail> <order-detail :visible.sync="open" :title="title" :order-id="currentOrderId" :project-id="currentProjectIdForOrder" @success="getList"></order-detail>
<!-- 项目详情抽屉 --> <!-- 项目详情抽屉 -->
<project-detail-drawer :visible.sync="projectDrawerVisible" :project-id="currentProjectId" /> <project-detail-drawer :visible.sync="projectDrawerVisible" :project-id="currentProjectId" />
<!-- 订单详情抽屉 -->
<order-detail-drawer :visible.sync="orderDrawerVisible" :order-id="currentOrderId" title="订单详情" />
</div> </div>
</template> </template>
<script> <script>
import { listOrder, delOrder, exportOrder } from "@/api/project/order"; import { listOrder, delOrder, exportOrder } from "@/api/project/order";
import OrderDetail from './OrderDetail.vue'; import OrderDetail from './OrderDetail.vue';
import OrderDetailDrawer from './OrderDetailDrawer.vue';
import ProjectDetailDrawer from '../info/ProjectDetailDrawer.vue'; import ProjectDetailDrawer from '../info/ProjectDetailDrawer.vue';
export default { export default {
name: "Order", name: "Order",
components: { components: {
OrderDetail, OrderDetail,
ProjectDetailDrawer ProjectDetailDrawer,
OrderDetailDrawer
}, },
dicts: ['order_status'], dicts: ['order_status'],
data() { data() {
@ -171,8 +176,10 @@ export default {
open: false, open: false,
// ID // ID
currentOrderId: null, currentOrderId: null,
currentProjectIdForOrder: null,
// --- --- // --- ---
projectDrawerVisible: false, projectDrawerVisible: false,
orderDrawerVisible: false,
currentProjectId: null, currentProjectId: null,
// --- --- // --- ---
queryParams: { queryParams: {
@ -193,6 +200,10 @@ export default {
}, },
created() { created() {
this.getList(); this.getList();
if (this.$route.query.projectId) {
const projectId = Number(this.$route.query.projectId);
this.handleAdd(projectId);
}
}, },
methods: { methods: {
/** 查询订单管理列表 */ /** 查询订单管理列表 */
@ -235,8 +246,9 @@ export default {
this.multiple = !selection.length this.multiple = !selection.length
}, },
/** 新增按钮操作 */ /** 新增按钮操作 */
handleAdd() { handleAdd(projectId = null) {
this.currentOrderId = null; this.currentOrderId = null;
this.currentProjectIdForOrder = projectId; // Store projectId
this.open = true; this.open = true;
this.title = "添加订单"; this.title = "添加订单";
}, },
@ -301,6 +313,11 @@ export default {
this.currentProjectId = row.projectId; this.currentProjectId = row.projectId;
this.projectDrawerVisible = true; this.projectDrawerVisible = true;
}, },
/** 查看订单详情 */
handleViewOrder(row) {
this.currentOrderId = row.id;
this.orderDrawerVisible = true;
},
/** 查看审批历史 */ /** 查看审批历史 */
viewApproveLog(row) { viewApproveLog(row) {
// this.$router.push({ path: '/project/order/approveLog/' + row.id }); // this.$router.push({ path: '/project/order/approveLog/' + row.id });
@ -309,4 +326,3 @@ export default {
} }
}; };
</script> </script>