bonus-ui/src/views/toolsManage/codeToolsLedger/index.vue

813 lines
27 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-card v-show="showSearch" style="margin-bottom: 20px">
<el-form :model="queryParams" ref="queryForm" size="small" inline @submit.native.prevent>
<el-form-item label="工具专业" prop="fourthParentId">
<el-select
v-model="queryParams.fourthParentId"
placeholder="请选择工具专业"
clearable
filterable
@change="(val) => changeType(val, '2')"
style="width: 240px"
>
<el-option v-for="item in fourthParentList" :key="item.id" :label="item.label" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="施工类型" prop="greatGrandparentId">
<el-select
v-model="queryParams.greatGrandparentId"
placeholder="请选择施工类型"
clearable
filterable
:disabled="!queryParams.fourthParentId"
@change="(val) => changeType(val, '3')"
style="width: 240px"
>
<el-option v-for="item in greatGrandparentList" :key="item.id" :label="item.label" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="工具类型" prop="grandparentTypeId">
<el-select
v-model="queryParams.grandparentTypeId"
placeholder="请选择工具类型"
clearable
filterable
:disabled="!queryParams.greatGrandparentId"
@change="(val) => changeType(val, '4')"
style="width: 240px"
>
<el-option v-for="item in grandparentTypeList" :key="item.id" :label="item.label" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="工具名称" prop="parentTypeId">
<el-select
v-model="queryParams.parentTypeId"
placeholder="请选择工具名称"
clearable
filterable
:disabled="!queryParams.grandparentTypeId"
style="width: 240px"
>
<el-option v-for="item in parentTypeList" :key="item.id" :label="item.label" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="规格型号" prop="typeName">
<el-input
v-model="queryParams.typeName"
placeholder="请输入规格型号"
clearable
@keyup.enter.native="handleQuery"
style="width: 240px"
/>
</el-form-item>
<el-form-item label="工具编码" prop="toolCode">
<el-input
v-model="queryParams.toolCode"
placeholder="请输入工具编码"
clearable
@keyup.enter.native="handleQuery"
style="width: 240px"
/>
</el-form-item>
<!-- 表单按钮 -->
<el-form-item style="float: right">
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
<el-button icon="el-icon-refresh" @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<div style="font-size: 20px; font-weight: 800">编码工具台账列表</div>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
</el-row>
<el-table
v-loading="isLoading"
:data="tableList"
highlight-current-row
border
stripe
height="546"
style="width: 100%"
>
<el-table-column
type="index"
width="55"
label="序号"
align="center"
:index="(index) => (queryParams.pageNum - 1) * queryParams.pageSize + index + 1"
/>
<el-table-column
v-for="(column, index) in tableColumns"
show-overflow-tooltip
:key="index"
:label="column.label"
:prop="column.prop"
align="center"
>
<!-- render插槽 -->
<template v-slot="{ row }">
<component :is="column.render ? { render: (h) => column.render(h, { row }) } : 'span'">
{{ !column.render ? row[column.prop] : '' }}
</component>
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="{ row }">
<el-button size="mini" type="text" icon="el-icon-zoom-in" @click="handleDialog(row, true)">查看</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleDialog(row, false)">编辑</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</el-card>
<!-- 弹框 -->
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="60%" v-loading="isLoading">
<el-form
ref="dialogForm"
:model="dialogForm"
label-width="110px"
size="small"
inline
@submit.native.prevent
:disabled="isView"
>
<el-form-item label="工具专业" prop="fourthParentName">
<el-input v-model="dialogForm.fourthParentName" placeholder="请输入工具专业" readonly style="width: 240px" />
</el-form-item>
<el-form-item label="施工类型" prop="greatGrandparentName">
<el-input
v-model="dialogForm.greatGrandparentName"
placeholder="请输入施工类型"
readonly
style="width: 240px"
/>
</el-form-item>
<el-form-item label="工具类型" prop="grandparentTypeName">
<el-input
v-model="dialogForm.grandparentTypeName"
placeholder="请输入工具类型"
readonly
style="width: 240px"
/>
</el-form-item>
<el-form-item label="工具名称" prop="parentTypeName">
<el-input v-model="dialogForm.parentTypeName" placeholder="请输入工具名称" readonly style="width: 240px" />
</el-form-item>
<el-form-item label="规格型号" prop="typeName">
<el-input v-model="dialogForm.typeName" placeholder="请输入规格型号" readonly style="width: 240px" />
</el-form-item>
<el-form-item label="工具编码" prop="toolCode">
<el-input v-model="dialogForm.toolCode" placeholder="请输入工具编码" readonly style="width: 240px" />
</el-form-item>
<el-form-item label="计量单位" prop="unitName">
<el-select v-model="dialogForm.unitName" placeholder="请选择计量单位" clearable style="width: 240px">
<el-option
v-for="dict in dict.type.dev_unit_type"
:key="dict.label"
:label="dict.label"
:value="dict.label"
/>
</el-select>
</el-form-item>
<!-- 厂家 -->
<el-form-item label="生产厂家">
<el-select v-model="dialogForm.supplierId" placeholder="请选择厂家" clearable style="width: 240px">
<el-option
v-for="item in manufacturerSelect"
:key="item.id"
:label="item.label"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<!-- 出厂日期 -->
<el-form-item label="出厂日期">
<el-date-picker
v-model="dialogForm.productionDate"
type="date"
clearable
placeholder="选择出厂日期"
value-format="yyyy-MM-dd"
style="width: 240px"
/>
</el-form-item>
<el-form-item label="本次检验时间">
<el-date-picker
v-model="dialogForm.lastCheckDate"
type="date"
clearable
placeholder="选择本次检验时间"
value-format="yyyy-MM-dd"
style="width: 240px"
/>
</el-form-item>
<el-form-item label="资产原值(万元)">
<el-input-number
v-model="dialogForm.originCost"
:min="0"
:max="99999999"
:controls="false"
:precision="0"
style="width: 240px"
/>
</el-form-item>
<el-form-item label="原始编码">
<el-input v-model="dialogForm.identifyCode" maxlength="999" style="width: 240px" />
</el-form-item>
<el-form-item label="下次检验时间">
<el-date-picker
v-model="dialogForm.nextCheckDate"
type="date"
clearable
placeholder="选择下次检验时间"
value-format="yyyy-MM-dd"
style="width: 240px"
/>
</el-form-item>
<el-form-item label="工具状态">
<el-input v-model="dialogForm.statusName" readonly style="width: 240px" />
</el-form-item>
<div v-for="(item, index) in dialogForm.propertyVoList" :key="index">
<el-form-item label="特征项">
<el-input v-model="item.propertyName" placeholder="请输入特征项" style="width: 240px" />
</el-form-item>
<el-form-item label="特征值">
<div style="display: flex; align-items: center">
<el-input v-model="item.propertyValue" placeholder="请输入特征值" style="width: 240px" />
<i
v-if="index == dialogForm.propertyVoList.length - 1 && dialogForm.propertyVoList.length < 9 && !isView"
class="el-icon-circle-plus-outline"
@click="handleProperty('add', index)"
style="color: #67c23a; font-size: 24px; margin-left: 8px"
/>
<i
v-if="index != 0 && !isView"
class="el-icon-remove-outline"
@click="handleProperty('remove', index)"
style="color: #f56c6c; font-size: 24px; margin-left: 8px"
/>
</div>
</el-form-item>
</div>
<!-- 附件区域(仅修改这里的图标显示) -->
<el-form-item label="附件" prop="fileList">
<div class="custom-file-upload">
<el-upload
multiple
:action="uploadFileUrl"
:before-upload="handleBeforeUpload"
:file-list="dialogForm.fileList"
:limit="9"
:on-error="handleUploadError"
:on-exceed="handleExceed"
:on-success="handleUploadSuccess"
:show-file-list="false"
:headers="headers"
ref="fileUpload"
:disabled="isView"
>
<!-- 上传按钮 -->
<el-button size="mini" type="primary">选取文件</el-button>
<!-- 上传提示 -->
<div class="el-upload__tip" slot="tip" v-if="showTip">
请上传大小不超过5MB格式为 doc、xls、pdf、jpg、jpeg、png 的文件
</div>
</el-upload>
<!-- 文件列表(图标统一靠左) -->
<transition-group name="el-fade-in-linear" tag="ul">
<li
:key="file.uid"
class="file-item"
v-for="(file, index) in dialogForm.fileList"
>
<el-link
:href="file.url"
:underline="false"
target="_blank"
class="file-name-link"
>
<!-- 图标统一靠左 -->
<div class="file-icon-container">
<img
v-if="isPdfFile(file)"
src="@/assets/images/pdf.png"
class="file-type-icon"
alt="PDF文件"
/>
<img
v-else-if="isWordFile(file)"
src="@/assets/images/word.png"
class="file-type-icon"
alt="Word文件"
/>
<img
v-else-if="isExcelFile(file)"
src="@/assets/images/pdf.png"
class="file-type-icon"
alt="Excel文件"
/>
<img
v-else-if="isImageFile(file)"
:src="file.url"
class="file-type-icon"
alt="图片文件"
/>
<i v-else class="el-icon-file file-default-icon"></i>
</div>
</el-link>
<div class="file-action">
<el-link
v-if="!isView"
:underline="false"
@click.stop="handleDeleteFile(index)"
type="danger"
>
删除
</el-link>
</div>
</li>
</transition-group>
</div>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button v-if="!isView" type="primary" @click="submit">确 定</el-button>
<el-button @click="dialogVisible = false">{{ isView ? ' ' : ' ' }}</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { getListCodeApi, getToolSelectApi, updateByIdApi } from '@/api/toolsManage'
import { getManufacturerSelectApi } from '@/api/EquipmentLedger'
import { getToken } from '@/utils/auth'
export default {
name: 'CodeToolsLedger',
dicts: ['dev_unit_type'],
data() {
return {
isLoading: false,
showSearch: true,
queryParams: {
pageNum: 1,
pageSize: 10,
parentId: '0',
level: '1',
fourthParentId: null, // 工具专业
greatGrandparentId: null, // 施工类型
grandparentTypeId: null, // 工具类型
parentTypeId: null, // 工具名称
typeName: null, // 规格型号
toolCode: null,
},
fourthParentList: [],
greatGrandparentList: [],
grandparentTypeList: [],
parentTypeList: [],
total: 0, // 总条数
// 表头
tableColumns: [
{ label: '工具专业', prop: 'fourthParentName' },
{ label: '施工类型', prop: 'greatGrandparentName' },
{ label: '工具类型', prop: 'grandparentTypeName' },
{ label: '工具名称', prop: 'parentTypeName' },
{ label: '规格型号', prop: 'typeName' },
{ label: '计量单位', prop: 'unitName' },
{ label: '工具编码', prop: 'toolCode' },
// {
// label: "工具状态",
// prop: "status",
// width: 120,
// render: (h, { row }) => {
// const statusOptions = {
// 0: { text: "在库", type: "success" },
// 1: { text: "在用", type: "info" },
// 2: { text: "在修", type: "warning" },
// 3: { text: "已报废", type: "danger" },
// };
// const option = statusOptions[row.status] || {
// text: "未知状态",
// type: "",
// };
// return h(
// "el-tag",
// {
// props: {
// type: option.type,
// size: "mini",
// },
// },
// option.text
// );
// },
// },
{ label: '下次检验时间', prop: 'nextCheckDate' },
{ label: '生产厂家', prop: 'supplierName', width: 200 },
{ label: '出厂日期', prop: 'productionDate' },
{ label: '资产原值', prop: 'originCost' },
{ label: '原始编码', prop: 'identifyCode' },
],
// 表格数据
tableList: [],
isView: false,
dialogTitle: '编码设备管理',
dialogVisible: false,
dialogForm: {
fourthParentName: '',
greatGrandparentName: '',
grandparentTypeName: '',
parentTypeName: '',
typeName: '',
unitName: '',
supplierId: '',
productionDate: '',
lastCheckDate: '',
originCost: null,
identifyCode: '',
nextCheckDate: '',
statusName: '',
propertyVoList: [],
fileList: [], // 初始化文件列表为数组
},
manufacturerSelect: [],
// 上传相关配置从FileUpload组件迁移
uploadFileUrl: process.env.VUE_APP_BASE_API + '/file/upload', // 上传文件服务器地址
headers: {
Authorization: 'Bearer ' + getToken()
},
fileSize: 5, // 文件大小限制(MB)
fileType: ['doc', 'docx', 'xls', 'xlsx', 'pdf', 'jpg', 'jpeg', 'png'], // 允许上传的文件类型
showTip: true, // 是否显示上传提示
number: 0, // 上传文件计数
}
},
created() {
this.getList()
this.getSelectList()
},
methods: {
// 处理图片上传变化
handleImageChange(files) {
this.form.mainFileList = files
this.$refs.formRef.validateField('mainFileList')
},
// 处理合格证上传变化
handleCertificateChange(files) {
this.form.certificateList = files
this.$refs.formRef.validateField('certificateList')
},
// 处理检测证书上传变化
handleInspectionChange(files) {
this.form.inspectionList = files
this.$refs.formRef.validateField('inspectionList')
},
// 处理采购发票上传变化
handlePurchaseInvoicesChange(files) {
this.form.purchaseInvoices = files
this.$refs.formRef.validateField('purchaseInvoices')
},
// 查询
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
// 重置
handleReset() {
this.queryParams.pageNum = 1
this.queryParams.pageSize = 10
this.queryParams.parentId = '0'
this.queryParams.level = '1'
this.$refs.queryForm.resetFields()
this.getList()
},
// 获取列表
async getList() {
console.log('列表-查询', this.queryParams)
this.isLoading = true
try {
const params = { ...this.queryParams }
const res = await getListCodeApi(params)
this.tableList = res.rows || []
this.total = res.total || 0
} catch (error) {
this.tableList = []
this.total = 0
} finally {
this.isLoading = false
}
},
// 下拉
async getSelectList() {
try {
const params = { ...this.queryParams }
const res = await getToolSelectApi(params)
if (this.queryParams.level == '1') {
this.fourthParentList = res.data || []
} else if (this.queryParams.level == '2') {
this.greatGrandparentList = res.data || []
} else if (this.queryParams.level == '3') {
this.grandparentTypeList = res.data || []
} else if (this.queryParams.level == '4') {
this.parentTypeList = res.data || []
}
} catch (error) {
console.log('🚀 ~ error:', error)
}
},
changeType(val, level) {
console.log('🚀 ~ val, type:', val, level)
if (level == '2') {
this.queryParams.parentId = val
this.queryParams.greatGrandparentId = null
this.queryParams.grandparentTypeId = null
this.queryParams.parentTypeId = null
this.greatGrandparentList = []
this.grandparentTypeList = []
this.parentTypeList = []
} else if (level == '3') {
this.queryParams.parentId = this.queryParams.greatGrandparentId
this.queryParams.grandparentTypeId = null
this.queryParams.parentTypeId = null
this.grandparentTypeList = []
this.parentTypeList = []
} else if (level == '4') {
this.queryParams.parentId = this.queryParams.grandparentTypeId
this.queryParams.parentTypeId = null
this.parentTypeList = []
}
this.queryParams.level = level
if (!val) return
this.getSelectList()
},
// 获取厂家
async getManufacturerSelect() {
try {
const res = await getManufacturerSelectApi()
this.manufacturerSelect = res.data
} catch (error) {}
},
handleProperty(type, index) {
if (type == 'add') {
this.dialogForm.propertyVoList.push({
propertyName: '',
propertyValue: '',
})
} else {
this.dialogForm.propertyVoList.splice(index, 1)
}
},
handleDialog(row, type) {
this.dialogTitle = type ? '编码设备详情' : '编码设备编辑'
this.isView = type
this.dialogVisible = true
this.getManufacturerSelect()
this.$nextTick(() => {
this.$refs.dialogForm.resetFields()
// 深拷贝行数据
this.dialogForm = { ...this.dialogForm, ...JSON.parse(JSON.stringify(row)) }
// 处理状态名称
const statusMap = { 0: '在库', 1: '在用', 2: '在修', 3: '已报废' }
this.dialogForm.statusName = statusMap[this.dialogForm.status] || '未知状态'
if (!this.dialogForm.propertyVoList || this.dialogForm.propertyVoList.length === 0) {
this.dialogForm.propertyVoList.push({
propertyName: '',
propertyValue: '',
})
}
// 确保fileList是数组格式
if (!Array.isArray(this.dialogForm.fileList)) {
this.dialogForm.fileList = this.dialogForm.fileList ?
this.dialogForm.fileList.split(',').map(url => ({
name: url.split('/').pop(),
url: url,
uid: new Date().getTime() + Math.random()
})) : []
} else {
// 为数组中的文件添加uid
this.dialogForm.fileList = this.dialogForm.fileList.map(file => ({
...file,
uid: file.uid || new Date().getTime() + Math.random()
}))
}
console.log('🚀 ~ this.dialogForm:', this.dialogForm)
})
},
// 上传前校检格式和大小从FileUpload组件迁移
handleBeforeUpload(file) {
// 校检文件类型
if (this.fileType) {
const fileName = file.name.split('.')
const fileExt = fileName[fileName.length - 1]
const isTypeOk = this.fileType.indexOf(fileExt) >= 0
if (!isTypeOk) {
this.$message.error(`文件格式不正确, 请上传${this.fileType.join('/')}格式文件!`)
return false
}
}
// 校检文件大小
if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize
if (!isLt) {
this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`)
return false
}
}
this.number++
return true
},
// 文件个数超出从FileUpload组件迁移
handleExceed() {
this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`)
},
// 上传失败从FileUpload组件迁移
handleUploadError(err) {
this.$message.error('上传文件失败,请重试')
this.number--
},
// 上传成功回调从FileUpload组件迁移
handleUploadSuccess(res, file) {
if (res.code === 200) {
const newFile = {
name: res.data.url.split('/').pop(),
url: res.data.url,
uid: file.uid
}
this.dialogForm.fileList.push(newFile)
this.$message.success('文件上传成功')
} else {
this.$message.error(res.msg || '上传失败')
}
this.number--
},
// 删除文件
handleDeleteFile(index) {
this.$confirm('确定要删除该文件吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.dialogForm.fileList.splice(index, 1)
this.$message.success('文件删除成功')
}).catch(() => {
// 取消删除
})
},
// 获取文件名称从FileUpload组件迁移
getFileName(name) {
if (name.lastIndexOf('/') > -1) {
return name.slice(name.lastIndexOf('/') + 1)
} else {
return name
}
},
// 判断是否为PDF文件
isPdfFile(file) {
const fileName = this.getFileName(file.name || '')
return fileName.toLowerCase().endsWith('.pdf')
},
// 判断是否为Word文件
isWordFile(file) {
const fileName = this.getFileName(file.name || '')
return fileName.toLowerCase().endsWith('.doc') || fileName.toLowerCase().endsWith('.docx')
},
// 判断是否为Excel文件
isExcelFile(file) {
const fileName = this.getFileName(file.name || '')
return fileName.toLowerCase().endsWith('.xls') || fileName.toLowerCase().endsWith('.xlsx')
},
// 判断是否为图片文件
isImageFile(file) {
const fileName = this.getFileName(file.name || '')
const ext = fileName.toLowerCase().split('.').pop()
return ['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(ext)
},
async submit() {
console.log('🚀 ~ methods.submit:', this.dialogForm)
this.isLoading = true
try {
// 处理文件列表为字符串格式(如果接口需要)
const submitForm = {
...this.dialogForm,
fileList: this.dialogForm.fileList.map(file => file.url).join(',')
}
await updateByIdApi(submitForm)
this.$message({
type: 'success',
message: '操作成功!',
})
this.dialogVisible = false
this.getList()
} catch (error) {
console.log('🚀 ~ error:', error)
this.$message.error('操作失败,请重试')
} finally {
this.isLoading = false
}
},
},
}
</script>
<style lang="scss" scoped>
// 核心样式:确保图标统一靠左
.custom-file-upload {
width: 100%;
}
// 上传提示文本样式
::v-deep .el-upload__tip {
margin-bottom: 10px;
color: #606266;
}
// 文件列表容器
.upload-file-list {
list-style: none;
padding: 0;
margin: 0;
}
// 文件列表项样式
.file-item {
display: flex;
align-items: center;
padding: 8px 12px;
//border: 1px solid #e4e7ed;
//border-radius: 4px;
margin-bottom: 8px;
width: 100%;
box-sizing: border-box;
}
// 图标容器(关键:固定宽度确保图标对齐)
.file-icon-container {
width: 140px; // 固定宽度,确保所有图标左对齐且对齐线一致
display: flex;
justify-content: flex-start; // 强制靠左
margin-right: 10px;
}
// 图标样式
.file-type-icon {
width: 120px;
height: 120px;
object-fit: contain;
}
.file-default-icon {
font-size: 18px;
color: #606266;
}
// 文件名链接样式
.file-name-link {
color: #606266;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: left; // 文件名也靠左
}
// 操作按钮区域
.file-action {
margin-left: 10px;
white-space: nowrap; // 防止删除按钮换行
}
// 确保删除按钮样式正确
::v-deep .file-action .el-link {
color: #f56c6c;
&:hover {
color: #ff4d4f;
}
}
</style>