You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1157 lines
38 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="table-page-container">
<div ref="lxHeader">
<lx-header icon="md-apps" text="维护规则" style="margin-bottom: 10px; border: 0px; margin-top: 15px">
<slot>
<div style="display: flex;justify-content: flex-end;flex-wrap: wrap;">
<Button type="primary" @click="showAddRuleModal"></Button>
</div>
</slot>
</lx-header>
</div>
<div class="table-flex-content">
<xy-table
:list="list"
:total="total"
:table-item="table"
size="medium"
:height="tableHeight"
style="border-radius: 10px; overflow: hidden; box-shadow: 0 2px 12px 0 rgba(0,0,0,0.08); width: 100%;"
@pageSizeChange="pageSizeChange"
@pageIndexChange="pageChange"
>
<template v-slot:btns>
<el-table-column label="操作" width="240" header-align="center" class-name="table-col-action">
<template slot-scope="scope">
<div>
<Button type="primary" size="small" style="margin-left: 10px;" @click="handleEdit(scope.row)"></Button>
<Poptip transfer confirm title="确认要删除吗?" @on-ok="handleDelete(scope.row)">
<Button type="error" style="margin-left: 10px;" size="small" ghost>删除</Button>
</Poptip>
<!-- <Button type="primary" size="small" ghost @click="">删除</Button> -->
<Button type="primary" size="small" style="margin-left: 10px;" ghost @click="handleAssociate(scope.row)"></Button>
</div>
</template>
</el-table-column>
</template>
</xy-table>
</div>
<!-- 新增规则 Modal -->
<Modal v-model="showModal" title="新增维护规则" :footer="null" @on-cancel="handleCancel">
<Form ref="form" :model="form" :rules="rules" :label-width="120">
<FormItem label="规则名称" prop="name">
<Input v-model="form.name" placeholder="请输入规则名称" />
</FormItem>
<FormItem label="重复周期" prop="cycle">
<Select v-model="form.cycle">
<Option v-for="item in cycleOptions" :key="item.value" :value="item.value">{{ item.label }}</Option>
</Select>
</FormItem>
<FormItem label="起始日期设定" prop="startSetting">
<Select v-model="form.startSetting">
<Option v-for="item in startStandardOptions" :key="item.value" :value="item.value">{{ item.label }}</Option>
</Select>
</FormItem>
<!-- <FormItem label="生成计划时机" prop="timing">
<div class="timing-controls">
<Select v-model="form.timingUnit" style="width: 80px">
<Option value="days">提前</Option>
</Select>
<InputNumber v-model="form.timingValue" :min="1" style="width: 80px" />
<Select v-model="form.timingPeriod" style="width: 80px">
<Option value="days">天</Option>
</Select>
</div>
</FormItem> -->
<FormItem label="未完成时下次计划" prop="nextPlan">
<Select v-model="form.nextPlan">
<Option v-for="item in nextPlanOptions" :key="item.value" :value="item.value">{{ item.label }}</Option>
</Select>
</FormItem>
<FormItem label="备注" prop="notes">
<Input v-model="form.notes" type="textarea" :rows="3" placeholder="请输入备注" />
</FormItem>
</Form>
<div slot="footer" style="text-align: right;">
<Button @click="handleCancel">取消</Button>
<Button type="primary" style="margin-left: 8px;" @click="handleCustomSubmit">确定</Button>
</div>
</Modal>
<!-- 编辑规则 Modal -->
<Modal v-model="showEditModal" title="编辑维护规则" @on-ok="handleEditSubmit" @on-cancel="handleEditCancel">
<Form ref="editForm" :model="editForm" :rules="rules" :label-width="120">
<FormItem label="规则名称" prop="name">
<Input v-model="editForm.name" placeholder="请输入规则名称" />
</FormItem>
<FormItem label="重复周期" prop="cycle">
<Select v-model="editForm.cycle">
<Option v-for="item in cycleOptions" :key="item.value" :value="item.value">{{ item.label }}</Option>
</Select>
</FormItem>
<FormItem label="起始日期设定" prop="startSetting">
<Select v-model="editForm.startSetting">
<Option v-for="item in startStandardOptions" :key="item.value" :value="item.value">{{ item.label }}</Option>
</Select>
</FormItem>
<!-- <FormItem label="生成计划时机" prop="timing">
<div class="timing-controls">
<Select v-model="editForm.timingUnit" style="width: 80px">
<Option value="days">提前</Option>
</Select>
<InputNumber v-model="editForm.timingValue" :min="1" style="width: 80px" />
<Select v-model="editForm.timingPeriod" style="width: 80px">
<Option value="days">天</Option>
</Select>
</div>
</FormItem> -->
<FormItem label="未完成时下次计划" prop="nextPlan">
<Select v-model="editForm.nextPlan">
<Option v-for="item in nextPlanOptions" :key="item.value" :value="item.value">{{ item.label }}</Option>
</Select>
</FormItem>
<FormItem label="备注" prop="notes">
<Input v-model="editForm.notes" type="textarea" :rows="3" placeholder="请输入备注" />
</FormItem>
</Form>
</Modal>
<!-- 关联物资 Modal -->
<Modal v-model="showAssociateModal" title="关联物资" width="1000" @on-ok="handleAssociateSubmit" @on-cancel="handleAssociateCancel">
<div class="associate-content">
<div class="associate-toolbar">
<Input v-model="associateSearch" placeholder="搜索物资名称..." style="width: 250px; margin-right: 10px;" clearable />
<el-cascader
size="small"
v-model="associateFenlei"
:options="fenleiList"
:props="{label:'name',value:'id'}"
placeholder="选择分类"
style="width: 250px; margin-right: 10px;"
clearable
@change="changeAssociateFenlei"
/>
<!-- <Select v-model="select.storehouses_id" style="width: 120px; margin-right: 10px;" clearable placeholder="仓库类型" @on-change="getWarehouseNames">
<Option v-for="item in warehouseTypes" :key="item.id" :value="item.id">{{ item.name }}</Option>
</Select> -->
<!-- <Select v-model="select.area" style="width: 120px; margin-right: 10px;" clearable placeholder="所在区域" @on-change="getWarehouseNames">
<Option v-for="item in warehouseAreas" :key="item.id" :value="item.value">{{ item.value }}</Option>
</Select> -->
<!-- <Select v-model="associateWarehouseName" style="width: 120px; margin-right: 10px;" clearable placeholder="仓库名称">
<Option v-for="warehouse in warehouseNames" :key="warehouse.value" :value="warehouse.label">{{ warehouse.label }}</Option>
</Select> -->
<Button type="primary" @click="searchMaterialsPost">搜索</Button>
<Button style="margin-left: 8px;" @click="resetAssociateSearch">重置</Button>
</div>
<div class="batch-operations" style="margin-bottom: 15px;">
<Button type="primary" @click="batchAssociate" :disabled="!hasSelectedItems || isAssociating || isDisassociating" :loading="isAssociating">
{{ isAssociating ? '关联中...' : '批量关联' }}
</Button>
<Button type="error" style="margin-left: 8px;" @click="batchDisassociate" :disabled="!hasSelectedItems || isAssociating || isDisassociating" :loading="isDisassociating">
{{ isDisassociating ? '...' : '' }}
</Button>
<span style="margin-left: 15px; color: #666;">已选择 {{ selectedItems.length }} </span>
</div>
<Table :columns="associateColumns" :data="associateList" :height="400" style="margin-top: 15px;" @on-selection-change="handleSelectionChange">
<template slot="action" slot-scope="{ row }">
<div style="display: flex; gap: 8px; justify-content: center;">
<!--
<Button
v-else-if="row.equipment_maintain_config"
type="warning"
size="small"
ghost
style="border-radius: 6px;"
:title="row.equipment_maintain_config ? `已关联规则: ${row.equipment_maintain_config.name}` : ''"
@click="toggleAssociation(row)"
>
重新绑定
</Button> -->
<Button
v-if="isMaterialAssociated(row)"
type="error"
size="small"
ghost
style="border-radius: 6px;"
@click="toggleAssociation(row)"
>
解除绑定
</Button>
<Button
v-else
type="primary"
size="small"
ghost
style="border-radius: 6px;"
@click="toggleAssociation(row)"
>
绑定
</Button>
</div>
</template>
</Table>
<div class="pagination-container">
<el-pagination
:current-page="associateCurrentPage"
:page-sizes="[10, 20, 30, 50, 100]"
:page-size="associatePageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="associateTotal"
@size-change="handleAssociatePageSizeChange"
@current-change="handleAssociatePageChange"
/>
</div>
</div>
</Modal>
</div>
</template>
<script>
import { Button, Modal, Form, FormItem, Input, Select, Option, InputNumber, Table } from 'view-design'
import { getStorehouseTypeList } from '@/api/system/storehouseType'
import { getparameteritem } from '@/api/system/dictionary.js'
import { index } from '@/api/system/baseForm.js'
import { saveMaintainConfig, getMaintainConfigList, deleteMaintainConfig } from '@/api/maintenance/maintenance.js'
import { saveStocksItem } from '@/api/stocks-item.js'
import request from '@/utils/request'
import qs from 'qs'
import { index as getFenleilist } from '@/api/fenlei.js'
export default {
components: {
Button,
Modal,
Form,
FormItem,
Input,
Select,
Option,
InputNumber,
Table
},
data() {
return {
select: {
page: 1,
page_size: 999,
keyword: '',
table_name: 'materialstorages',
area: '',
storehouses_id: ''
},
total: 0,
list: [],
cycleOptions: [
{ value: '0.5', label: '每半月' },
{ value: '1.0', label: '每月' },
{ value: '3.0', label: '每季度' },
{ value: '6.0', label: '每半年' },
{ value: '12.0', label: '每年' }
],
startStandardOptions: [
{ value: '1', label: '从每年第一天开始运算' },
{ value: '2', label: '首次关联物资时' }
],
nextPlanOptions: [
{ value: '1', label: '暂停生成(直到上次计划已经执行完成)' },
{ value: '2', label: '强制生成(忽略未完成状态)' }
],
table: [
{ label: '序号', type: 'index', width: 60 },
{ label: '规则名称', prop: 'name', minWidth: 160 },
{ label: '重复周期', prop: 'month_frequency', minWidth: 120, formatter: row => this.cycleOptions.find(opt => opt.value == row.month_frequency)?.label || row.month_frequency },
{ label: '起始日期设定', prop: 'start_standard', minWidth: 160, formatter: row => this.startStandardOptions.find(opt => opt.value == row.start_standard)?.label || row.start_standard },
// { label: '生成计划时机(天)', prop: 'advance_days', minWidth: 120 },
// { label: '生成计划时机(天)', prop: 'advance_days', minWidth: 120 },
{
label: '已用于物资数',
prop: 'equipment_maintain_config_material_infos',
minWidth: 120,
formatter: row => row.equipment_maintain_config_material_infos ? row.equipment_maintain_config_material_infos.length : 0
},
{ label: '未完成时下次计划', prop: 'next_plan_type', minWidth: 160, formatter: row => this.nextPlanOptions.find(opt => opt.value == row.next_plan_type)?.label || row.next_plan_type }
],
tableHeight: 550,
showModal: false,
showEditModal: false,
showAssociateModal: false,
form: {
name: '',
cycle: '',
startSetting: '',
timingUnit: 'days',
timingValue: 7,
timingPeriod: 'days',
nextPlan: '',
notes: ''
},
editForm: {
name: '',
cycle: '',
startSetting: '',
timingUnit: 'days',
timingValue: 7,
timingPeriod: 'days',
nextPlan: '',
notes: ''
},
rules: {
name: [{ required: true, message: '请输入规则名称', trigger: 'blur' }],
cycle: [{ required: true, message: '请选择重复周期', trigger: 'change' }],
startSetting: [{ required: true, message: '请选择起始日期设定', trigger: 'change' }],
nextPlan: [{ required: true, message: '请选择未完成时下次计划', trigger: 'change' }]
},
associateSearch: '',
associateWarehouseName: '',
associatePageSize: 30,
associateCurrentPage: 1,
associateTotal: 0,
associateFenlei: '',
fenleiList: [],
associateColumns: [
{
type: 'selection',
width: 60,
align: 'center'
},
{
title: '已关联规则',
key: 'equipment_maintain_config_material_infos',
minWidth: 180,
render: (h, params) => {
const relations = params.row.equipment_maintain_config_material_infos
if (!relations || relations.length === 0) {
return h('span', '-')
}
// 如果有多个规则,每行显示一个
if (relations.length === 1) {
const rule = relations[0]
return h('span', rule.equipment_maintain_config && rule.equipment_maintain_config.name ? rule.equipment_maintain_config.name : '-')
} else {
// 多个规则,每行显示一个
const ruleElements = relations.map(rule => {
const ruleName = rule.equipment_maintain_config && rule.equipment_maintain_config.name ? rule.equipment_maintain_config.name : '-'
return h('div', { style: 'line-height: 1.5; margin-bottom: 2px;' }, ruleName)
})
return h('div', ruleElements)
}
}
},
{
title: '物资名称',
key: 'zichanmingcheng',
minWidth: 180
},
{
title: '所属种类',
key: 'fenlei_detail',
minWidth: 180,
render: (h, params) => {
const relation = params.row.fenlei_detail
return h('span', relation && relation.name ? relation.name : '-')
}
},
{
title: '物资类型',
key: 'wuzileixing',
minWidth: 120
},
{
title: '物资型号',
key: 'guigexinghao',
minWidth: 120
},
{
title: '物资规格',
key: 'wuziguige',
minWidth: 120
},
{
title: '单位',
key: 'jiliangdanwei',
minWidth: 80
},
{
title: '储备年限',
key: 'chubeinianxian',
minWidth: 80
},
{
title: '存放要求',
key: 'cunfangyaoqiu',
minWidth: 120
},
{
title: '维护要求',
key: 'weihuyaoqiu',
minWidth: 120
},
{
title: '保养频次',
key: 'equipment_maintain_config_id_equipment_maintain_configs_id_relation',
minWidth: 120,
render: (h, params) => {
const relation = params.row.equipment_maintain_config_id_equipment_maintain_configs_id_relation
return h('span', relation && relation.name ? relation.name : '-')
}
},
{
title: '备注',
key: 'beizhu',
minWidth: 240
},
{
title: '操作',
slot: 'action',
width: 200,
fixed: 'right',
align: 'center',
headerAlign: 'center',
className: 'table-col-action'
}
],
associateList: [],
currentRule: null,
ruleAssociations: new Map(),
warehouseTypes: [],
warehouseAreas: [],
warehouseNames: [],
allWarehouses: [],
currentWarehouseNames: [],
selectedItems: [],
hasSelectedItems: false,
isSelecting: false,
isAssociating: false,
isDisassociating: false,
selectionTimer: null
}
},
watch: {
associateWarehouseArea(val) {
if (val) {
this.getWarehouseNames(val)
} else {
this.warehouseNames = []
}
}
},
created() {
this.getList()
this.getWarehouseTypes()
this.getWarehouseAreas()
this.getWarehouseNames()
},
mounted() {
this.calcTableHeight()
window.addEventListener('resize', this.calcTableHeight)
},
beforeDestroy() {
window.removeEventListener('resize', this.calcTableHeight)
// 清理选择定时器
if (this.selectionTimer) {
clearTimeout(this.selectionTimer)
}
},
methods: {
async getList() {
try {
const res = await getMaintainConfigList({
page: this.select.page,
page_size: this.select.page_size
// 可加其它筛选参数
})
if (res && res.data) {
this.list = res.data
this.total = res.total
}
} catch (e) {
this.$message.error('获取运维规则列表失败')
}
},
pageChange(e) {
this.select.page = e
this.getList()
},
pageSizeChange(e) {
this.select.page_size = e
this.getList()
},
calcTableHeight() {
const header = this.$refs.lxHeader ? this.$refs.lxHeader.offsetHeight : 0
const windowHeight = window.innerHeight
const minTableHeight = 600
this.tableHeight = Math.max(windowHeight - header - 100, minTableHeight)
},
showAddRuleModal() {
this.form = {
name: '',
cycle: '',
startSetting: '',
timingUnit: 'days',
timingValue: 7,
timingPeriod: 'days',
nextPlan: '',
notes: ''
}
this.showModal = true
this.$nextTick(() => {
if (this.$refs.form) {
this.$refs.form.resetFields()
}
})
},
handleCancel() {
this.showModal = false
this.$refs.form.resetFields()
},
handleEdit(row) {
this.currentRule = row
this.editForm = {
name: row.name,
cycle: String(row.month_frequency),
startSetting: String(row.start_standard),
timingUnit: 'days',
timingValue: row.advance_days,
timingPeriod: 'days',
nextPlan: String(row.next_plan_type),
notes: row.remark || ''
}
this.showEditModal = true
},
handleEditSubmit() {
this.$refs.editForm.validate(async(valid) => {
if (valid) {
const data = {
id: this.currentRule.id,
name: this.editForm.name,
month_frequency: this.editForm.cycle,
start_standard: this.editForm.startSetting,
advance_days: this.editForm.timingValue,
next_plan_type: this.editForm.nextPlan,
remark: this.editForm.notes
}
try {
await saveMaintainConfig(data)
this.$message.success('编辑成功')
this.showEditModal = false
this.getList()
} catch (e) {
this.$message.error('编辑失败')
}
} else {
this.$message.error('请填写所有必填项')
}
})
},
handleEditCancel() {
this.showEditModal = false
this.$refs.editForm.resetFields()
},
handleDelete(row) {
this.currentRule = row
this.$confirm('确认要删除该维护规则吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async() => {
try {
await deleteMaintainConfig({ id: this.currentRule.id })
this.$message.success('删除成功')
this.getList()
} catch (e) {
this.$message.error('删除失败')
}
})
},
handleAssociate(row) {
this.currentRule = row
// 重置弹窗相关数据
this.associateSearch = ''
this.associateFenlei = ''
this.select.storehouses_id = ''
this.select.area = ''
this.associateWarehouseName = ''
this.associateCurrentPage = 1
// 重置选择状态
this.selectedItems = []
this.hasSelectedItems = false
// 重置操作状态
this.isAssociating = false
this.isDisassociating = false
// 先关闭再打开,确保弹窗能弹出
this.showAssociateModal = false
this.$nextTick(() => {
this.showAssociateModal = true
this.loadAssociations()
this.getFenlei()
// 重置分页到第一页
this.associateCurrentPage = 1
// 重置物资列表
this.associateList = []
this.associateTotal = 0
// 重新获取物资列表
this.searchMaterialsPost()
})
},
loadAssociations() {
// Load saved associations from localStorage
const saved = localStorage.getItem('ruleAssociations')
if (saved) {
const parsed = JSON.parse(saved)
Object.entries(parsed).forEach(([ruleId, materials]) => {
this.ruleAssociations.set(ruleId, new Set(materials))
})
}
},
async getFenlei() {
try {
const res = await getFenleilist({
tree: 1,
sort_type: 'ASC',
sort_name: 'sort'
})
this.fenleiList = this.removeEmptyChildren(res)
} catch (e) {
console.error('获取分类列表失败:', e)
this.$message.error('获取分类列表失败')
}
},
changeAssociateFenlei(e) {
if (e) {
this.associateFenlei = e[e.length - 1]
} else {
this.associateFenlei = ''
}
},
// 移除children=[]
removeEmptyChildren(node) {
if (Array.isArray(node)) {
return node.map(child => {
if (child.children) {
// 递归处理子节点
child.children = this.removeEmptyChildren(child.children);
// 若处理后 children 为空,删除该属性
if (child.children.length === 0) {
delete child.children;
}
}
return child;
});
}
return [];
},
// 判断物资是否已关联到当前规则
isMaterialAssociated(material) {
if (!this.currentRule || !this.currentRule.equipment_maintain_config_material_infos) {
return false
}
return this.currentRule.equipment_maintain_config_material_infos.some(
item => item.material_info_id === material.id
)
},
saveAssociations() {
const serialized = {}
this.ruleAssociations.forEach((materials, ruleId) => {
serialized[ruleId] = Array.from(materials)
})
localStorage.setItem('ruleAssociations', JSON.stringify(serialized))
},
async searchMaterialsPost() {
try {
const data = {
page_size: this.associatePageSize,
page: this.associateCurrentPage,
'show_relation[0]': 'equipmentMaintainConfig',
'show_relation[1]': 'materialInfo.materialstorage',
'materialstorages_cangkumingcheng': this.associateWarehouseName ? this.associateWarehouseName : '',
'materialstorages_suozaiquyu': this.select.area ? this.select.area : '',
'storehouses_id': this.select.storehouses_id ? this.select.storehouses_id : '',
'filter[0][key]': 'zichanmingcheng',
'filter[0][op]': 'like',
'filter[0][value]': this.associateSearch ? this.associateSearch : '',
// 'filter[1][key]': 'wuzileixing',
// 'filter[1][op]': 'eq',
// 'filter[1][value]': '一物一码'
}
// 如果选择了分类,添加分类筛选
if (this.associateFenlei) {
data['filter[1][key]'] = 'fenlei'
data['filter[1][op]'] = 'eq'
data['filter[1][value]'] = this.associateFenlei
}
const res = await request({
url: '/api/admin/material-infos/index',
method: 'post',
data: qs.stringify(data),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
if (res && res.data) {
this.associateList = res.data.map(material => ({
...material,
selected: this.ruleAssociations.get(this.currentRule.id)?.has(material.id) || false
}))
this.associateTotal = res.total
// 重置选择状态
this.selectedItems = []
this.hasSelectedItems = false
}
} catch (e) {
console.error('获取物资种类列表失败:', e)
this.$message.error('获取物资种类失败')
}
},
async toggleAssociation(row) {
if (!this.currentRule) return
let equipment_maintain_config_material_infos = this.currentRule.equipment_maintain_config_material_infos
console.log("this.currentRule",this.currentRule,row)
const targetIndex = this.currentRule.equipment_maintain_config_material_infos.findIndex(
item => item.material_info_id === row.id
);
// 3. 若找到对应项(索引不为 -1则删除该项
console.log("targetIndex",targetIndex)
if (targetIndex !== -1) {
equipment_maintain_config_material_infos.splice(targetIndex, 1); // splice(索引, 删除数量)
}else{
equipment_maintain_config_material_infos.push({
material_info_id:row.id,
equipment_maintain_config_time:''
})
}
console.log("equipment_maintain_config_material_infos",equipment_maintain_config_material_infos)
// return
await saveMaintainConfig({
id:this.currentRule.id,
equipment_maintain_config_material_infos:equipment_maintain_config_material_infos
})
this.$message.success('操作成功')
this.getList()
this.searchMaterialsPost()
return
if (row.equipment_maintain_config?.id === this.currentRule.id) {
// 解除绑定
try {
await saveStocksItem({
id: row.id,
equipment_maintain_config_id: null
})
this.$message.success('已解除绑定物资')
this.searchMaterialsPost()
} catch (e) {
this.$message.error('解除绑定失败')
}
} else {
// 绑定
try {
// await saveStocksItem({
// id: row.id,
// equipment_maintain_config_id: this.currentRule.id
// })
let equipment_maintain_config_material_infos = []
if(this.currentRule.material_info.length>0){
}else{
equipment_maintain_config_material_infos.push({
material_info_id:row.id,
equipment_maintain_config_time:''
})
}
await saveMaintainConfig({
id:this.currentRule.id,
})
this.$message.success('已成功绑定物资')
this.searchMaterialsPost()
} catch (e) {
this.$message.error('绑定失败:' + e.message)
}
}
},
updateMaterialCount() {
const count = this.ruleAssociations.get(this.currentRule.id)?.size || 0
const index = this.list.findIndex(item => item.id === this.currentRule.id)
if (index !== -1) {
this.$set(this.list[index], 'materialCount', count)
}
},
handleAssociatePageChange(page) {
this.associateCurrentPage = page
this.searchMaterialsPost()
},
handleAssociateSubmit() {
this.showAssociateModal = false
// 弹窗关闭时重置列表状态
this.associateList = []
this.associateTotal = 0
this.associateCurrentPage = 1
this.selectedItems = []
this.hasSelectedItems = false
this.getList()
},
handleAssociateCancel() {
this.showAssociateModal = false
// 弹窗关闭时重置列表状态
this.associateList = []
this.associateTotal = 0
this.associateCurrentPage = 1
this.selectedItems = []
this.hasSelectedItems = false
},
handleSelectionChange(selection) {
// 防抖处理,避免频繁更新导致的卡顿
if (this.selectionTimer) {
clearTimeout(this.selectionTimer)
}
this.selectionTimer = setTimeout(() => {
this.selectedItems = selection
this.hasSelectedItems = selection.length > 0
}, 100)
},
async batchAssociate() {
if (this.selectedItems.length === 0) {
this.$message.warning('请先选择需要关联的物资')
return
}
this.isAssociating = true
try {
let equipment_maintain_config_material_infos = [...(this.currentRule.equipment_maintain_config_material_infos || [])]
// 批量添加选中的物资
this.selectedItems.forEach(item => {
const existingIndex = equipment_maintain_config_material_infos.findIndex(
existing => existing.material_info_id === item.id
)
if (existingIndex === -1) {
equipment_maintain_config_material_infos.push({
material_info_id: item.id,
equipment_maintain_config_time: ''
})
}
})
await saveMaintainConfig({
id: this.currentRule.id,
equipment_maintain_config_material_infos: equipment_maintain_config_material_infos
})
this.$message.success(`批量关联成功,共关联 ${this.selectedItems.length} 项物资`)
this.selectedItems = []
this.hasSelectedItems = false
this.getList()
this.searchMaterialsPost()
} catch (e) {
this.$message.error('批量关联失败')
} finally {
this.isAssociating = false
}
},
async batchDisassociate() {
if (this.selectedItems.length === 0) {
this.$message.warning('请先选择需要取消关联的物资')
return
}
this.isDisassociating = true
try {
let equipment_maintain_config_material_infos = [...(this.currentRule.equipment_maintain_config_material_infos || [])]
// 批量移除选中的物资
this.selectedItems.forEach(item => {
const existingIndex = equipment_maintain_config_material_infos.findIndex(
existing => existing.material_info_id === item.id
)
if (existingIndex !== -1) {
equipment_maintain_config_material_infos.splice(existingIndex, 1)
}
})
await saveMaintainConfig({
id: this.currentRule.id,
equipment_maintain_config_material_infos: equipment_maintain_config_material_infos
})
this.$message.success(`批量取消关联成功,共取消关联 ${this.selectedItems.length} 项物资`)
this.selectedItems = []
this.hasSelectedItems = false
this.getList()
this.searchMaterialsPost()
} catch (e) {
this.$message.error('批量取消关联失败')
} finally {
this.isDisassociating = false
}
},
handleAssociatePageSizeChange(size) {
this.associatePageSize = size
this.associateCurrentPage = 1
this.searchMaterialsPost()
},
resetAssociateSearch() {
this.associateSearch = ''
this.associateFenlei = ''
this.select.storehouses_id = ''
this.select.area = ''
this.associateWarehouseName = ''
this.associateCurrentPage = 1
this.searchMaterialsPost()
},
async getWarehouseTypes() {
try {
const res = await getStorehouseTypeList({
page: 1,
page_size: 999
})
if (res && res.data) {
this.warehouseTypes = res.data
}
} catch (e) {
console.error('获取仓库类型列表失败:', e)
this.$message.error('获取仓库类型列表失败')
}
},
async getWarehouseAreas() {
try {
const res = await getparameteritem('area')
if (res && res.detail) {
this.warehouseAreas = res.detail
}
} catch (e) {
console.error('获取仓库区域列表失败:', e)
this.$message.error('获取仓库区域列表失败')
}
},
async getWarehouseNames() {
try {
const res = await index({
page_size: this.select.page_size,
page: this.select.page,
table_name: this.select.table_name,
filter: [{
key: 'cangkumingcheng',
op: 'like',
value: this.select.keyword ? this.select.keyword : ''
}, {
key: 'quyu_id',
op: 'eq',
value: this.select.area ? this.select.area : ''
}, {
key: 'storehouses_id',
op: 'eq',
value: this.select.storehouses_id ? this.select.storehouses_id : ''
}]
})
if (res && res.data) {
this.warehouseNames = res.data.map(warehouse => ({
value: warehouse.id,
label: warehouse.cangkumingcheng
}))
}
} catch (e) {
console.error('获取仓库名称列表失败:', e)
this.$message.error('获取仓库名称列表失败')
}
},
clearArea(e) {
this.select.area = e || ''
this.filterWarehouses()
},
clearType(e) {
this.select.storehouses_id = e || ''
this.filterWarehouses()
},
async getAllWarehouses() {
try {
const formData = new FormData()
formData.append('page', 1)
formData.append('page_size', 999)
formData.append('table_name', 'materialstorages')
const res = await index(formData)
if (res && res.data) {
this.allWarehouses = res.data
this.filterWarehouses()
}
} catch (e) {
console.error('获取仓库列表失败:', e)
this.$message.error('获取仓库列表失败')
}
},
filterWarehouses() {
let filtered = [...this.allWarehouses]
// 按仓库类型筛选
if (this.select.storehouses_id) {
filtered = filtered.filter(warehouse =>
warehouse.storehouses_id === this.select.storehouses_id
)
}
// 按区域筛选
if (this.select.area) {
filtered = filtered.filter(warehouse =>
warehouse.quyu_id === this.select.area
)
}
// 更新仓库名称列表
this.warehouseNames = filtered.map(warehouse => ({
value: warehouse.id,
label: warehouse.cangkumingcheng
}))
},
async handleCustomSubmit() {
this.$refs.form.validate(async(valid) => {
if (valid) {
const data = {
name: this.form.name,
month_frequency: this.form.cycle,
start_standard: this.form.startSetting,
advance_days: this.form.timingValue,
next_plan_type: this.form.nextPlan,
remark: this.form.notes,
equipment_maintain_config_stocks_items: this.selectedMaterialIds?.map(id => [{ stocks_item_id: id }]) || []
}
try {
await saveMaintainConfig(data)
this.$message.success('保存成功')
this.showModal = false
this.getList()
} catch (e) {
this.$message.error('保存失败')
}
} else {
this.$message.error('请填写所有必填项')
}
})
}
}
}
</script>
<style scoped>
.table-page-container {
display: flex;
flex-direction: column;
height: 100vh;
box-sizing: border-box;
background: #f5f7fa;
}
.table-flex-content {
flex: 1 1 0;
display: flex;
flex-direction: column;
min-height: 0;
}
.el-table th {
background: #f5f7fa !important;
color: #333;
font-weight: bold;
font-size: 15px;
}
.el-table td {
font-size: 14px;
height: 48px;
}
.el-table {
border-radius: 10px;
overflow: hidden;
width: 100%;
height: 100%;
}
.timing-controls {
display: flex;
align-items: center;
gap: 8px;
}
.associate-toolbar {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 15px;
}
.pagination-container {
display: flex;
justify-content: flex-end;
align-items: center;
margin-top: 15px;
}
/* 确保加载提示显示在模态框之上 */
.ivu-message {
z-index: 9999 !important;
}
.ivu-loading-mask {
z-index: 9999 !important;
}
.ivu-message-notice {
z-index: 9999 !important;
}
.ivu-message-notice-content {
z-index: 9999 !important;
}
.ivu-modal-mask {
z-index: 1000 !important;
}
.ivu-modal-wrap {
z-index: 1000 !important;
}
/* .ivu-btn {
margin: 0 4px;
border-radius: 4px;
}
.ivu-btn-error {
background-color: #ed4014;
border-color: #ed4014;
color: #fff;
}
.ivu-btn-error:hover {
background-color: #f16643;
border-color: #f16643;
color: #fff;
}
.ivu-btn-warning {
background-color: #ff9900;
border-color: #ff9900;
color: #fff;
}
.ivu-btn-warning:hover {
background-color: #ffad33;
border-color: #ffad33;
color: #fff;
}
.ivu-btn-primary {
background-color: #2d8cf0;
border-color: #2d8cf0;
color: #fff;
}
.ivu-btn-primary:hover {
background-color: #5cadff;
border-color: #5cadff;
color: #fff;
} */
</style>