新购到货管理/领料申请-类型规格-优化

This commit is contained in:
binbin_pan 2025-01-08 10:30:19 +08:00
parent a0519e57fa
commit fa474c8a07
3 changed files with 1741 additions and 1229 deletions

17
.prettierrc Normal file
View File

@ -0,0 +1,17 @@
{
"printWidth": 120,
"tabWidth": 4,
"singleQuote": true,
"semi": false,
"bracketSpacing": true,
"jsxBracketSameLine": true,
"arrowParens": "avoid",
"endOfLine": "lf",
"useTabs": false,
"trailingComma": "none",
"bracketSameLine": false,
"htmlWhitespaceSensitivity": "ignore",
"vueIndentScriptAndStyle": false,
"singleAttributePerLine": false,
"importStatement": "none"
}

View File

@ -91,20 +91,57 @@
</el-form-item> </el-form-item>
<el-form-item label="类型规格" prop="deviceType"> <el-form-item label="类型规格" prop="deviceType">
<el-cascader <el-row :gutter="10">
:key="propsKey" <el-col :span="15">
v-model="deviceType" <el-select
:show-all-levels="false" ref="typeSelect"
:options="equipmentTypeList" v-model="tempDeviceType"
:props="deviceTypeTreeProps" multiple
filterable filterable
placeholder="请输入类型规格"
style="width: 500px"
@change="handleTypeChange"
clearable
collapse-tags collapse-tags
style="width: 240px" :filter-method="handleSearchImpl"
placeholder="请选择规格型号" :popper-class="'type-select-dropdown'"
ref="deviceTypeCascader" :popper-append-to-body="false"
popper-class="popper-select" @visible-change="handleVisibleChange"
@change="deviceTypeChange" >
></el-cascader> <el-option
v-for="item in filteredOptions"
:key="item.typeId"
:label="item.fullPath"
:value="item.typeId"
:data-key="item.typeId"
>
<span v-html="highlightText(item.fullPath, searchKeyword)"></span>
<span style="float: right; color: #8492a6; font-size: 13px">
库存:{{ item.storageNum }}
</span>
</el-option>
</el-select>
</el-col>
<el-col :span="6">
<el-input
ref="searchInput"
v-model="searchKeyword"
placeholder="输入类型规格高亮搜索"
prefix-icon="el-icon-search"
clearable
style="width: 300px"
@input="handleHighlightSearch"
@focus="handleSearchFocus"
@click.native="handleSearchClick"
>
<template slot="append">
<span v-if="matchedOptions.length" style="margin: 0 5px">
{{ currentMatchIndex + 1 }}/{{ matchedOptions.length }}
</span>
</template>
</el-input>
</el-col>
</el-row>
</el-form-item> </el-form-item>
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
<el-input <el-input
@ -340,9 +377,9 @@ export default {
deviceTypeTreeProps: { deviceTypeTreeProps: {
children: "children", children: "children",
label: "typeName", label: "typeName",
// multiple: false,
value: "typeId", value: "typeId",
multiple: true, multiple: true,
emitPath: true
}, },
deviceType: [], deviceType: [],
propsKey: 1000, propsKey: 1000,
@ -350,6 +387,23 @@ export default {
unitTemp: undefined, unitTemp: undefined,
agreementId: undefined, agreementId: undefined,
// taxRate:0, // taxRate:0,
flattenOptions: [], //
typePopoverVisible: false,
typeOptions: [], //
allTypeList: [], //
flattenTypeOptions: [], //
typeGroups: [], //
typeGroupsBackup: [], //
typeMap: new Map(), //
tempDeviceType: [], //
filteredOptions: [], //
maxShowOptions: 100, //
searchTimer: null, //
searchKeyword: '', //
currentMatchIndex: -1, //
matchedOptions: [], //
keepSelectOpen: false, //
isSearching: false, //
}; };
}, },
computed: { computed: {
@ -363,7 +417,6 @@ export default {
}; };
}, },
}, },
watch: {},
mounted() { mounted() {
this.projectInfoList();// this.projectInfoList();//
this.equipmentType();// this.equipmentType();//
@ -452,84 +505,95 @@ export default {
equipmentType() { equipmentType() {
equipmentTypeTree().then((response) => { equipmentTypeTree().then((response) => {
this.equipmentTypeList = response.data; this.equipmentTypeList = response.data;
this.equipmentTypeList.forEach((item, index) => { //
if (item.children && item.children.length > 0) { this.flattenTypeOptions = this.processTypeData(response.data);
item.children.forEach((item2, index2) => { //
if (item2.children && item2.children.length > 0) { this.filteredOptions = [...this.flattenTypeOptions];
item2.children.forEach((item3) => {
if (item3.children && item3.children.length > 0) { //
item3.children.forEach((item4) => { if (this.equipmentList.length > 0) {
item4.maTypeName = item3.typeName; this.deviceType = this.equipmentList.map(item => item.typeId);
item4.specificationType = item4.typeName;
// this.$set(item4, "purchaseTaxPrice", 0);
// this.$set(item4, "purchasePrice", 0);
});
} }
}); });
}
});
}
});
//
let selectList = [];
this.equipmentList.forEach((e) => {
selectList.push(
this.getParentsById(this.equipmentTypeList, e.typeId)
);
});
this.deviceType = selectList;
});
}, },
// //
deviceTypeChange(val) { processTypeData(data) {
const deviceTypeList = this.$refs.deviceTypeCascader.getCheckedNodes(); const result = [];
let tempList = [];
if (val.length > 0) { const traverse = (node, parents = []) => {
const items = val.map((e) => { const path = [...parents, node.typeName];
return e[3];
if (!node.children || node.children.length === 0) {
result.push({
typeId: node.typeId,
typeName: node.typeName,
fullPath: path.join(' / '),
searchKey: path.join('').toLowerCase(),
storageNum: node.storageNum || 0,
maTypeName: parents[parents.length - 1] || '',
specificationType: node.typeName,
unitName: node.unitName,
unitValue: node.unitValue
}); });
for (let i of items) { }
for (let z of deviceTypeList) {
if (z.data.typeId === i) { if (node.children) {
const obj = JSON.parse(JSON.stringify(z.data)); node.children.forEach(child => traverse(child, path));
obj.preNum = 0; }
if(obj.storageNum<=0){ };
let index = this.deviceType.length;
if(index==1){ data.forEach(node => traverse(node));
return result;
},
//
handleSearchImpl(query) {
if (!query) {
this.filteredOptions = [...this.flattenTypeOptions];
return;
}
const lowercaseQuery = query.toLowerCase();
this.filteredOptions = this.flattenTypeOptions.filter(item =>
item.searchKey.includes(lowercaseQuery) ||
item.fullPath.toLowerCase().includes(lowercaseQuery)
);
},
//
handleTypeChange(val) {
if (!val || val.length === 0) return;
//
const lastSelected = val[val.length - 1];
const typeData = this.flattenTypeOptions.find(item => item.typeId === lastSelected);
if (typeData) {
if (this.equipmentList.some(item => item.typeId === lastSelected)) {
this.$message({
message: `${typeData.typeName} 已添加到列表中`,
type: 'warning'
});
this.tempDeviceType = this.tempDeviceType.filter(id => id !== lastSelected);
} else if (typeData.storageNum <= 0) {
this.$message.error("所选物资规格类型暂时无库存,无法申请!");
this.tempDeviceType = this.tempDeviceType.filter(id => id !== lastSelected);
} else {
//
this.equipmentList.unshift({
...typeData,
preNum: 0
});
this.deviceType.push(lastSelected);
this.$message({
message: `已添加 ${typeData.typeName}`,
type: 'success'
});
}
}
//
this.$nextTick(() => { this.$nextTick(() => {
this.deviceType=[]; // this.tempDeviceType = [];
}); });
}else{
this.deviceType=this.deviceType.splice(0,1)
}
this.$modal.msgError("所选物资规格类型暂时无库存,无法申请!");
}else{
tempList.push(obj);
}
break;
}
}
}
const newDataListNew = [...this.equipmentList, ...tempList];
const map = new Map();
for (let item of newDataListNew) {
if (!map.has(item.typeId)) {
map.set(item.typeId, item);
}
}
const newArray = [...map.values()];
let newArray_array = [];
items.forEach((e) => {
newArray.forEach((j) => {
if (e == j.typeId) {
newArray_array.push(j);
}
});
});
this.equipmentList = newArray_array;
} else {
this.equipmentList = [];
}
}, },
//--- //---
async getTaskInfo() { async getTaskInfo() {
@ -775,42 +839,16 @@ export default {
this.dialogVisible = true; this.dialogVisible = true;
} }
}, },
//
getParentsById(list, id) {
for (let i in list) {
if (list[i].typeId == id) {
//value
return [list[i].typeId];
}
if (list[i].children) {
let node = this.getParentsById(list[i].children, id);
if (node !== undefined) {
//
node.unshift(list[i].typeId);
return node;
}
}
}
},
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
console.log(row)
this.$modal this.$modal
.confirm("是否确认删除所选择的数据项?") .confirm("是否确认删除所选择的数据项?")
.then(() => { .then(() => {
this.deviceType.forEach((e, index) => { this.equipmentList = this.equipmentList.filter(
console.log("e", e); item => item.typeId !== row.typeId
if (e[3] === row.typeId) { );
this.deviceType.splice(index, 1); //
this.propsKey++; this.deviceType = this.equipmentList.map(item => item.typeId);
}
});
console.log(this.equipmentList)
this.equipmentList.forEach((item, index) => {
if (item.typeId == row.typeId) {
this.equipmentList.splice(index, 1);
}
});
}) })
.catch(() => {}); .catch(() => {});
}, },
@ -822,7 +860,88 @@ export default {
`新购到货详情_${new Date().getTime()}.xlsx` `新购到货详情_${new Date().getTime()}.xlsx`
); );
}, },
//
highlightText(text, keyword) {
if (!keyword) return text;
const reg = new RegExp(keyword, 'gi');
return text.replace(reg, match => `<span class="highlight-text">${match}</span>`);
}, },
//
handleVisibleChange(visible) {
if (!visible && this.keepSelectOpen && !this.isSearching) {
//
this.$nextTick(() => {
this.$refs.typeSelect.focus();
});
}
},
//
handleSearchClick() {
this.isSearching = true;
this.keepSelectOpen = true;
//
this.$refs.typeSelect.focus();
//
this.$nextTick(() => {
this.$refs.searchInput.focus();
});
},
//
handleSearchFocus() {
this.isSearching = true;
if (!this.$refs.typeSelect.visible) {
this.$refs.typeSelect.focus();
this.$nextTick(() => {
this.$refs.searchInput.focus();
});
}
},
//
handleHighlightSearch() {
this.isSearching = true;
this.keepSelectOpen = true;
if (!this.searchKeyword) {
this.currentMatchIndex = -1;
this.matchedOptions = [];
return;
}
//
this.matchedOptions = this.filteredOptions.filter(item =>
item.fullPath.toLowerCase().includes(this.searchKeyword.toLowerCase())
);
if (this.matchedOptions.length > 0) {
this.currentMatchIndex = 0;
this.$nextTick(() => {
this.scrollToMatch();
});
}
},
//
scrollToMatch() {
if (this.currentMatchIndex === -1 || !this.matchedOptions.length) return;
const option = this.matchedOptions[this.currentMatchIndex];
const selectDom = this.$el.querySelector('.el-select-dropdown__wrap');
const optionDom = selectDom?.querySelector(`[data-key="${option.typeId}"]`);
if (optionDom) {
optionDom.scrollIntoView({ block: 'center', behavior: 'smooth' });
}
},
},
//
beforeDestroy() {
this.keepSelectOpen = false;
this.isSearching = false;
}
}; };
</script> </script>
<style lang="scss"> <style lang="scss">
@ -835,4 +954,75 @@ export default {
display: block !important; display: block !important;
} }
} }
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
.el-icon-arrow-down.is-reverse {
transform: rotateZ(180deg);
}
.el-tree {
max-height: 300px;
overflow-y: auto;
}
.highlight-text {
background-color: #ffd04b;
color: #000;
}
::v-deep .el-input-group__append {
padding: 0;
.el-button {
padding: 0 10px;
border: none;
height: 100%;
&:first-child {
border-right: 1px solid #dcdfe6;
}
&[disabled] {
color: #c0c4cc;
}
}
}
.type-select-dropdown {
.el-select-dropdown__wrap {
max-height: 400px !important;
}
.el-select-dropdown__item {
height: auto;
padding: 8px 20px;
white-space: normal;
word-break: break-all;
}
}
.highlight-text {
background-color: #ffd04b;
color: #000;
}
.el-input-group__append {
padding: 0;
.el-button {
padding: 0 10px;
border: none;
height: 100%;
&:first-child {
border-right: 1px solid #dcdfe6;
}
&[disabled] {
color: #c0c4cc;
}
}
}
</style> </style>