🎈 perf: 处理一些细节问题
This commit is contained in:
@@ -362,4 +362,8 @@ div.pagination-container {
|
||||
.el-input--large .el-input__icon {
|
||||
height: var(--btn-height);
|
||||
line-height: var(--btn-height);
|
||||
}
|
||||
|
||||
.el-tabs__content {
|
||||
overflow: visible !important;
|
||||
}
|
||||
278
klp-ui/src/components/KLPUI/KLPList/index.vue
Normal file
278
klp-ui/src/components/KLPUI/KLPList/index.vue
Normal file
@@ -0,0 +1,278 @@
|
||||
<template>
|
||||
<div class="klp-list-container">
|
||||
<!-- 列表加载状态 -->
|
||||
<div v-loading="loading" class="list-loading-wrapper">
|
||||
<!-- 列表项渲染 -->
|
||||
<div
|
||||
v-for="(item, index) in listData"
|
||||
:key="item[listKey] || index"
|
||||
class="klp-list-item"
|
||||
:class="{ 'active': isSelected(item) }"
|
||||
@click.stop="handleItemClick(item)"
|
||||
>
|
||||
<!-- 列表标题区域 - 文字溢出省略+Tooltip -->
|
||||
<div class="klp-list-title">
|
||||
<span class="title-label">{{ titleLabel }}:</span>
|
||||
<el-tooltip
|
||||
:content="item[titleField]"
|
||||
placement="top"
|
||||
:disabled="!isContentOverflow(item)"
|
||||
effect="light"
|
||||
>
|
||||
<span class="title-value">{{ item[titleField] }}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
||||
<!-- 右侧操作按钮组 -->
|
||||
<div class="klp-list-actions">
|
||||
<slot name="actions" :item="item" :isSelected="isSelected(item)"></slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 空状态提示 -->
|
||||
<div v-if="listData.length === 0 && !loading" class="klp-list-empty">
|
||||
<el-empty description="暂无数据" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "klp-list",
|
||||
components: {},
|
||||
props: {
|
||||
/** 列表数据源(必传) */
|
||||
listData: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
},
|
||||
|
||||
/** 列表项唯一标识字段(必传,如orderId、id) */
|
||||
listKey: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
|
||||
/** 列表标题前置标签(如"订单编号:") */
|
||||
titleLabel: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "标题"
|
||||
},
|
||||
|
||||
/** 列表项标题对应的字段名(如orderCode、name) */
|
||||
titleField: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "title"
|
||||
},
|
||||
|
||||
/** 列表加载状态 */
|
||||
loading: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
|
||||
/** 标题最大宽度(像素),控制文字溢出 */
|
||||
titleMaxWidth: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 200
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 内部管理选中状态:存储当前选中项的唯一键值(单选中)
|
||||
selectedKey: null,
|
||||
// 文字溢出检测临时元素(避免重复创建)
|
||||
overflowCheckElements: {}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 判断当前列表项是否被选中
|
||||
* @param {Object} item - 列表项数据
|
||||
* @returns {Boolean} 选中状态
|
||||
*/
|
||||
isSelected(item) {
|
||||
const itemKey = item[this.listKey];
|
||||
return this.selectedKey === itemKey;
|
||||
},
|
||||
|
||||
/**
|
||||
* 列表项点击事件:切换选中状态(单选中逻辑)
|
||||
* @param {Object} item - 点击的列表项数据
|
||||
*/
|
||||
handleItemClick(item) {
|
||||
const itemKey = item[this.listKey];
|
||||
// 单选中逻辑:点击已选中项取消选中,点击未选中项切换选中(取消其他项)
|
||||
this.selectedKey = this.selectedKey === itemKey ? null : itemKey;
|
||||
|
||||
// 向父组件触发事件:传递当前选中项(null表示无选中)
|
||||
const selectedItem = this.selectedKey ? item : null;
|
||||
this.$emit("item-click", selectedItem, item);
|
||||
},
|
||||
|
||||
/**
|
||||
* 清空选中状态(支持父组件通过ref调用)
|
||||
*/
|
||||
clearSelection() {
|
||||
this.selectedKey = null;
|
||||
// 触发清空选中事件
|
||||
this.$emit("selection-cleared");
|
||||
},
|
||||
|
||||
/**
|
||||
* 主动设置选中项(支持父组件通过ref调用)
|
||||
* @param {String/Number} targetKey - 要选中项的唯一键值
|
||||
*/
|
||||
setSelection(targetKey) {
|
||||
const isExist = this.listData.some(item => item[this.listKey] === targetKey);
|
||||
if (isExist) {
|
||||
this.selectedKey = targetKey;
|
||||
// 触发选中事件
|
||||
const selectedItem = this.listData.find(item => item[this.listKey] === targetKey);
|
||||
this.$emit("item-click", selectedItem);
|
||||
} else {
|
||||
this.selectedKey = null;
|
||||
console.warn(`列表中不存在key为${targetKey}的项`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 判断文字是否溢出(控制Tooltip显示/隐藏)
|
||||
* @param {Object} item - 列表项数据
|
||||
* @returns {Boolean} 是否溢出
|
||||
*/
|
||||
isContentOverflow(item) {
|
||||
const itemKey = item[this.listKey];
|
||||
const content = item[this.titleField] || "";
|
||||
|
||||
// 内容为空时不显示Tooltip
|
||||
if (!content) return false;
|
||||
|
||||
// 创建临时元素测量文字实际宽度(复用元素避免性能问题)
|
||||
if (!this.overflowCheckElements[itemKey]) {
|
||||
const tempEl = document.createElement("span");
|
||||
// 复制title-value的样式(确保测量准确)
|
||||
tempEl.style.cssText = `
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
`;
|
||||
tempEl.textContent = content;
|
||||
document.body.appendChild(tempEl);
|
||||
this.overflowCheckElements[itemKey] = tempEl;
|
||||
}
|
||||
|
||||
// 比较文字实际宽度与设定的最大宽度
|
||||
const tempEl = this.overflowCheckElements[itemKey];
|
||||
return tempEl.offsetWidth > this.titleMaxWidth;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
/** 列表数据变化时,重置选中状态和溢出检测元素 */
|
||||
listData: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.clearSelection();
|
||||
// 清理临时测量元素
|
||||
Object.values(this.overflowCheckElements).forEach(el => {
|
||||
document.body.removeChild(el);
|
||||
});
|
||||
this.overflowCheckElements = {};
|
||||
}
|
||||
},
|
||||
|
||||
/** 标题最大宽度变化时,强制重绘以重新计算溢出 */
|
||||
titleMaxWidth() {
|
||||
this.$forceUpdate();
|
||||
}
|
||||
},
|
||||
/** 组件销毁时清理临时元素,避免内存泄漏 */
|
||||
beforeDestroy() {
|
||||
Object.values(this.overflowCheckElements).forEach(el => {
|
||||
document.body.removeChild(el);
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 列表容器基础样式 */
|
||||
.klp-list-container {
|
||||
max-height: calc(100vh - 220px);
|
||||
overflow-y: auto;
|
||||
padding-right: 8px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* 加载状态容器(避免加载时容器塌陷) */
|
||||
.list-loading-wrapper {
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
/* 列表项样式 */
|
||||
.klp-list-item {
|
||||
padding: 6px 8px;
|
||||
margin-bottom: 6px;
|
||||
border-bottom: 1px solid #e6e6e6;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 列表项选中状态(左侧高亮边框+背景色) */
|
||||
.klp-list-item.active {
|
||||
border-left: 3px solid #409eff;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
/* 列表标题区域(占满中间空间,让操作按钮靠右) */
|
||||
.klp-list-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* 标题前置标签样式 */
|
||||
.klp-list-title .title-label {
|
||||
color: #606266;
|
||||
margin-right: 6px;
|
||||
font-size: 13px;
|
||||
white-space: nowrap; /* 标签不换行 */
|
||||
}
|
||||
|
||||
/* 标题内容样式(溢出省略) */
|
||||
.klp-list-title .title-value {
|
||||
color: #303133;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
white-space: nowrap; /* 禁止换行 */
|
||||
overflow: hidden; /* 超出部分隐藏 */
|
||||
text-overflow: ellipsis; /* 超出部分显示省略号 */
|
||||
max-width: v-bind(titleMaxWidth + "px"); /* 绑定父组件传入的最大宽度 */
|
||||
}
|
||||
|
||||
/* 操作按钮组(按钮间距控制) */
|
||||
.klp-list-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
/* 空状态样式(居中显示) */
|
||||
.klp-list-empty {
|
||||
padding: 40px 0;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -4,10 +4,36 @@
|
||||
<el-col :span="6">
|
||||
<div>
|
||||
<el-row>
|
||||
<el-input v-model="queryParams.orderCode" placeholder="请输入单据编号" clearable
|
||||
@keyup.enter.native="handleQuery" />
|
||||
<el-input
|
||||
v-model="queryParams.orderCode"
|
||||
placeholder="请输入单据编号"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-row>
|
||||
<el-tree v-loading="orderListLoading" :data="treeData" :props="defaultProps" @node-click="handleNodeClick" />
|
||||
|
||||
<!-- 使用klp-list组件替换el-tree -->
|
||||
<klp-list
|
||||
v-loading="orderListLoading"
|
||||
:list-data="orderList"
|
||||
list-key="orderId"
|
||||
title-label="订单编号"
|
||||
title-field="orderCode"
|
||||
:title-max-width="180"
|
||||
@item-click="handleItemClick"
|
||||
>
|
||||
<!-- 操作按钮插槽 -->
|
||||
<!-- <template #actions="{ item, isSelected }">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
@click.stop="handleViewDetail(item)"
|
||||
title="查看详情"
|
||||
></el-button>
|
||||
</template> -->
|
||||
</klp-list>
|
||||
|
||||
<pagination
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@@ -47,14 +73,15 @@
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="应收明细" name="receivable">
|
||||
<el-table v-loading="rightLoading" :data="currentOrder.receivables" empty-text="暂无数据">
|
||||
<el-table-column label="应收ID" align="center" prop="receivableId" v-if="false" />
|
||||
<el-table-column label="客户" align="center" prop="customerName" />
|
||||
<el-table-column label="订单ID" align="center" prop="orderId" />
|
||||
<el-table-column label="到期日" align="center" prop="dueDate" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.dueDate, '{y}-{m}-{d}') }}</span>
|
||||
<el-tag v-if="new Date(scope.row.dueDate) < new Date()" type="danger">过期</el-tag>
|
||||
<el-tag v-else-if="new Date(scope.row.dueDate) > new Date()" type="success">还剩{{ parseInt((new Date(scope.row.dueDate) - new Date()) / (1000 * 60 * 60 * 24)) }}天</el-tag>
|
||||
<el-tag v-else-if="new Date(scope.row.dueDate) > new Date()" type="success">
|
||||
还剩{{ parseInt((new Date(scope.row.dueDate) - new Date()) / (1000 * 60 * 60 * 24)) }}天
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="应收金额" align="center" prop="amount" />
|
||||
@@ -66,14 +93,15 @@
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="应付明细" name="payable">
|
||||
<el-table v-loading="rightLoading" :data="currentOrder.payables" empty-text="暂无数据">
|
||||
<el-table-column label="应付ID" align="center" prop="payableId" v-if="false" />
|
||||
<el-table-column label="供应商" align="center" prop="supplierName" />
|
||||
<el-table-column label="订单ID" align="center" prop="orderId" />
|
||||
<el-table-column label="到期日" align="center" prop="dueDate" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.dueDate, '{y}-{m}-{d}') }}</span>
|
||||
<el-tag v-if="new Date(scope.row.dueDate) < new Date()" type="danger">过期</el-tag>
|
||||
<el-tag v-else-if="new Date(scope.row.dueDate) > new Date()" type="success">还剩{{ parseInt((new Date(scope.row.dueDate) - new Date()) / (1000 * 60 * 60 * 24)) }}天</el-tag>
|
||||
<el-tag v-else-if="new Date(scope.row.dueDate) > new Date()" type="success">
|
||||
还剩{{ parseInt((new Date(scope.row.dueDate) - new Date()) / (1000 * 60 * 60 * 24)) }}天
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="应付金额" align="center" prop="amount" />
|
||||
@@ -97,7 +125,6 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -108,11 +135,13 @@ import { listPayable } from "@/api/finance/payable";
|
||||
import { listFinancialDocument } from "@/api/finance/financialDocument";
|
||||
|
||||
import OrderDetailList from '@/views/wms/order/panels/detail.vue'
|
||||
import klpList from "@/components/KLPUI/KLPList/index.vue"; // 引入klp-list组件
|
||||
|
||||
export default {
|
||||
name: "Order",
|
||||
components: {
|
||||
OrderDetailList
|
||||
OrderDetailList,
|
||||
klpList // 注册klp-list组件
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -124,12 +153,8 @@ export default {
|
||||
orderCode: undefined
|
||||
},
|
||||
orderListLoading: false,
|
||||
treeData: [],
|
||||
orderList: [], // 用于klp-list的列表数据
|
||||
total: 0,
|
||||
defaultProps: {
|
||||
children: 'children',
|
||||
label: 'label'
|
||||
},
|
||||
rightLoading: false,
|
||||
}
|
||||
},
|
||||
@@ -144,39 +169,62 @@ export default {
|
||||
getList() {
|
||||
this.orderListLoading = true;
|
||||
listOrder(this.queryParams).then(response => {
|
||||
this.treeData = response.rows.map(item => ({
|
||||
label: item.orderCode,
|
||||
value: item
|
||||
}));
|
||||
this.orderList = response.rows; // 直接使用原始数据
|
||||
this.total = response.total;
|
||||
}).finally(() => {
|
||||
this.orderListLoading = false;
|
||||
});
|
||||
},
|
||||
handleNodeClick(data) {
|
||||
// 处理列表项点击事件
|
||||
handleItemClick(selectedItem) {
|
||||
if (!selectedItem) {
|
||||
this.currentOrder = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.rightLoading) {
|
||||
this.$message.warning('请等待当前订单加载完成');
|
||||
return;
|
||||
}
|
||||
this.currentOrder = data.value;
|
||||
this.fetchData(data.value.orderId);
|
||||
|
||||
this.currentOrder = selectedItem;
|
||||
this.fetchData(selectedItem.orderId);
|
||||
},
|
||||
// 查看详情按钮点击事件
|
||||
handleViewDetail(item) {
|
||||
this.currentOrder = item;
|
||||
this.fetchData(item.orderId);
|
||||
},
|
||||
async fetchData(orderId) {
|
||||
this.rightLoading = true;
|
||||
// 需要逐个获取订单明细、应收明细、应付明细、凭证管理
|
||||
const orderDetail = (await listOrderDetail({ orderId, pageSize: 1000 })).rows;
|
||||
const receivableDetail = (await listReceivable({ orderId, pageSize: 1000 })).rows;
|
||||
const payableDetail = (await listPayable({ orderId, pageSize: 1000 })).rows;
|
||||
const documentDetail = (await listFinancialDocument({ orderId, pageSize: 1000 })).rows;
|
||||
this.rightLoading = false;
|
||||
this.currentOrder = {
|
||||
...this.currentOrder,
|
||||
details: orderDetail,
|
||||
receivables: receivableDetail,
|
||||
payables: payableDetail,
|
||||
documents: documentDetail
|
||||
try {
|
||||
// 并行请求提高性能
|
||||
const [
|
||||
orderDetailRes,
|
||||
receivableRes,
|
||||
payableRes,
|
||||
documentRes
|
||||
] = await Promise.all([
|
||||
listOrderDetail({ orderId, pageSize: 1000 }),
|
||||
listReceivable({ orderId, pageSize: 1000 }),
|
||||
listPayable({ orderId, pageSize: 1000 }),
|
||||
listFinancialDocument({ orderId, pageSize: 1000 })
|
||||
]);
|
||||
|
||||
this.currentOrder = {
|
||||
...this.currentOrder,
|
||||
details: orderDetailRes.rows,
|
||||
receivables: receivableRes.rows,
|
||||
payables: payableRes.rows,
|
||||
documents: documentRes.rows
|
||||
};
|
||||
} catch (error) {
|
||||
this.$message.error('数据加载失败,请重试');
|
||||
console.error(error);
|
||||
} finally {
|
||||
this.rightLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -39,14 +39,22 @@
|
||||
@click="handleExport"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="bomItemList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="属性名称" align="center" prop="attrKey" />
|
||||
<el-table-column label="属性名称" align="center" prop="attrKey">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.attrKey }}</span>
|
||||
<span v-if="scope.row.remark">
|
||||
<el-tooltip :content="scope.row.remark" placement="top">
|
||||
<i class="el-icon-info"></i>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="属性值" align="center" prop="attrValue" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<!-- <el-table-column label="备注" align="center" prop="remark" /> -->
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
|
||||
@@ -65,8 +65,8 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<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" /> -->
|
||||
|
||||
<!-- 添加或修改订单明细对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
@@ -106,7 +106,7 @@
|
||||
<el-select placeholder="请选择产品规范" @change="handleChangeSpec" style="width: 100%;">
|
||||
<el-option v-for="item in productSpecList" :key="item.groupId" :label="item.groupName" :value="item.groupId" />
|
||||
<template #empty>
|
||||
<el-button type="primary" @click="handleAddSpec">新增产品规范</el-button>
|
||||
<el-button @click="handleAddSpec" style="width: 100%;">新增产品规范</el-button>
|
||||
</template>
|
||||
</el-select>
|
||||
</div>
|
||||
@@ -158,7 +158,7 @@ export default {
|
||||
EOrderStatus,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
pageSize: 100,
|
||||
orderId: this.orderId,
|
||||
productId: undefined,
|
||||
quantity: undefined,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="app-container">
|
||||
<!-- 左右布局容器 -->
|
||||
<el-row :gutter="20">
|
||||
<!-- 左侧:自定义简洁订单列表区(占8列) -->
|
||||
<!-- 左侧:使用klp-list组件(占6列) -->
|
||||
<el-col :span="6" style="display: table-cell;">
|
||||
<!-- 搜索表单 - 精简搜索项 -->
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"
|
||||
@@ -19,54 +19,33 @@
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<!-- 功能按钮区 -->
|
||||
<!-- <el-row :gutter="10" class="mb-4">
|
||||
<el-col :span="6">
|
||||
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete"
|
||||
class="w-full">批量删除</el-button>
|
||||
</el-col>
|
||||
</el-row> -->
|
||||
<!-- klp-list组件 -->
|
||||
<klp-list
|
||||
:list-data="orderList"
|
||||
:model-value="selectedIds"
|
||||
title-field="orderCode"
|
||||
list-key="orderId"
|
||||
title-label="订单编号"
|
||||
:loading="loading"
|
||||
@item-click="handleRowClick"
|
||||
>
|
||||
<!-- 自定义操作按钮 -->
|
||||
<template #actions="{ item }">
|
||||
<!-- 预订单确认按钮 -->
|
||||
<el-button size="mini" plain title="预订单确认" type="success" icon="el-icon-check" v-if="isPre"
|
||||
@click.stop="handleStartProduction(item)"></el-button>
|
||||
|
||||
<!-- 自定义简洁列表 -->
|
||||
<div class="custom-list-container" v-loading="loading">
|
||||
<!-- 列表项 -->
|
||||
<div v-for="(item, index) in orderList" :key="item.orderId" class="order-item"
|
||||
:class="{ 'active': selectedOrderId === item.orderId }" @click="handleRowClick(item)">
|
||||
<!-- 复选框 -->
|
||||
<!-- <el-checkbox v-model="selectedIds[item.orderId]" @change.stop="handleCheckboxChange(item, $event)"
|
||||
class="checkbox"></el-checkbox> -->
|
||||
<!-- 订单编号 -->
|
||||
<div class="order-code">
|
||||
<span class="label">订单编号:</span>
|
||||
<span class="value">{{ item.orderCode }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮组 -->
|
||||
<div class="order-actions">
|
||||
<!-- 预订单确认按钮 -->
|
||||
<el-button size="mini" plain title="预订单确认" type="success" icon="el-icon-check" v-if="isPre"
|
||||
@click.stop="handleStartProduction(item)"></el-button>
|
||||
|
||||
<!-- 删除按钮 -->
|
||||
<el-button size="mini" type="text" style="color: red" icon="el-icon-delete" @click.stop="handleDelete(item)"></el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<div v-if="orderList.length === 0 && !loading" class="empty-state">
|
||||
<el-empty description="暂无订单数据" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 删除按钮 -->
|
||||
<el-button size="mini" type="text" style="color: red" icon="el-icon-delete" @click.stop="handleDelete(item)"></el-button>
|
||||
</template>
|
||||
</klp-list>
|
||||
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize" @pagination="getList" class="mt-4" />
|
||||
</el-col>
|
||||
|
||||
<!-- 右侧:详情区(占16列) -->
|
||||
<!-- 右侧:详情区(占18列) -->
|
||||
<el-col :span="18">
|
||||
<div>
|
||||
<!-- 未选中行时显示提示 -->
|
||||
@@ -81,56 +60,45 @@
|
||||
<!-- 订单信息Tab -->
|
||||
<el-tab-pane label="订单信息" name="orderInfo">
|
||||
<el-form ref="detailForm" :model="form" :rules="rules" label-width="80px" size="small" class="mt-4">
|
||||
<!-- <el-row :gutter="20"> -->
|
||||
<!-- <el-col :span="12"> -->
|
||||
<el-form-item label="订单ID" prop="orderId">
|
||||
<el-input style="width: 60%;" v-model="form.orderId" placeholder="无" disabled>
|
||||
<el-button style="padding: -1;" slot="append" size="mini" type="text" icon="el-icon-document-copy"
|
||||
@click.stop="copyOrderId(form.orderId)"></el-button>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<!-- </el-col> -->
|
||||
<!-- <el-col :span="12"> -->
|
||||
<el-form-item label="订单编号" prop="orderCode">
|
||||
<el-input style="width: 60%;" v-model="form.orderCode" placeholder="无" disabled />
|
||||
</el-form-item>
|
||||
<!-- </el-col> -->
|
||||
<!-- <el-col :span="12"> -->
|
||||
<el-form-item label="客户名称" prop="customerId">
|
||||
<customer-select style="width: 60%;" v-model="form.customerId" />
|
||||
</el-form-item>
|
||||
<!-- </el-col> -->
|
||||
<!-- <el-col :span="12"> -->
|
||||
<el-form-item label="销售经理" prop="salesManager">
|
||||
<el-input style="width: 60%;" v-model="form.salesManager" placeholder="无" />
|
||||
</el-form-item>
|
||||
<!-- </el-col> -->
|
||||
<!-- <el-col :span="12"> -->
|
||||
<el-form-item label="含税金额" prop="taxAmount">
|
||||
<el-input-number style="width: 60%;" :controls="false" v-model="form.taxAmount" placeholder="0.00" precision="2"
|
||||
:min="0" />
|
||||
</el-form-item>
|
||||
<!-- </el-col> -->
|
||||
<!-- <el-col :span="12"> -->
|
||||
<el-form-item label="无税金额" prop="noTaxAmount">
|
||||
<el-input-number style="width: 60%;" :controls="false" v-model="form.noTaxAmount" placeholder="0.00" precision="2"
|
||||
:min="0" />
|
||||
</el-form-item>
|
||||
<!-- </el-col> -->
|
||||
<!-- <el-col :span="12" v-if="!isPre"> -->
|
||||
<el-form-item label="订单状态" prop="orderStatus">
|
||||
<el-select style="width: 60%;" v-model="form.orderStatus" @change="handleOrderStatusChange" size="mini">
|
||||
<el-option v-for="item in dict.type.order_status" :key="item.value" :label="item.label"
|
||||
:value="parseInt(item.value)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- </el-col> -->
|
||||
<!-- <el-col :span="24"> -->
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input style="width: 60%;" v-model="form.remark" placeholder="无" type="textarea" rows="4" />
|
||||
</el-form-item>
|
||||
<!-- </el-col> -->
|
||||
<!-- </el-row> -->
|
||||
<el-form-item label="订单ID" prop="orderId">
|
||||
<el-input style="width: 60%;" v-model="form.orderId" placeholder="无" disabled>
|
||||
<el-button style="padding: -1;" slot="append" size="mini" type="text" icon="el-icon-document-copy"
|
||||
@click.stop="copyOrderId(form.orderId)"></el-button>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="订单编号" prop="orderCode">
|
||||
<el-input style="width: 60%;" v-model="form.orderCode" placeholder="无" disabled />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="客户名称" prop="customerId">
|
||||
<customer-select style="width: 60%;" v-model="form.customerId" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="销售经理" prop="salesManager">
|
||||
<el-input style="width: 60%;" v-model="form.salesManager" placeholder="无" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="含税金额" prop="taxAmount">
|
||||
<el-input-number style="width: 60%;" :controls="false" v-model="form.taxAmount" placeholder="0.00" precision="2"
|
||||
:min="0" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="无税金额" prop="noTaxAmount">
|
||||
<el-input-number style="width: 60%;" :controls="false" v-model="form.noTaxAmount" placeholder="0.00" precision="2"
|
||||
:min="0" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="订单状态" prop="orderStatus" v-if="!isPre">
|
||||
<el-select style="width: 60%;" v-model="form.orderStatus" @change="handleOrderStatusChange" size="mini">
|
||||
<el-option v-for="item in dict.type.order_status" :key="item.value" :label="item.label"
|
||||
:value="parseInt(item.value)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input style="width: 60%;" v-model="form.remark" placeholder="无" type="textarea" rows="4" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 更新按钮 -->
|
||||
<el-form-item class="text-right">
|
||||
@@ -203,10 +171,11 @@ import { getOrder, delOrder, addOrder, updateOrder, listByStatus } from "@/api/w
|
||||
import OrderDetailPanel from './detail.vue';
|
||||
import { EOrderStatus } from "@/utils/enums";
|
||||
import CustomerSelect from '@/components/KLPService/CustomerSelect/index.vue';
|
||||
import klpList from "@/components/KLPUI/KLPList/index.vue";
|
||||
|
||||
export default {
|
||||
name: "Order",
|
||||
components: { OrderDetailPanel, CustomerSelect },
|
||||
components: { OrderDetailPanel, CustomerSelect, klpList },
|
||||
dicts: ['order_status'],
|
||||
props: {
|
||||
isPre: {
|
||||
@@ -227,10 +196,8 @@ export default {
|
||||
buttonLoading: false,
|
||||
// 列表加载遮罩
|
||||
loading: true,
|
||||
// 选中的订单ID集合(用于批量操作)
|
||||
// 选中的订单ID集合
|
||||
selectedIds: {},
|
||||
// 非多个禁用(批量删除用)
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
@@ -304,7 +271,6 @@ export default {
|
||||
|
||||
// 重置选中状态
|
||||
this.selectedIds = {};
|
||||
this.checkMultipleStatus();
|
||||
|
||||
// 如果之前选中的订单不在列表中了,清空选中状态
|
||||
if (this.selectedOrderId && !this.orderList.some(item => item.orderId === this.selectedOrderId)) {
|
||||
@@ -337,18 +303,6 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
/** 处理复选框变化 */
|
||||
handleCheckboxChange(item, checked) {
|
||||
this.selectedIds[item.orderId] = checked;
|
||||
this.checkMultipleStatus();
|
||||
},
|
||||
|
||||
/** 检查批量操作状态 */
|
||||
checkMultipleStatus() {
|
||||
const selectedCount = Object.values(this.selectedIds).filter(checked => checked).length;
|
||||
this.multiple = selectedCount === 0;
|
||||
},
|
||||
|
||||
/** 订单状态变更 */
|
||||
handleOrderStatusChange() {
|
||||
updateOrder(this.form).then(response => {
|
||||
@@ -463,30 +417,13 @@ export default {
|
||||
|
||||
/** 删除订单 */
|
||||
handleDelete(row) {
|
||||
// 获取要删除的订单ID
|
||||
let orderIds;
|
||||
if (row) {
|
||||
// 单条删除
|
||||
orderIds = [row.orderId];
|
||||
} else {
|
||||
// 批量删除
|
||||
orderIds = Object.entries(this.selectedIds)
|
||||
.filter(([id, checked]) => checked)
|
||||
.map(([id]) => id);
|
||||
}
|
||||
|
||||
if (!orderIds.length) {
|
||||
this.$modal.msgWarning("请选择要删除的订单");
|
||||
return;
|
||||
}
|
||||
|
||||
this.$modal.confirm(`是否确认删除选中的 ${orderIds.length} 个订单?`).then(() => {
|
||||
this.$modal.confirm(`是否确认删除订单"${row.orderCode}"?`).then(() => {
|
||||
this.loading = true;
|
||||
return delOrder(orderIds);
|
||||
return delOrder([row.orderId]);
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
// 如果删除的是当前选中的订单,清空详情
|
||||
if (row && this.selectedOrderId === row.orderId) {
|
||||
if (this.selectedOrderId === row.orderId) {
|
||||
this.selectedOrderId = null;
|
||||
}
|
||||
this.getList();
|
||||
@@ -525,78 +462,6 @@ export default {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
/* 自定义列表容器 */
|
||||
.custom-list-container {
|
||||
max-height: calc(100vh - 220px);
|
||||
overflow-y: auto;
|
||||
padding-right: 8px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* 列表项样式 */
|
||||
.order-item {
|
||||
padding: 12px 16px;
|
||||
margin-bottom: 10px;
|
||||
border-bottom: 1px solid #e6e6e6;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 选中状态 */
|
||||
.order-item.active {
|
||||
border-left: 3px solid #409eff;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
/* 订单编号样式 */
|
||||
.order-code {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.order-code .label {
|
||||
color: #606266;
|
||||
margin-right: 6px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.order-code .value {
|
||||
color: #303133;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 操作按钮组 */
|
||||
.order-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
/* 复选框样式调整 */
|
||||
.checkbox {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
/* 空状态样式 */
|
||||
.empty-state {
|
||||
padding: 40px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 右侧详情容器 */
|
||||
.detail-container {
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
min-height: calc(100vh - 32px);
|
||||
}
|
||||
|
||||
/* 空提示样式 */
|
||||
.empty-tip {
|
||||
height: 400px;
|
||||
@@ -617,4 +482,4 @@ export default {
|
||||
padding: 0 10px !important;
|
||||
text-align: center !important;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="120px">
|
||||
<el-form-item label="采购订单编号" prop="detailCode">
|
||||
<el-input v-model="queryParams.detailCode" placeholder="请输入采购订单编号" clearable
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="原材料" prop="rawMaterialId">
|
||||
<RawMaterialSelect v-model="queryParams.rawMaterialId" placeholder="请选择原材料" can-add />
|
||||
</el-form-item>
|
||||
@@ -40,10 +36,10 @@
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport">导出</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<!-- <el-col :span="1.5">
|
||||
<el-button type="info" plain icon="el-icon-plus" size="mini" :disabled="!hasArrivalItems"
|
||||
@click="handleCreateStockIn">创建入库单</el-button>
|
||||
</el-col>
|
||||
</el-col> -->
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
|
||||
@@ -12,15 +12,15 @@
|
||||
>
|
||||
<!-- 下拉选项:循环制造规范列表 -->
|
||||
<el-option
|
||||
v-for="item in mSpecList"
|
||||
:key="item.specId"
|
||||
:label="item.specName"
|
||||
:value="item.specId"
|
||||
v-for="item in pSpecList"
|
||||
:key="item.groupId"
|
||||
:label="item.groupName"
|
||||
:value="item.groupId"
|
||||
/>
|
||||
|
||||
<!-- 无数据提示 -->
|
||||
<el-option
|
||||
v-if="mSpecList.length === 0 && !loading"
|
||||
v-if="pSpecList.length === 0 && !loading"
|
||||
value=""
|
||||
disabled
|
||||
>
|
||||
@@ -30,7 +30,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listManufacturingSpec } from '@/api/work/manufacturingSpec'
|
||||
import { listProductSpecGroup } from '@/api/work/productSpecGroup'
|
||||
import { debounce } from '@/utils' // 防抖:避免频繁触发接口请求
|
||||
|
||||
export default {
|
||||
@@ -44,7 +44,7 @@ export default {
|
||||
// 可选:允许外部自定义搜索参数的字段名(增强组件复用性)
|
||||
searchKey: {
|
||||
type: String,
|
||||
default: 'specName' // 默认为“规范名称”搜索(对应接口的mSpecName参数)
|
||||
default: 'groupName' // 默认为“规范名称”搜索(对应接口的mSpecName参数)
|
||||
},
|
||||
// 可选:每页加载数量(外部可配置)
|
||||
pageSize: {
|
||||
@@ -54,7 +54,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mSpecList: [], // 制造规范列表数据
|
||||
pSpecList: [], // 制造规范列表数据
|
||||
loading: false, // 远程请求加载状态
|
||||
queryParams: {
|
||||
// 搜索参数:默认用specName(可通过searchKey自定义)
|
||||
@@ -109,14 +109,14 @@ export default {
|
||||
// 5. 获取制造规范列表(远程接口请求)
|
||||
getList() {
|
||||
this.loading = true // 开始加载:显示加载动画
|
||||
listManufacturingSpec(this.queryParams)
|
||||
listProductSpecGroup(this.queryParams)
|
||||
.then(res => {
|
||||
// 接口成功:赋值列表数据(兼容res.rows或res.data.rows,避免接口返回格式差异)
|
||||
this.mSpecList = res.rows || res.data?.rows || []
|
||||
this.pSpecList = res.rows || res.data?.rows || []
|
||||
})
|
||||
.catch(() => {
|
||||
// 接口失败:清空列表,避免旧数据残留
|
||||
this.mSpecList = []
|
||||
this.pSpecList = []
|
||||
this.$message.error('获取制造规范列表失败,请重试') // 错误提示(优化用户体验)
|
||||
})
|
||||
.finally(() => {
|
||||
@@ -125,9 +125,9 @@ export default {
|
||||
},
|
||||
|
||||
// 6. 选择变化时触发(返回完整订单项,方便父组件使用)
|
||||
handleSelectChange(mSpecId) {
|
||||
handleSelectChange(pSpecId) {
|
||||
// 根据选中的ID,找到对应的完整制造规范对象
|
||||
const selectedItem = this.mSpecList.find(item => item.specId === mSpecId)
|
||||
const selectedItem = this.pSpecList.find(item => item.groupId === pSpecId)
|
||||
// 触发change事件:返回完整项(父组件可通过@change接收)
|
||||
this.$emit('change', selectedItem)
|
||||
// 可选:触发input事件后,额外触发change事件(符合常规组件使用习惯)
|
||||
|
||||
@@ -53,7 +53,9 @@ export default {
|
||||
return;
|
||||
}
|
||||
// 处理数据,兼容多种字段名,保证任务名唯一
|
||||
const taskData = this.tasks.map((item, idx) => {
|
||||
|
||||
const taskData = this.tasks
|
||||
.map((item, idx) => {
|
||||
const name = (item.taskName || item.planName || item.remark || item.productName || item.name || `任务${idx+1}`) + (item.productName ? `-${item.productName}` : '');
|
||||
const start = item.startDate || item.start_time || item.start || item.start_date;
|
||||
const end = item.endDate || item.end_time || item.end || item.end_date;
|
||||
@@ -72,7 +74,10 @@ export default {
|
||||
startDate: start,
|
||||
endDate: end
|
||||
};
|
||||
});
|
||||
})
|
||||
// 确保三个字段都存在:startDate,endDate,name
|
||||
.filter(item => item.startDate && item.endDate && item.name);
|
||||
|
||||
// 先全部用 getColor 分配基础色
|
||||
taskData.forEach((item, idx) => {
|
||||
item._color = getColor(item.lineId, item.orderId, idx);
|
||||
|
||||
@@ -44,11 +44,18 @@
|
||||
|
||||
<el-table v-loading="loading" :data="productSpecList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="主键" align="center" prop="specId" v-if="false"/>
|
||||
<el-table-column label="所属产品规范组ID" align="center" prop="groupId" />
|
||||
<el-table-column label="规范名称" align="center" prop="specKey" />
|
||||
<el-table-column label="规范名称" align="center" prop="specKey">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.specKey }}</span>
|
||||
<span v-if="scope.row.remark">
|
||||
<el-tooltip :content="scope.row.remark" placement="top">
|
||||
<i class="el-icon-info"></i>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="规范值" align="center" prop="specValue" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<!-- <el-table-column label="备注" align="center" prop="remark" /> -->
|
||||
<el-table-column label="操作" v-if="!readonly" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
|
||||
@@ -135,8 +135,10 @@ export default {
|
||||
this.$refs.detailForm.validate(valid => {
|
||||
if (!valid) return;
|
||||
if (this.detailForm.dateRange && this.detailForm.dateRange.length === 2) {
|
||||
this.detailForm.startDate = this.detailForm.dateRange[0].replace(' ', "T") + '.000Z';
|
||||
this.detailForm.endDate = this.detailForm.dateRange[1].replace(' ', "T") + '.000Z';
|
||||
// const startDate = this.parseTime(this.detailForm.dateRange[0], '{y}-{m}-{d}T{h}:{i}:{s}') + '.000Z';
|
||||
// const endDate = this.parseTime(this.detailForm.dateRange[1], '{y}-{m}-{d}T{h}:{i}:{s}') + '.000Z';
|
||||
this.detailForm.startDate = this.detailForm.dateRange[0];
|
||||
this.detailForm.endDate = this.detailForm.dateRange[1];
|
||||
} else {
|
||||
this.detailForm.startDate = '';
|
||||
this.detailForm.endDate = '';
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<el-select placeholder="请选择产品规范" @change="handleChangeSpec" style="width: 100%;">
|
||||
<el-option v-for="item in productSpecList.filter(item => item.productId != this.form.productId)" :key="item.groupId" :label="item.groupName" :value="item.groupId" />
|
||||
<template #empty>
|
||||
<el-button type="primary" @click="handleAddSpec">新增产品规范</el-button>
|
||||
<el-button @click="handleAddSpec" style="width: 100%;">新增产品规范</el-button>
|
||||
</template>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user