Files
klp-oa/klp-ui/src/components/KLPService/ContractSelect/index.vue
砂糖 041e5aef0e feat(contract-select): 为合同选择组件添加分页功能并优化搜索逻辑
1.  移除了vis-network依赖包
2.  重构两个合同选择页面的搜索与列表逻辑,移除本地合并合同数据的操作,改为直接使用接口返回数据
3.  为所有合同tab添加分页组件,支持分页查询、搜索重置页码
4.  调整表格高度优化布局,更新搜索触发事件为失焦、回车和清空按钮
5.  新增搜索查询按钮,优化搜索交互体验
2026-06-18 15:39:42 +08:00

289 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<div style="display: flex; align-items: center; margin-bottom: 0px;">
<el-select v-model="selectedValue" placeholder="请选择合同" style="width: 100%" clearable>
<el-option v-for="item in contractList" :key="item.orderId" :value="item.orderId"
:label="item.contractCode" />
</el-select>
<!-- 编辑按钮点击打开弹窗 -->
<el-button v-if="mode == 'today'" @click="openSelectDialog" type="primary" size="small"
style="margin-left: 8px; padding: 0 12px;">
<i class="el-icon-setting"></i>
</el-button>
<!-- 刷新时不会移除手动添加的合同 -->
<el-button @click="handleRefresh" type="info" size="small" style="margin-left: 8px; padding: 0 12px;">
<i class="el-icon-refresh"></i>
</el-button>
</div>
<!-- 查询所有的合同和当前localstorage中的合同可以对localstorage中的合同进行新增和删除手动新增的合同带有手动添加的标记 -->
<el-dialog title="可选合同配置" :visible.sync="dialogVisible" width="80%" append-to-body>
<el-tabs v-model="activeTab">
<!-- 已配置合同tab -->
<el-tab-pane label="可选合同" name="configured">
<div v-if="contractList.length === 0" style="text-align: center; padding: 20px;">
暂无已配置合同
</div>
<el-table v-else :data="contractList" style="width: 100%" size="mini" height="600">
<el-table-column prop="contractCode" label="合同编号" width="160" />
<el-table-column prop="contractName" label="合同名称" width="180" />
<el-table-column prop="customer" label="客户" width="140" />
<el-table-column prop="salesman" label="销售人员" width="100" />
<el-table-column prop="deliveryDate" label="交付日期" width="110">
<template slot-scope="scope">
{{ scope.row.deliveryDate || '-' }}
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" show-overflow-tooltip />
<el-table-column label="添加方式" width="90">
<template slot-scope="scope">
<el-tag v-if="scope.row.isManual" type="success" size="small">手动</el-tag>
<el-tag v-else type="info" size="small">接口</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="70">
<template slot-scope="scope">
<el-button type="danger" size="mini" @click="removeContract(scope.row.orderId)" plain>
移除
</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<!-- 所有合同tab -->
<el-tab-pane label="所有合同" name="all">
<div style="margin-bottom: 16px;">
<el-input v-model="searchKeyword" placeholder="搜索合同" @blur="handleSearch"
@keyup.enter.native="handleSearch" @clear="handleSearch" clearable
size="small">
<el-button slot="append" icon="el-icon-search" @click="handleSearch" size="small"></el-button>
</el-input>
</div>
<el-table :data="allContracts" style="width: 100%" size="mini" height="520">
<el-table-column prop="contractCode" label="合同编号" width="160" />
<el-table-column prop="contractName" label="合同名称" width="180" />
<el-table-column prop="customer" label="客户" width="140" />
<el-table-column prop="salesman" label="销售人员" width="100" />
<el-table-column prop="deliveryDate" label="交付日期" width="110">
<template slot-scope="scope">
{{ scope.row.deliveryDate || '-' }}
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" show-overflow-tooltip />
<el-table-column label="状态" width="80">
<template slot-scope="scope">
<el-tag v-if="isContractInList(scope.row.orderId)" type="success"
size="small">已添加</el-tag>
<el-tag v-else type="info" size="small">未添加</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template slot-scope="scope">
<el-button v-if="!isContractInList(scope.row.orderId)" type="primary" size="mini"
@click="addContract(scope.row)" plain>
添加
</el-button>
<el-button v-else type="danger" size="mini" @click="removeContract(scope.row.orderId)"
plain>
移除
</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination v-if="allTotal > 0" background layout="total, prev, pager, next, jumper"
:total="allTotal" :page-size="allPageSize" :current-page.sync="allPageNum"
@current-change="handleAllPageChange" style="margin-top: 12px; text-align: right;" />
<div v-if="allContracts.length === 0" style="text-align: center; padding: 20px;">
暂无合同数据
</div>
</el-tab-pane>
</el-tabs>
</el-dialog>
</div>
</template>
<script>
import { listOrder, listTodayOrder } from '@/api/crm/order';
export default {
name: "ContractSelect",
props: {
value: {
type: String,
default: ""
},
mode: {
type: String,
default: "today" // today 或 all
}
},
data() {
return {
contractList: [],
dialogVisible: false,
searchKeyword: '',
allContracts: [],
activeTab: 'configured', // 默认显示已配置合同tab
allPageNum: 1,
allPageSize: 20,
allTotal: 0,
}
},
computed: {
selectedValue: {
get() {
return this.value;
},
set(val) {
this.$emit('input', val);
if (val) {
localStorage.setItem('lastSelectedContractId', val);
}
}
}
},
mounted() {
if (this.mode == "today") {
this.loadFromLocalStorage();
} else {
this.loadContractList();
}
},
methods: {
// 从localStorage中加载合同列表
loadFromLocalStorage() {
try {
const storedContracts = localStorage.getItem('todayContracts');
if (storedContracts) {
this.contractList = JSON.parse(storedContracts);
}
// else {
// 如果localStorage中没有从接口获取
this.loadContractList();
// }
} catch (error) {
console.error('Failed to load contracts from localStorage:', error);
this.loadContractList();
}
},
// 保存合同列表到localStorage
saveToLocalStorage() {
try {
localStorage.setItem('todayContracts', JSON.stringify(this.contractList));
} catch (error) {
console.error('Failed to save contracts to localStorage:', error);
}
},
// 加载合同列表
async loadContractList(keyword) {
if (this.mode == "all") {
const res = await listOrder({
pageNum: 1,
pageSize: 1000,
keyword: keyword || undefined,
});
this.contractList = res.rows || [];
}
else if (this.mode == "today") {
const res = await listTodayOrder();
// 获取现有手动添加的合同
const existingManualContracts = this.contractList.filter(item => item.isManual);
// 将接口返回的合同标记为非手动添加
const apiContracts = (res.data || []).map(item => ({
...item,
isManual: false
}));
// 合并合同列表,保留手动添加的合同
this.contractList = [...apiContracts, ...existingManualContracts];
// 去重,避免重复合同
this.contractList = this.contractList.filter((item, index, self) =>
index === self.findIndex(t => t.orderId === item.orderId)
);
// 上一次选择的合同放在列表第一位
this.sortLastSelectedToFirst();
// 保存到localStorage
this.saveToLocalStorage();
}
},
// 将上一次选择的合同排到列表第一位
sortLastSelectedToFirst() {
const lastId = localStorage.getItem('lastSelectedContractId');
if (!lastId) return;
const index = this.contractList.findIndex(item => String(item.orderId) === String(lastId));
if (index > 0) {
const [item] = this.contractList.splice(index, 1);
this.contractList.unshift(item);
}
},
// 打开选择弹窗
async openSelectDialog() {
this.dialogVisible = true;
// 加载所有合同供选择
await this.loadAllContracts();
},
// 加载所有合同
async loadAllContracts() {
try {
const res = await listOrder({
pageNum: this.allPageNum,
pageSize: this.allPageSize,
keyword: this.searchKeyword || undefined,
});
this.allTotal = res.total || 0;
this.allContracts = res.rows || [];
} catch (error) {
console.error('Failed to load all contracts:', error);
this.allContracts = [];
}
},
// 搜索合同
handleSearch() {
this.allPageNum = 1;
this.loadAllContracts();
},
handleAllPageChange(page) {
this.allPageNum = page;
this.loadAllContracts();
},
// 检查合同是否在列表中
isContractInList(orderId) {
return this.contractList.some(item => item.orderId === orderId);
},
// 添加合同
addContract(contract) {
if (!this.isContractInList(contract.orderId)) {
this.contractList.push({
...contract,
isManual: true // 标记为手动添加
});
this.saveToLocalStorage();
}
},
// 移除合同
removeContract(orderId) {
this.contractList = this.contractList.filter(item => item.orderId !== orderId);
this.saveToLocalStorage();
},
// 刷新合同列表
handleRefresh() {
this.loadContractList();
},
}
}
</script>