bonus-ui/src/views/business/businessHandling/index.vue

1530 lines
48 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="app-container">
<el-form
:model="maForm"
ref="maForm"
size="small"
:rules="rules"
:inline="true"
label-width="120px"
:disabled="isDetail"
>
<el-form-item label="领用单位" prop="unitId">
<treeselect
v-model="maForm.unitId"
:disabled="isEdit || isDetail"
:options="uniteList"
:normalizer="normalizer"
:show-count="true"
style="width: 240px"
:disable-branch-nodes="true"
noChildrenText="没有数据了"
noOptionsText="没有数据"
noResultsText="没有搜索结果"
placeholder="请选择领用单位"
@select="uniteChange"
/>
</el-form-item>
<el-form-item label="领用工程" prop="projectId">
<treeselect
v-model="maForm.projectId"
:disabled="isEdit || isDetail"
:options="projectList"
:normalizer="normalizer"
:show-count="true"
style="width: 240px"
:disable-branch-nodes="true"
noChildrenText="没有数据了"
noOptionsText="没有数据"
noResultsText="没有搜索结果"
placeholder="请选择领用工程"
@select="projectChange"
/>
</el-form-item>
<el-form-item label="领料人" prop="leasePerson">
<el-input
v-model="maForm.leasePerson"
placeholder="请输入领料人"
clearable
maxlength="50"
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-row :gutter="20">
<el-col :span="24" :offset="0">
<el-form-item label="供货时间" prop="supplierTime">
<el-date-picker
v-model="maForm.supplierTime"
type="date"
placeholder="请选择供货时间"
clearable
style="width: 240px"
value-format="yyyy-MM-dd"
:picker-options="pickerOptions"
/>
</el-form-item>
<el-form-item label="供货地点" prop="supplierPlace">
<el-input
v-model="maForm.supplierPlace"
placeholder="请输入供货地点"
clearable
maxlength="200"
style="width: 240px"
/>
</el-form-item>
<el-form-item label="联系电话" prop="phone">
<el-input
v-model="maForm.phone"
placeholder="请输入联系电话"
clearable
maxlength="11"
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="适用班组数" prop="fitNum">
<el-input
v-model="maForm.fitNum"
placeholder="请输入适用班组数"
maxlength="10"
type="number"
style="width: 240px"
@blur="fitNumChange"
/>
</el-form-item>
<el-form-item label="业务单号" prop="code" v-if="isEdit || isDetail">
<el-input
v-model="maForm.code"
placeholder="请输入业务单号"
clearable
maxlength="150"
style="width: 240px"
disabled
/>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="标准配置" prop="standardConfig">
<treeselect
v-model="maForm.standardConfig"
:disabled="isDetail"
:options="standardConfigList"
:normalizer="normalizer"
:show-count="true"
style="width: 240px"
:disable-branch-nodes="true"
noChildrenText="没有数据了"
noOptionsText="没有数据"
noResultsText="没有搜索结果"
placeholder="请选择标准配置"
@select="standardConfigChange"
/>
</el-form-item>
<el-form-item label="类型规格" prop="deviceType">
<el-row :gutter="10">
<el-col :span="15">
<el-select
ref="typeSelect"
v-model="tempDeviceType"
multiple
filterable
placeholder="请输入类型规格"
style="width: 500px"
@change="handleTypeChange"
clearable
collapse-tags
:filter-method="handleSearchImpl"
:popper-class="'type-select-dropdown'"
:popper-append-to-body="false"
@visible-change="handleVisibleChange"
>
<el-option
v-for="item in filteredOptions"
:key="item.typeId"
:label="item.fullPath"
:value="item.typeId"
:data-key="item.typeId"
@mouseenter.native="showCustomTooltip(item, $event)"
@mouseleave.native="hideCustomTooltip"
>
<span v-html="highlightText(item.fullPath, searchKeyword)"></span>
</el-option>
</el-select>
<div
v-if="currentTooltipItem"
class="custom-tooltip"
:style="{
left: tooltipPosition.x + 'px',
top: tooltipPosition.y + 'px'
}"
>
<img
:src="currentTooltipItem.imageUrl || defaultImage"
style="max-width: 200px; max-height: 150px"
@load="imageLoaded"
@error="imageLoadError"
/>
<p>库存: {{ currentTooltipItem.storageNum }}</p>
</div>
</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 label="委托书" prop="bmFileInfos" v-if="isFileFbs">
<el-upload
:action="uploadUrl"
:file-list="maForm.bmFileInfos"
:show-file-list="true"
:auto-upload="true"
:key="uploadKey"
:limit="5"
list-type="picture-card"
accept=".png, .jpg, .jpeg, .pdf"
:on-change="handleChangeBusinessList"
:class="{ disabledFbs: uploadDisabled }"
:on-preview="picturePreviewFbs"
:on-remove="handleRemoveElectricianImgList"
:disabled="isDetail"
>
<!-- 文件格式下载,图片格式预览 -->
<div slot="file" slot-scope="{ file }">
<img v-if="isImage(file)" class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
<div v-else class="picture-card-container">
<img class="picture-card" :src="urlTemp" alt="" />
<p class="file-name">{{ file.name }}</p>
</div>
<span class="el-upload-list__item-actions">
<span v-if="updataIf(file)" class="el-upload-list__item-delete" @click="handleDownload(file)">
<i class="el-icon-download" />
</span>
<span v-else class="el-upload-list__item-preview" @click="picturePreviewFbs(file)">
<i class="el-icon-zoom-in" />
</span>
<span v-if="!isDetail" class="el-upload-list__item-delete" @click="handleRemoveElectricianImgList(file)">
<i class="el-icon-delete" />
</span>
</span>
</div>
<i class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5" v-if="!isDetail">
<el-button type="primary" plain icon="el-icon-document" size="mini" @click="handleSave">
{{ isEdit ? '提交' : '发起申请' }}
</el-button>
</el-col>
<el-col :span="1.5" v-if="!isDetail">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="addColumns">新增条目</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-arrow-left" size="mini" @click="handleApplyRecord">
领料记录查看
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport">
导出工具器清单
</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="equipmentList" @selection-change="handleSelectionChange">
<!-- <el-table-column type="selection" width="55" align="center" /> -->
<el-table-column align="center" label="序号" type="index" width="55" />
<el-table-column align="center" label="类型名称" prop="maTypeName" show-overflow-tooltip>
<template v-slot="scope">
<el-cascader
v-if="scope.row.isManual == 1"
v-model="scope.row.maTypeIds"
placeholder="请选择类型名称"
:options="maTypeList"
:props="{ label: 'typeName', value: 'typeId' }"
filterable
clearable
:disabled="isDetail"
@change="selectedIds => getTypeList(scope.row, selectedIds, scope.$index)"
></el-cascader>
<span v-else>{{ scope.row.maTypeName }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="规格型号" prop="typeName" show-overflow-tooltip>
<template v-slot="scope">
<el-select
v-if="scope.row.isManual == 1"
v-model="scope.row.typeId"
clearable
filterable
placeholder="请选择规格型号"
:disabled="isDetail"
@change="val => changeTypeName(scope.row, val, getSelectedItemName(val, scope.row))"
>
<el-option
v-for="item in scope.row.typeList"
:key="item.typeId"
:label="item.name"
:value="item.typeId"
></el-option>
</el-select>
<span v-else>{{ scope.row.typeName }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="计量单位" prop="unitName" />
<el-table-column label="预领数量" prop="preNum" align="center">
<template v-slot="scope">
<el-input
v-model.number="scope.row.preNum"
controls-position="right"
type="number"
style="width: 100%"
:disabled="isDetail"
:min="0"
@input="
v =>
scope.row.unitValue == 1
? (scope.row.preNum = Number(v.replace(/[^\d.]/g, '')))
: (scope.row.preNum = Number(v.replace(/[^\d]/g, '')))
"
></el-input>
</template>
</el-table-column>
<!-- <el-table-column align="center" label="当前库存" prop="storageNum" /> -->
<!-- <el-table-column label="待出库数量" align="center" prop="alNum" show-overflow-tooltip /> -->
<el-table-column label="备注" prop="remark" align="center" label-width="500px">
<template v-slot="scope">
<el-input
v-model="scope.row.remark"
controls-position="right"
:disabled="isDetail"
style="width: 100%"
></el-input>
</template>
</el-table-column>
<el-table-column label="操作" align="center" v-if="!isDetail">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-delete"
style="color: red"
@click="handleDelete(scope.$index, scope.row)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 弹框 -->
<el-dialog title="领用申请" :visible.sync="dialogVisible" width="60%">
<el-form ref="dialogForm" :model="maForm" label-width="120px" inline>
<el-form-item label="领用单位:" prop="unitName">
<span>{{ maForm.unitName }}</span>
</el-form-item>
<el-form-item label="领用工程:" prop="projectName">
<span>{{ maForm.projectName }}</span>
</el-form-item>
<el-form-item label="领料人:" prop="leasePerson">
<span>{{ maForm.leasePerson }}</span>
</el-form-item>
<el-form-item label="联系电话:" prop="phone">
<span>{{ maForm.phone }}</span>
</el-form-item>
<el-form-item label="供货时间:" prop="supplierTime">
<span>{{ maForm.supplierTime }}</span>
</el-form-item>
<el-form-item label="供货地点:" prop="supplierPlace">
<span>{{ maForm.supplierPlace }}</span>
</el-form-item>
<el-form-item label="业务单号:" prop="code">
<span>{{ maForm.code }}</span>
</el-form-item>
</el-form>
<!-- 列表 -->
<el-table :data="equipmentList">
<el-table-column
v-for="item in dialogColumns"
:key="item.prop"
:label="item.label"
:prop="item.prop"
></el-table-column>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="handleConfirm(0)">提交申请</el-button>
<el-button @click="handleConfirm(1)">保 存</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { equipmentTypeTree } from '@/api/purchase/goodsArrived'
import { getListProject, getListUnite, getAgreement } from '@/api/lease/apply'
import {
getStandardConfigList,
getListsByConfigId,
addLeaseTask,
editLeaseTask,
getLeaseTaskDetail,
getCode
} from '@/api/business/index'
import { getEquipmentThreeTypeThree, getMaTypeOpt } from '@/api/ma/base'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
export default {
name: 'Index',
dicts: ['purchase_task_status'],
components: { Treeselect },
data() {
return {
id: '',
isEdit: false, // 是否编辑
isDetail: false, // 是否查看
// 遮罩层
loading: false,
loadingTwo: false,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
selectTreeProps: {
children: 'children',
label: 'name',
// multiple: false,
value: 'id'
// multiple: true,
},
//租赁单位
uniteList: [],
//租赁工程
projectList: [],
standardConfigList: [], //标准配置
//机具类型
equipmentTypeList: [],
// 角色表格数据
equipmentList: [],
// 弹出层标题
title: '',
// 是否显示弹出层
open: false,
rowData: {},
unitId: null,
projectId: null,
maForm: {
unitId: undefined,
projectId: undefined,
code: '', // 采购申请编号
supplierTime: '', // 供货时间
supplierPlace: '', // 供货地点
bmFileInfos: [], // 附件
fitNum: 1
},
lastFitNum: 1,
pickerOptions: {
disabledDate(time) {
// 禁用今天之前的日期
return time.getTime() < Date.now() - 86400000 // 86400000 是一天的毫秒数
}
},
// 表单参数
form: {},
defaultProps: {
children: 'children',
label: 'label'
},
// 表单校验
rules: {
unitId: [
{
required: true,
message: '请选择租赁单位',
trigger: 'blur'
}
],
projectId: [
{
required: true,
message: '请选择租赁工程',
trigger: 'blur'
}
],
leasePerson: [
{
required: true,
message: '请输入领料人',
trigger: 'blur'
}
],
phone: [
// { required: true, message: '联系电话不能为空', trigger: 'blur' },
{
pattern: /^(?:(?:\+|00)86)?1[3-9]\d{9}$/,
message: '请输入正确的手机号码',
trigger: 'blur'
}
],
supplierTime: [
{
required: true,
message: '请选择供货时间',
trigger: 'blur'
}
],
bmFileInfos: [
{
required: false, // 是否分包商(是:合同编号必填)
message: '请上传委托书',
trigger: 'change'
}
],
deviceType: [{ required: true, message: '请选择类型规格', trigger: 'blur' }]
},
maTypeList: [], // 类型名称
// 规格型号
typeList: [],
dialogVisible: false, // 弹框
// 弹框表单
dialogForm: {},
// 弹框表头
dialogColumns: [
{ label: '类型名称', prop: 'maTypeName' },
{ label: '规格型号', prop: 'typeName' },
{ label: '计量单位', prop: 'unitName' },
{ label: '预领数量', prop: 'preNum' },
{ label: '备注', prop: 'remark' }
],
deviceTypeTreeProps: {
children: 'children',
label: 'typeName',
value: 'typeId',
multiple: true,
emitPath: true
},
deviceType: [],
propsKey: 1000,
unitTemp: undefined,
agreementId: undefined,
// 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, // 添加搜索状态标记
//是否是分包商
isFileFbs: false,
urlTemp: '',
delBusinessFileIdList: [],
//图片查看弹窗
dialogImageUrl: '',
dialogVisible: false,
uploadKey: Date.now(),
uploadUrl: process.env.VUE_APP_BASE_API + '/file/upload', // 上传的图片服务器地址
currentTooltipItem: null,
tooltipPosition: { x: 0, y: 0 },
defaultImage: 'https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg',
tooltipTimeout: null
}
},
computed: {
//图片上传1张后隐藏上传框
uploadDisabled() {
return this.maForm.bmFileInfos && this.maForm.bmFileInfos.length == 5
}
},
watch: {
equipmentList(newVal) {
if (newVal && newVal.length > 0) {
// 设备列表有值设置deviceType为非必填
this.rules.deviceType = []
} else {
// 设备列表为空设置deviceType为必填
this.rules.deviceType = [{ required: true, message: '请选择类型规格', trigger: 'blur' }]
}
// 重置表单验证状态,避免旧的错误提示残留
this.$refs.maForm.clearValidate('deviceType')
},
// 监听一下路由的type
$route: {
handler(newVal) {
if (newVal.query.type == 'edit') {
this.isEdit = true
this.isDetail = false
this.id = newVal.query.id
const obj = Object.assign({}, newVal, { title: '领用申请编辑' })
this.$tab.updatePage(obj)
} else if (newVal.query.type == 'detail') {
this.isEdit = false
this.isDetail = true
this.id = newVal.query.id
const obj = Object.assign({}, this.$route, { title: '领用申请详情' })
this.$tab.updatePage(obj)
}
if (this.isEdit || this.isDetail) {
console.log('isEdit', this.isEdit)
this.getTaskInfo()
}
},
deep: true,
immediate: true
}
},
created() {
// getCode()
if (this.$route.query.type == 'edit') {
// this.isEdit = true
// this.isDetail = false
// this.id = this.$route.query.id
// const obj = Object.assign({}, this.$route, { title: '领用申请编辑' })
// this.$tab.updatePage(obj)
} else if (this.$route.query.type == 'detail') {
// this.isEdit = false
// this.isDetail = true
// this.id = this.$route.query.id
// const obj = Object.assign({}, this.$route, { title: '领用申请详情' })
// this.$tab.updatePage(obj)
} else {
this.isEdit = false
this.isDetail = false
this.id = ''
const obj = Object.assign({}, this.$route, { title: '领用申请' })
this.$tab.updatePage(obj)
}
this.projectInfoList() //单位工程下拉选
this.equipmentType() //机具类型下拉选
this.getStandardConfigList() // 标准配置下拉选
this.getMaTypeNameOpt() // 类型名称下拉选
// if (this.isEdit || this.isDetail) {
// console.log('isEdit', this.isEdit)
// this.getTaskInfo()
// }
console.log('🚀 ~ created ~ this.isDetail:', this.isDetail)
console.log(this.$store, 'this.$store.getters')
console.log(this.$route.query, 'this.$route.query')
},
methods: {
fitNumChange() {
const newVal = Math.min(5, Math.max(1, parseInt(this.maForm.fitNum) || 1))
const ratio = newVal / this.lastFitNum
this.equipmentList.forEach(item => {
if (typeof item.preNum === 'number') {
item.preNum = Math.max(1, Math.floor(item.preNum * ratio)) // 向下取整且至少为1
}
})
this.lastFitNum = newVal
this.maForm.fitNum = newVal
},
showCustomTooltip(item, event) {
clearTimeout(this.tooltipTimeout)
this.tooltipTimeout = setTimeout(() => {
this.currentTooltipItem = item
this.tooltipPosition = {
x: event.clientX + 15,
y: event.clientY + 15
}
}, 300) // 300ms延迟显示避免鼠标快速移动时频繁触发
},
imageLoaded() {
this.shouldShowTooltip = true // 图片加载完成,显示悬浮框
},
imageLoadError() {
this.shouldShowTooltip = true // 图片加载失败,也显示悬浮框
},
hideCustomTooltip() {
clearTimeout(this.tooltipTimeout)
this.currentTooltipItem = null
},
// 获取类型名称-tree
async getMaTypeNameOpt() {
try {
const res = await getEquipmentThreeTypeThree()
console.log('🚀 ~ getEquipmentThreeTypeThree ~ res:', res)
const filterData = (data, level = 1) => {
return data.map(item => {
if (level < 3 && item.children && item.children.length) {
item.children = filterData(item.children, level + 1)
} else {
delete item.children
}
return item
})
}
this.maTypeList = filterData(res.data)
console.log('🚀 ~ this.maTypeList:', this.maTypeList)
} catch (error) {
console.log('🚀 ~ error:', error)
}
},
// // 获取规格型号
// async getTypeList(row, typeIds) {
// console.log('🚀 ~ getTypeList ~ row:', row)
// console.log('🚀 ~ getTypeList ~ typeId:', typeIds[typeIds.length - 1])
// // 递归循环 获取类型名称
// const filterData = data => {
// data.forEach(item => {
// if (item.typeId === typeIds[typeIds.length - 1]) {
// row.maTypeName = item.typeName
// } else {
// if (item.children && item.children.length) {
// filterData(item.children)
// }
// }
// })
// }
// filterData(this.maTypeList)
// console.log('🚀 ~ getTypeList ~ maType:', row)
// row.typeId = ''
// row.unitName = ''
// try {
// const res = await getMaTypeOpt({ typeId: typeIds[typeIds.length - 1] })
// // console.log('🚀 ~ getMaTypeOpt ~ res:', res)
// this.typeList = res.data
// } catch (error) {
// console.log('🚀 ~ error:', error)
// }
// },
async getTypeList(row, typeIds, index) {
console.log('🚀 ~ getTypeList ~ row:', row)
// 递归循环 获取类型名称
const filterData = data => {
data.forEach(item => {
if (item.typeId === typeIds[typeIds.length - 1]) {
row.maTypeName = item.typeName
} else {
if (item.children && item.children.length) {
filterData(item.children)
}
}
})
}
filterData(this.maTypeList)
console.log('🚀 ~ getTypeList ~ maType:', row)
row.typeId = ''
row.unitName = ''
try {
if (typeIds.length === 0) {
// 如果 typeIds 为空,则清空 typeList
row.typeList = []
return
}
const res = await getMaTypeOpt({ typeId: typeIds[typeIds.length - 1] })
// 将每个条目的规格型号列表存储在各自的 row 对象中
this.equipmentList[index].typeList = res.data
} catch (error) {
console.log('🚀 ~ error:', error)
}
},
getSelectedItemName(typeId, row) {
const selectedItem = row.typeList.find(item => item.typeId === typeId)
return selectedItem ? selectedItem.name : ''
},
//
changeTypeName(row, val, name) {
console.log('🚀 ~ changeTypeName ~ row:', row)
console.log('🚀 ~ changeTypeName ~ val:', val)
this.equipmentList.some(item => {
// 跳过当前行
if (item === row) return false
if (item.typeId === val) {
this.$message({
message: `${name} 已添加到列表中`,
type: 'warning'
})
row.typeId = ''
return true
}
return false
})
// console.log('xxxxxxxxxxxxxxxxx', this.equipmentList.some(item => item.typeId === val))
// if (this.equipmentList.some(item => item.typeId === val)) {
// // console.log("yyyyyyyyyyy",item.typeId)
// console.log("zzzzzzzzz",val)
// this.$message({
// message: `${name} 已添加到列表中`,
// type: 'warning'
// })
// row.typeId = ''
// return
// }
const type = row.typeList.find(item => item.typeId === val)
// console.log('🚀 ~ changeTypeName ~ type:', type)
row.unitName = type.unitName
row.typeName = type.name
},
// 获取标准配置
async getStandardConfigList() {
try {
const res = await getStandardConfigList()
console.log('🚀 ~ getStandardConfigList ~ res:', res)
this.standardConfigList = res.data
} catch (error) {
console.log('🚀 ~ error:', error)
}
},
// 查看领料记录
handleApplyRecord() {
this.$router.push({ path: '/business/businessHandlingRecord/index' })
},
/** 转换菜单数据结构 */
normalizer(node) {
if (!Array.isArray(node.children) || node.children.length === 0) {
delete node.children
}
return {
id: node.id,
label: node.name,
children: node.children
}
},
uniteChange(val) {
// console.log('🚀 ~ uniteChange ~ val:', val)
this.maForm.unitName = val.name
if (val.typeKey == 'fbs') {
this.isFileFbs = true
this.rules['bmFileInfos'][0].required = true
} else {
this.isFileFbs = false
this.rules['bmFileInfos'][0].required = false
}
// setTimeout(() => {
// getListProject({ unitId: this.maForm.unitId }).then(response => {
// this.projectList = response.data
// this.maForm.projectId = null
// })
// }, 500)
},
projectChange(val) {
this.maForm.projectName = val.name
// setTimeout(() => {
// // projectId: this.maForm.projectId
// getListUnite({}).then(response => {
// this.uniteList = response.data
// })
// }, 500)
},
async standardConfigChange(val) {
console.log('🚀 ~ standardConfigChange ~ val:', val)
const loading = this.$loading()
try {
const params = {
configId: val.id
}
const res = await getListsByConfigId(params)
console.log('🚀 ~ standardConfigChange ~ res:', res)
// this.equipmentList.unshift(...res.data)
res.data.forEach(newItem => {
const existingItem = this.equipmentList.find(item => item.typeId === newItem.typeId)
if (existingItem) {
existingItem.preNum += newItem.preNum
} else {
this.equipmentList.unshift(newItem)
}
})
loading.close()
} catch (error) {
console.log('🚀 ~ error:', error)
loading.close()
}
},
/** 租赁单位和工程-下拉选 */
projectInfoList() {
if (!this.isEdit) {
getListUnite({ projectId: null, enableFilter: true }).then(response => {
this.uniteList = response.data
})
getListProject({ unitId: null, enableFilter: true }).then(response => {
this.projectList = response.data
})
} else {
getListUnite({ projectId: null, enableFilter: true }).then(response => {
this.uniteList = response.data
})
getListProject({ unitId: this.maForm.unitId, enableFilter: true }).then(response => {
this.projectList = response.data
})
}
},
/** 机具类型 */
equipmentType() {
equipmentTypeTree().then(response => {
console.log('🚀 ~ equipmentTypeTree ~ response:', response)
this.equipmentTypeList = response.data
// 处理并扁平化所有类型数据
this.flattenTypeOptions = this.processTypeData(response.data)
// 初始显示所有选项
this.filteredOptions = [...this.flattenTypeOptions]
// 反显选中数据
if (this.equipmentList && this.equipmentList.length > 0) {
this.deviceType = this.equipmentList.map(item => item.typeId)
}
})
},
// 处理类型数据
processTypeData(data) {
const result = []
const traverse = (node, parents = []) => {
const path = [...parents, node.typeName]
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
})
}
if (node.children) {
node.children.forEach(child => traverse(child, path))
}
}
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.tempDeviceType = []
})
},
//获取任务详情--- 编辑回显数据
async getTaskInfo() {
const loading = this.$loading()
try {
const res = await getLeaseTaskDetail(this.id)
console.log('🚀 ~ getTaskInfo ~ res:', res)
this.maForm = res.data.leaseApplyInfo
this.maForm.unitId = res.data.leaseApplyInfo.leaseUnitId
this.maForm.projectId = res.data.leaseApplyInfo.leaseProjectId
this.equipmentList = res.data.leaseApplyDetailsList
// 如果 bmFileInfos有值
if (this.maForm.bmFileInfos && this.maForm.bmFileInfos.length > 0) {
this.isFileFbs = true
}
loading.close()
} catch (error) {
console.log('🚀 ~ error:', error)
loading.close()
}
},
//单位,工程树结构数据获取父
treeParentsById(list, id) {
for (let i in list) {
if (list[i].id == id) {
//查询到就返回该数组对象的value
return [list[i].id]
}
if (list[i].children) {
let node = this.treeParentsById(list[i].children, id)
if (node !== undefined) {
//查询到把父节把父节点加到数组前面
node.unshift(list[i].id)
return node
}
}
}
},
// 多选框选中数据
handleSelectionChange() {},
// 新增条目
addColumns() {
// 头部新增一天空数据
this.equipmentList.push({
isManual: 1,
maTypeIds: [],
maTypeName: '',
typeId: '',
typeName: '',
preNum: 0,
remark: '',
typeList: []
})
},
/** 保存按钮操作 */
handleSave() {
// console.log(this.equipmentList)
console.log('maForm', this.maForm)
if (this.equipmentList.length > 0) {
this.$refs['maForm'].validate(async valid => {
if (valid) {
for (let i = 0; i < this.equipmentList.length; i++) {
if (!this.equipmentList[i].typeId) {
this.$message.error(`第 ${i + 1} 行的 ${'规格型号'} 不能为空`)
return
}
if (this.equipmentList[i].preNum <= 0) {
this.$message.error(`第 ${i + 1} 行的 ${'预领数量必须大于0'} `)
return
}
// if (this.equipmentList[i].preNum > this.equipmentList[i].storageNum) {
// this.$message.error(`第 ${i + 1} 行的 ${'预领数量不可大于库存量'} `)
// return
// }
}
// 获取业务单号
const res = await getCode()
console.log('🚀 ~ handleSave ~ res:', res)
if (res.code === 200) {
this.maForm.code = res.data.taskCode
}
// 打开弹框
this.dialogVisible = true
}
})
} else {
this.$modal.msgError('请先添加类型规格')
}
},
// 确认
async handleConfirm(type) {
// await getAgreement({
// unitId: this.maForm.unitId,
// projectId: this.maForm.projectId
// }).then(response => {
// if(response.msg==="未找到匹配的协议信息"){
// this.maForm.agreementId = null
// }else{
// this.agreementId = response.data.agreementId
// this.maForm.agreementId = this.agreementId
// }
// })
await this.$modal
.confirm(type == 0 ? '是否确认提交' : '是否确认保存')
.then(async () => {
const params = {
leaseApplyDetailsList: this.equipmentList,
leaseApplyInfo: this.maForm,
statusFlag: type
}
if (this.isEdit) {
try {
const res = await editLeaseTask(params)
if (res.code === 200) {
this.$modal.msgSuccess('操作成功')
// 关闭页面
this.$tab.closePage()
}
this.loading = false
} catch (error) {
console.log('🚀 ~ error:', error)
this.loading = false
}
} else if (!this.isEdit) {
console.log('新增')
console.log(this.equipmentList)
try {
const res = await addLeaseTask(params)
if (res.code === 200) {
this.$modal.msgSuccess('操作成功')
this.$refs['maForm'].resetFields()
this.equipmentList = []
// 关闭弹框
this.dialogVisible = false
}
} catch (error) {
console.log('🚀 ~ error:', error)
}
}
})
.catch(() => {})
},
/** 删除按钮操作 */
handleDelete(index, row) {
console.log('🚀 ~ handleDelete ~ row:', row)
this.$modal
.confirm('是否确认删除所选择的数据项?')
.then(() => {
this.equipmentList.splice(index, 1)
// 更新实际存储的选中值
this.deviceType = this.equipmentList.map(item => item.typeId)
})
.catch(() => {})
},
//委托书文件
handleChangeBusinessList(file, fileList) {
const fileListTemp = fileList.filter(item => {
return item.uid != file.uid
})
const parts = file.name.split('.')
const extension = parts.pop().toLowerCase()
if (fileList.length > 5) {
this.$message.warning('最多上传5张附件')
fileList = fileList.filter(item => {
return item.uid != file.uid
})
} else if (!(extension === 'pdf' || extension === 'png' || extension === 'jpg' || extension === 'jpeg')) {
this.$message.warning('文件格式不正确')
fileList = fileList.filter(item => {
return item.uid != file.uid
})
} else if (file.size > 1024 * 1024 * 10) {
this.$message.warning('文件大小不能超过10Mb')
fileList = fileList.filter(item => {
return item.uid != file.uid
})
} else if (file.name.length > 40) {
this.$message.warning('文件名长度不能超过40个字符')
fileList = fileList.filter(item => {
return item.uid != file.uid
})
} else if (fileListTemp.some(item => item.name === file.name)) {
this.$message.warning('文件名重复')
fileList = fileList.filter(item => {
return item.uid != file.uid
})
}
fileList.forEach(file => {
if (extension === 'pdf') {
this.urlTemp = require('@/assets/file.png')
}
})
this.maForm.bmFileInfos = fileList
// console.log('🚀 ~ handleChangeBusinessList ~ this.bmFileInfos:', this.bmFileInfos)
// 手动触发表单验证
this.$refs.maForm.validateField('bmFileInfos')
},
isImage(file) {
this.urlTemp = require('@/assets/file.png')
if (this.updataIf(file)) {
return false
} else {
return true
}
},
// 判断文件类型,图片预览,文件下载
updataIf(e) {
if (e.fileName) {
const parts = e.fileName.split('.')
const extension = parts.pop().toLowerCase()
if (extension === 'png' || extension === 'jpeg' || extension === 'jpg') {
return false
} else {
return true
}
} else {
const parts = e.name.split('.')
const extension = parts.pop().toLowerCase()
if (extension === 'png' || extension === 'jpeg' || extension === 'jpg') {
return false
} else {
return true
}
}
},
//上传组件-图片查看
picturePreviewFbs(file) {
this.dialogImageUrl = file.url.replaceAll('#', '%23')
const parts = file.name.split('.')
const extension = parts.pop()
if (extension === 'pdf') {
const windowName = file.name
window.open(file.url, windowName)
} else {
this.dialogVisible = true
}
},
//上传组件-图片删除
handleRemoveElectricianImgList(file, fileList) {
let sum = 0
this.maForm.bmFileInfos.forEach((item, index) => {
if (item.uid == file.uid) {
sum = index
}
})
this.maForm.bmFileInfos.splice(sum, 1)
if (file.status == 'success') {
this.delBusinessFileIdList.push(file.url)
}
console.log('delBusinessFileIdList', this.delBusinessFileIdList)
},
handleDownload(file) {
console.log(file)
if (file.status === 'ready') {
downloadFile({
fileName: file.name,
fileData: file.raw,
fileType: 'application/vnd.ms-excel;charset=utf-8'
})
} else if (file.status === 'success') {
downloadFileData({ fileName: file.name, fileUrl: file.url })
// downloadFileData({ fileName: file.name,fileUrl:file.url })
}
},
// 高亮文本
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('.type-select-dropdown')
const optionDom = selectDom?.querySelector(`[data-key="${option.typeId}"]`)
if (optionDom) {
optionDom.scrollIntoView({ block: 'center', behavior: 'smooth' })
}
},
// 导出数据
handleExport() {
try {
const formatTime = date => {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
const seconds = String(date.getSeconds()).padStart(2, '0')
return `${year}${month}${day}_${hours}${minutes}${seconds}`
}
const currentTime = formatTime(new Date())
let fileName = `工器具清单_${currentTime}.xLsx`
let url = '/material/leaseTask/export'
const params = { ...this.queryParams }
console.log('🚀 ~ 导出 ~ params:', params)
this.download(url, params, fileName)
} catch (error) {
console.log('导出数据失败', error)
}
}
},
// 添加组件销毁时的清理
beforeDestroy() {
this.keepSelectOpen = false
this.isSearching = false
}
}
</script>
<style lang="scss" scoped>
//隐藏图片上传框的css
::v-deep.disabledFbs {
.el-upload--picture-card {
display: none;
}
}
::v-deep .el-upload-list__item {
margin-bottom: 20px;
overflow: unset !important;
}
::v-deep .el-upload-list__item-actions {
overflow: unset !important;
}
.popper-select {
.el-cascader-panel .el-scrollbar .el-checkbox {
display: none;
}
.el-cascader-panel .el-scrollbar:nth-child(4) .el-checkbox {
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;
// }
::v-deep .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;
}
}
.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;
}
}
}
.el-upload-list__item-thumbnail {
height: 145px !important;
}
.picture-card-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
}
.picture-card {
width: 100%;
height: 100%;
object-fit: cover;
justify-content: center;
// border: 1px solid #ddd;
// border-radius: 4px;
}
.file-name {
width: 90%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
position: absolute;
bottom: -35px;
margin-top: 8px;
text-align: center;
font-size: 12px;
color: #333;
z-index: 999999;
}
.file-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
color: #fff;
font-size: 20px;
}
.type-tooltip {
max-width: none !important;
}
.custom-tooltip {
position: fixed;
z-index: 9999;
background: rgb(6, 6, 6);
border: 1px solid #ebeef5;
border-radius: 4px;
padding: 12px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
pointer-events: none;
max-width: 250px;
color: white;
}
</style>