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

- 实现订单查看和创建功能,包括从项目跳转到订单
- 增加订单详情抽屉组件用于展示订单信息
- 更新产品配置组件以支持项目选择后的数据填充
- 优化订单详情表单逻辑,增强项目与订单关联性- 改进合同文件上传控制,确保只有在订单保存后才允许上传
- 修复订单详情页面取消按钮行为,使其能正确返回上一页
dev_1.0.0
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' }
}
]
},
{
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('change', data);
},
getData() {
return {

View File

@ -235,6 +235,9 @@
:project-id="selectedProjectId"
@success="handleFormSuccess"
/>
<!-- 订单详情对话框 -->
<order-detail :visible.sync="openOrderDialog" :title="orderDialogTitle" :order-id="currentOrderIdForDialog" :project-id="currentProjectIdForDialog" @success="handleOrderFormSuccess"></order-detail>
</div>
</template>
@ -242,12 +245,14 @@
import { listProject, delProject, exportProject } from "@/api/project/info";
import ProjectDetailDrawer from "./ProjectDetailDrawer.vue";
import ProjectForm from "./ProjectForm.vue";
import OrderDetail from "../order/OrderDetail.vue";
export default {
name: "Project",
components: {
ProjectDetailDrawer,
ProjectForm,
OrderDetail,
},
dicts: ['bg_type', 'bg_yys', 'bg_hysy', 'project_stage'],
data() {
@ -269,9 +274,15 @@ export default {
//
drawerVisible: false,
currentProjectId: null,
currentProjectIdForOrder: null,
//
projectFormVisible: false,
selectedProjectId: null,
//
openOrderDialog: false,
orderDialogTitle: "",
currentOrderIdForDialog: null,
currentProjectIdForDialog: null,
//
queryParams: {
pageNum: 1,
@ -433,7 +444,15 @@ export default {
this.$modal.alertWarning("该项目已存在订单");
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-col :span="16">
<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-input>
</el-form-item>
@ -218,7 +218,7 @@
</el-tab-pane>
<el-tab-pane label="配置信息" name="config">
<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>
</el-tab-pane>
<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="操作" 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
<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 || !form.id"
>上传
</el-button> <el-button
v-if="scope.row.id !== -1"
type="text"
icon="el-icon-view"
@ -361,6 +360,7 @@
<select-customer :visible.sync="selectCustomerVisible" @customer-selected="handleCustomerSelected"/>
<select-partner :visible.sync="selectPartnerVisible" @partner-selected="handlePartnerSelected"/>
<select-user :visible.sync="selectUserVisible" @user-selected="handleUserSelected"/>
<select-project :visible.sync="selectProjectVisible" @project-selected="handleProjectSelected"/>
</div>
</template>
@ -373,12 +373,14 @@
<script>
import { getOrder, addOrder, updateOrder, delContractFile, uploadContractFile } from "@/api/project/order";
import { getProject } from "@/api/project/info";
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";
import SelectProject from "@/views/project/info/SelectProject.vue";
export default {
name: "OrderDetail",
@ -388,6 +390,7 @@ export default {
SelectPartner,
SelectUser,
ProductConfig,
SelectProject,
},
props: {
visible: {
@ -401,6 +404,10 @@ export default {
orderId: {
type: Number,
default: null
},
projectId: {
type: Number,
default: null
}
},
data() {
@ -420,6 +427,8 @@ export default {
selectCustomerVisible: false,
selectPartnerVisible: false,
selectUserVisible: false,
selectProjectVisible: false,
isProjectSelected: false,
canUpdate: false, // canUpdate
uploadFinalFile: false, // uploadFinalFile
updateFile: false, // updateFile
@ -550,6 +559,11 @@ export default {
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; });
// 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: {
handleAgentSelected(agent) {
@ -595,6 +609,7 @@ export default {
if (this.isEdit) {
getOrder(this.orderId).then(response => {
this.form = response.data.projectOrderInfo;
this.isProjectSelected = true;
//
if (!this.form.versionCode) {
this.form.versionCode = 1;
@ -608,17 +623,25 @@ export default {
//
if (!this.form.contractTableData) {
this.form.contractTableData = {
[this.form.versionCode]: []
};
const files = this.form.contractTableData[this.form.versionCode];
const placeholders = ['商务折扣审批', '合同', '补充附件'];
if (this.form.uploadFinalFile) {
placeholders.push('已盖章合同');
}
placeholders.forEach((_, index) => {
files.push({id: -1, fileSort: index});
});
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) {
@ -637,6 +660,26 @@ export default {
this.form.dutyName = this.$store.state.user.name;
this.form.dutyEmail = this.$store.state.user.email;
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() {
this.handleClose();
if (this.projectId && this.orderId === null) {
this.$router.go(-1); // Navigate back to the previous page (project info)
} else {
this.handleClose();
}
},
//
reset() {
@ -667,7 +714,7 @@ export default {
actualPurchaseAmount: null,
shipmentAmount: null,
deliveryTime: null,
companyDelivery: '0',
companyDelivery: null,
orderChannel: null,
supplier: null,
dutyName: null,
@ -694,6 +741,7 @@ export default {
this.activeTab = 'basic';
this.activeContractVersionTab = null;
this.showFileFlag = false;
this.isProjectSelected = false;
this.resetForm("form");
},
/** 提交按钮 */
@ -703,8 +751,16 @@ export default {
const action = this.isEdit ? updateOrder : addOrder;
action(this.form).then(response => {
this.msgSuccess(this.isEdit ? "修改成功" : "新增成功");
this.handleClose();
this.$emit('success');
if (!this.isEdit) {
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) {
this.form.industryType = null;
const dictType = value === 'YYS' ? 'bg_yys' : 'bg_hysy';
getDicts(dictType).then(response => {
return getDicts(dictType).then(response => {
this.industryOptions = response.data;
});
},
@ -791,7 +847,35 @@ export default {
},
/** 选择项目按钮操作 */
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() {
@ -850,6 +934,10 @@ export default {
});
},
importList(sortNum) {
if (!this.form.id) {
this.$modal.alertWarning("请先保存订单,再上传合同信息");
return;
}
this.fileSort = sortNum;
if (sortNum === 0) {
document.getElementById('uploadInput').click();
@ -895,6 +983,11 @@ export default {
});
}).catch(() => {});
},
handleProductConfigInput(productData) {
this.form.softwareProjectProductInfoList = productData.softwareProjectProductInfoList;
this.form.hardwareProjectProductInfoList = productData.hardwareProjectProductInfoList;
this.form.maintenanceProjectProductInfoList = productData.maintenanceProjectProductInfoList;
}
}
};
</script>

View File

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