Files
xgy-oa/klp-ui/src/components/KLPService/RawMaterialSelect/index.vue
砂糖 9d7ce2472d feat: 优化产品信息展示组件,使用悬停弹窗替代对话框
refactor: 重构原材料信息组件,采用与产品信息一致的交互方式
fix: 移除酸连轧工序页面,该功能已迁移至其他模块
style: 调整元素阴影样式,移除不必要的样式属性
chore: 添加调试日志,便于追踪参数传递
2025-11-24 17:21:26 +08:00

385 lines
10 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 class="raw-material-selector">
<!-- 触发器按钮 -->
<div class="el-input" v-if="!readonly" type="text" @click="dialogVisible = true">
<div class="el-input__inner">
<el-icon class="el-icon-search"></el-icon>
{{ buttonText }}
</div>
</div>
<span v-else class="readonly-text">{{ displayText }}</span>
<!-- 选择对话框 -->
<el-dialog title="选择原材料" :visible.sync="dialogVisible" width="1200px" :close-on-click-modal="false"
@close="handleClose" append-to-body>
<!-- 搜索区域保持不变 -->
<el-form :inline="true" :model="queryParams" class="search-form" size="small">
<el-form-item label="编号">
<el-input v-model="queryParams.rawMaterialCode" placeholder="请输入原材料编号" clearable
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="名称">
<el-input v-model="queryParams.rawMaterialName" placeholder="请输入原材料名称" clearable
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="规格">
<el-input v-model="queryParams.specification" placeholder="请输入规格" clearable
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="材质">
<el-input v-model="queryParams.material" placeholder="请输入材质" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 卡片布局替换原表格 -->
<div v-loading="loading" class="card-container">
<div v-for="(item, index) in rawMaterialList" :key="index + item.rawMaterialId" class="material-card"
:class="{ 'selected-card': isSelected(item.rawMaterialId) }" @click="handleRowClick(item)">
<!-- 多选勾选框 -->
<el-checkbox v-if="multiple" :checked="isSelected(item.rawMaterialId)"
@change="(val) => handleCardSelection(val, item)" class="card-checkbox" />
<!-- 卡片内容包含所有原表格字段 -->
<div class="card-content">
<div class="card-title">
<span class="name">{{ item.rawMaterialName }}</span>
<span class="code">[{{ item.rawMaterialCode }}]</span>
</div>
<div class="card-info">
<div class="info-item">规格<span>{{ item.specification || '-' }}</span></div>
<div class="info-item">单位<span>{{ item.unit || '-' }}</span></div>
<div class="info-item">材质<span>{{ item.material || '-' }}</span></div>
<div class="info-item">厂家<span>{{ item.manufacturer || '-' }}</span></div>
<div class="info-item">表面处理<span>{{ item.surfaceTreatmentDesc || '-' }}</span></div>
<div class="info-item">锌层<span>{{ item.zincLayer || '-' }}</span></div>
</div>
</div>
</div>
<!-- 空数据提示 -->
<div class="empty-tip" v-if="rawMaterialList.length === 0 && !loading">
暂无匹配的原材料数据
</div>
</div>
<!-- 分页保持不变 -->
<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 @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmSelection" v-if="multiple">
确认选择
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listRawMaterial } from '@/api/wms/rawMaterial';
export default {
name: 'RawMaterialSelector',
props: {
value: {
type: String,
default: ''
},
readonly: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: false
},
filters: {
type: Object,
default: () => ({})
}
},
data() {
return {
dialogVisible: false,
loading: false,
rawMaterialList: [],
total: 0,
queryParams: {
pageNum: 1,
pageSize: 10,
rawMaterialCode: undefined,
rawMaterialName: undefined,
specification: undefined,
material: undefined,
manufacturer: undefined,
surfaceTreatmentDesc: undefined,
zincLayer: undefined
},
selectedIds: [],
selectedRows: []
};
},
computed: {
buttonText() {
// 如果为选中任何原材料,显示选择原材料
// 如果为选中多个原材料,显示已选 X 项
// 如果为选中单个原材料,显示原材料名称
console.log(this.selectedIds);
if (this.selectedIds.length === 0) {
return '请选择原材料';
}
if (this.multiple) {
return `已选 ${this.selectedIds.length}`;
} else {
return `${this.selectedRows[0]?.rawMaterialName}[${this.selectedRows[0]?.specification || '-'}] (${this.selectedRows[0]?.material || '-'})`;
}
},
displayText() {
if (this.multiple) {
return this.selectedIds.length > 0
? `已选 ${this.selectedIds.length}`
: '未选择';
} else {
return this.selectedRows[0]?.rawMaterialName || '未选择';
}
},
},
watch: {
value: {
immediate: true,
handler(val) {
console.log('watch触发val', val);
this.selectedIds = val ? val.split(',').filter(id => id) : [];
// this.syncSelectedRows();
this.$forceUpdate(); // 新增:强制刷新视图
}
},
dialogVisible(val) {
if (val) {
this.getList();
}
}
},
methods: {
// 判断卡片是否选中
isSelected(rawMaterialId) {
return this.selectedIds.includes(rawMaterialId);
},
// 卡片选择事件(多选)
handleCardSelection(checked, item) {
if (checked) {
!this.selectedIds.includes(item.rawMaterialId) && this.selectedIds.push(item.rawMaterialId);
} else {
this.selectedIds = this.selectedIds.filter(id => id != item.rawMaterialId);
}
},
// 原有方法保持不变(仅修改同步选中状态逻辑)
async getList() {
try {
this.loading = true;
const params = { ...this.queryParams, ...this.filters };
console.log('params', params);
const response = await listRawMaterial(params);
if (response.code === 200) {
this.rawMaterialList = response.rows.map(item => ({
...item,
rawMaterialId: item.rawMaterialId.toString()
})) || [];
this.total = response.total || 0;
}
return this.rawMaterialList;
} catch (error) {
console.error('获取原材料列表失败', error);
this.$message.error('获取原材料列表失败');
} finally {
this.loading = false;
}
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.queryParams = {
pageNum: 1,
pageSize: 10,
rawMaterialCode: undefined,
rawMaterialName: undefined,
specification: undefined,
material: undefined,
manufacturer: undefined,
surfaceTreatmentDesc: undefined,
zincLayer: undefined
};
this.getList();
},
handleRowClick(row) {
if (!this.multiple) {
this.selectedIds = [row.rawMaterialId];
this.selectedRows = [row];
this.confirmSelection();
}
},
handleSelect(row) {
if (this.multiple) {
const index = this.selectedIds.indexOf(row.rawMaterialId);
index > -1
? (this.selectedIds.splice(index, 1), this.selectedRows.splice(index, 1))
: (this.selectedIds.push(row.rawMaterialId), this.selectedRows.push(row));
} else {
this.selectedIds = [row.rawMaterialId];
this.selectedRows = [row];
this.confirmSelection();
}
},
confirmSelection() {
const emitValue = this.selectedIds.join(',');
this.$emit('input', emitValue);
this.$emit('change', emitValue, this.selectedRows);
this.dialogVisible = false;
},
handleClose() {
this.selectedIds = this.value ? this.value.split(',').filter(id => id) : [];
// this.syncSelectedRows();
this.dialogVisible = false;
}
}
};
</script>
<style scoped lang="scss">
.raw-material-selector {
display: inline-block;
}
.search-form {
margin-bottom: 20px;
flex-wrap: wrap;
}
.readonly-text {
color: #606266;
line-height: 1;
padding: 8px 0;
display: inline-block;
}
::v-deep .el-dialog__body {
padding: 20px;
overflow-x: auto;
}
::v-deep .el-form-item {
margin-bottom: 15px;
margin-right: 15px;
}
/* 卡片容器样式 */
.card-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
gap: 20px;
margin-bottom: 20px;
min-height: 400px;
padding: 10px;
}
/* 卡片样式 */
.material-card {
border: 1px solid #e6e6e6;
border-radius: 0px;
padding: 4px;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
background: #fff;
&:hover {
border-color: #409eff;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08);
}
}
/* 选中卡片样式 */
.selected-card {
border-color: #409eff;
background-color: #f0f7ff;
}
/* 多选勾选框位置 */
.card-checkbox {
position: absolute;
top: 16px;
right: 16px;
}
/* 卡片内容样式 */
.card-content {
margin-right: 24px;
/* 给多选框留空间 */
}
.card-title {
display: flex;
align-items: center;
margin-bottom: 12px;
font-weight: 500;
}
.name {
font-size: 16px;
color: #1989fa;
margin-right: 8px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.code {
font-size: 14px;
color: #909399;
}
.card-info {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
font-size: 14px;
color: #606266;
}
.info-item {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.info-item span {
color: #303133;
}
/* 空数据提示 */
.empty-tip {
grid-column: 1 / -1;
display: flex;
align-items: center;
justify-content: center;
height: 400px;
color: #909399;
font-size: 16px;
}
</style>