flex基于TextArea组件的原始换行类似接口属性实例

本文介绍如何使用XML定义文本区域组件的属性,包括边框颜色、背景透明度等,实现类似标签组件但能自动换行的效果。

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
minWidth="1024" minHeight="768" backgroundColor="#FFFFFF">

<!--基于TextArea组件的原始换行接口属性实例-->
<mx:TextArea id="textAreaID" horizontalCenter="0" width="100" height="200"
text="基于TextArea组件的原始换行接口属性实例,即可以类似Label组件效果但是可以自动换行的效果
borderColor属性值和TextArea组件的父组件的backgroundColor属性值相同就更好"
enabled="false" contentBackgroundAlpha="0" borderColor="#FFFFFF" borderThickness="0" disabledColor="#000000"
horizontalScrollPolicy="off" verticalScrollPolicy="off"/>

</s:Application>


<template> <el-main> <!-- 查询条件 --> <el-form :model="searchModel" ref="searchForm" label-width="80px" :inline="true" size="small" > <el-form-item> <el-input v-model="searchModel.name" placeholder="请输入姓名" style="width: 220px" ></el-input> </el-form-item> <el-form-item> <el-input v-model="searchModel.category" placeholder="请输入事项类别" style="width: 220px" ></el-input> </el-form-item> <!-- 审核状态下拉框查询条件 --> <el-form-item label="审核状态"> <el-select v-model="searchModel.auditStatus" placeholder="全部" style="width: 180px" @change="search()" > <el-option label="全部" value="" /> <el-option label="待审核" value="0" /> <el-option label="已初审" value="1" /> <el-option label="初审驳回" value="2" /> <el-option label="已终审" value="3" /> <el-option label="终审驳回" value="4" /> </el-select> </el-form-item> <el-form-item> <div style="display: flex; align-items: center; gap: 10px"> <!-- 查询/重置/新增按钮组 --> <div> <el-button type="primary" icon="el-icon-search" @click="search()" >查询</el-button > <el-button icon="el-icon-refresh-right" @click="resetValue()" >重置</el-button > <el-button type="success" icon="el-icon-plus" @click="openAddWindow()" >积分申请</el-button > </div> <!-- 导出/导入按钮组 --> <div style="display: flex; gap: 10px; margin-left: 10px"> <el-button type="primary" icon="el-icon-download" @click="exportExcel()" >导出Excel</el-button > <el-upload :action="importExcelUrl" :headers="uploadHeaders" :show-file-list="false" :on-success="importExcel" :before-upload="beforeUpload" > <el-button type="success" icon="el-icon-upload2" >导入Excel</el-button > </el-upload> </div> </div> </el-form-item> </el-form> <!-- 数据表格 --> <el-table :data="scoreDetailList" :height="tableHeight" border stripe class="el-table-ellipsis" style="width: 100%; margin-bottom: 10px" show-summary :summary-method="getSummaries" > <!-- 原有列保持不变 --> <el-table-column prop="id" label="序号" width="80" align="center" fixed="left" ></el-table-column> <el-table-column prop="recordDate" label="日期" width="120" header-align="center" align="center" fixed="left" ></el-table-column> <el-table-column prop="name" label="姓名" width="100" header-align="center" align="center" fixed="left" ></el-table-column> <!-- 新增图像列 --> <el-table-column prop="avatar" label="图像" width="120" align="center" header-align="center" > <template slot-scope="scope"> <el-image v-if="scope.row.avatar" style="width: 50px; height: 50px; border-radius: 10%" :src="getAvatarUrl(scope.row.avatar)" :preview-src-list="[getAvatarUrl(scope.row.avatar)]" @error="() => handleImageError(scope.row)" > <div slot="error" class="image-error" /> </el-image> </template> </el-table-column> <!-- 剩余列保持不变 --> <el-table-column prop="category" label="事项类别" width="180" header-align="center" ></el-table-column> <el-table-column prop="score" label="奖惩积分" width="120" header-align="center" align="center" ></el-table-column> <el-table-column prop="originalScore" label="原始分值" width="120" header-align="center" align="center" ></el-table-column> <el-table-column prop="executor" label="执行扣分人" width="100" header-align="center" align="center" ></el-table-column> <el-table-column prop="errorType" label="错误类型" width="180" header-align="center" ></el-table-column> <el-table-column prop="mistakeCount" label="犯错次数" width="80" header-align="center" align="center" ></el-table-column> <el-table-column prop="redEnvelope" label="红包" width="80" header-align="center" align="center" ></el-table-column> <el-table-column prop="details" label="具体事情" width="250" header-align="center" ></el-table-column> <el-table-column prop="creator" label="制单人" width="120" header-align="center" ></el-table-column> <el-table-column prop="createDate" label="制单日期" width="120" header-align="center" align="center" ></el-table-column> <el-table-column prop="remarks" label="备注" width="200" header-align="center" ></el-table-column> <el-table-column prop="auditStatus" label="审核状态" width="100" align="center" header-align="center" > <template slot-scope="scope"> {{ formatAuditStatus(scope.row.auditStatus) }} </template> </el-table-column> <el-table-column prop="firstAuditOpinion" label="初审意见" width="200" header-align="center" ></el-table-column> <el-table-column prop="finalAuditOpinion" label="终审意见" width="200" header-align="center" ></el-table-column> <!-- 操作列 --> <el-table-column label="操作" align="center" width="400" fixed="right"> <template slot-scope="scope"> <!-- 编辑按钮:仅待审核、初审驳回、终审驳回时可见 --> <el-button icon="el-icon-edit" type="primary" size="small" @click="handleEdit(scope.row)" :disabled="scope.row.auditStatus === 3" v-if="[0, 2, 4].includes(scope.row.auditStatus)" >编辑</el-button > <!-- 删除按钮:仅待审核、终审驳回时可见 --> <el-button icon="el-icon-delete" type="danger" size="small" @click="handleDelete(scope.row)" :disabled=" scope.row.auditStatus === 1 || scope.row.auditStatus === 3 " v-if="[0, 4].includes(scope.row.auditStatus)" >删除</el-button > <!-- 初审按钮:仅待审核、初审驳回时可见,已初审状态显示为浅蓝色 --> <el-button icon="el-icon-edit" :type="scope.row.auditStatus === 1 ? 'info' : 'primary'" size="small" @click="firstAudit(scope.row)" v-if=" hasPermission('api:scoreDetail:audit:save') && [0, 1, 2].includes(scope.row.auditStatus) " >初审</el-button > <!-- 终审按钮:仅初审通过、终审驳回时可见,已终审状态显示为浅蓝色 --> <el-button icon="el-icon-edit" :type="scope.row.auditStatus === 3 ? 'info' : 'success'" size="small" @click="finalAudit(scope.row)" v-if=" hasPermission('api:scoreDetail:audit:save') && [1, 3, 4].includes(scope.row.auditStatus) " >终审</el-button > <!-- 行内上传图像按钮 --> <el-upload :action="uploadFileUrl" :show-file-list="false" :headers="uploadHeaders" :before-upload="(file) => beforeAvatarUpload(file, scope.row)" :on-success=" (response, file, fileList) => handleRowAvatarUpload(scope.row, response) " :on-error=" (error, file, fileList) => handleAvatarUploadError(scope.row, error) " style="display: inline-flex; align-items: center" > <el-button type="primary" size="small" icon="el-icon-upload" >上传图像</el-button > </el-upload> </template> </el-table-column> </el-table> <!-- 分页工具栏 --> <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="pageNum" :page-sizes="[10, 20, 30, 40, 50]" :page-size="10" layout="total, sizes, prev, pager, next, jumper" :total="total" ></el-pagination> <!-- 添加和修改分数详情窗口 --> <el-dialog :title="scoreDetailDialog.title" :visible.sync="scoreDetailDialog.visible" width="80%" > <el-form :model="scoreDetail" ref="scoreDetailForm" :rules="rules" label-width="80px" :inline="false" size="small" > <!-- 第1行:增加奖惩类型单选按钮 --> <el-row> <el-col :span="24"> <el-form-item label="奖惩类型"> <el-radio-group v-model="scoreType" @change="handleScoreTypeChange" > <el-radio label="reward">奖分</el-radio> <el-radio label="punish">扣分</el-radio> </el-radio-group> </el-form-item> </el-col> </el-row> <!-- 第2行 --> <el-row> <el-col :span="6"> <el-form-item label="日期" prop="recordDate"> <el-date-picker v-model="scoreDetail.recordDate" type="date" placeholder="选择日期" style="width: 180px" ></el-date-picker> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="姓名" prop="name"> <el-input v-model="scoreDetail.name" style="width: 150px" ></el-input> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="事项类别" prop="category"> <el-input v-model="scoreDetail.category" style="width: 180px" ></el-input> <el-button type="success" size="small" @click="openStandardDialog()" style="margin-left: 5px" > 积分标准 </el-button> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="奖惩积分" prop="score"> <el-input v-model.number="scoreDetail.score" style="width: 180px" ></el-input> </el-form-item> </el-col> </el-row> <!-- 第3行 --> <el-row> <!-- 左侧12列区域 - 跨两行显示积分标准 --> <el-col :span="12"> <el-form-item label="积分标准" prop="standard"> <!-- 使用文本域并设置合适的高度,使其视觉上占据两行空间 --> <el-input v-model="scoreDetail.standard" type="textarea" :rows="5" style="width: 100%;" placeholder="请输入积分标准" ></el-input > </el-form-item> </el-col> <!-- 仅扣分时显示 --> <el-col :span="4" v-if="scoreType === 'punish'"> <el-form-item label="原始分值" prop="originalScore"> <el-input v-model.number="scoreDetail.originalScore" style="width: 180px" ></el-input> </el-form-item> </el-col> <el-col :span="4" v-if="scoreType === 'punish'"> <el-form-item label="犯错次数" prop="mistakeCount"> <el-input v-model.number="scoreDetail.mistakeCount" style="width: 100%" ></el-input> </el-form-item> </el-col> <el-col :span="4" v-if="scoreType === 'punish'"> <el-form-item label="红包" prop="redEnvelope"> <el-input v-model.number="scoreDetail.redEnvelope" style="width: 100%" ></el-input> </el-form-item> </el-col> </el-row> <!-- 第4行 --> <el-row> <el-col :span="12"> </el-col> <!-- 仅扣分时显示 --> <el-col :span="8" v-if="scoreType === 'punish'"> <el-form-item label="执行扣分人" prop="executor"> <el-input v-model="scoreDetail.executor" style="width: 200px" @click.native="openPersonSelectDialog" :readonly="true" ></el-input> </el-form-item> </el-col> <el-col :span="4" v-if="scoreType === 'punish'"> <el-form-item label="错误类型" prop="errorType"> <el-input v-model="scoreDetail.errorType" style="width: 180px" @click.native="openErrorTypeDialog" :readonly="true" ></el-input> </el-form-item> </el-col> </el-row> <!-- 第5行 --> <el-row> <el-col :span="12"> <el-form-item label="具体事情" prop="details"> <el-input v-model="scoreDetail.details" type="textarea" :rows="4" style="width: 100%" ></el-input> </el-form-item> </el-col> <el-col :span="12"> <!-- 图像容器:整体居中 --> <div style=" display: flex; flex-direction: column; align-items: center; height: 100%; " > <!-- 上传按钮:在图像上方居中 --> <el-form-item label="图像" prop="avatar" style="width: 100%; text-align: center; margin-bottom: 15px" > <el-upload :action="uploadFileUrl" :show-file-list="false" :headers="uploadHeaders" :before-upload="beforeAvatarUpload" :on-success="handleFormAvatarUpload" :on-error="handleAvatarUploadError" style="display: inline-block" > <el-button type="primary" size="small" icon="el-icon-upload" >上传图像</el-button > </el-upload> </el-form-item> <!-- 图像预览区:居中显示 --> <div style=" flex: 1; display: flex; align-items: center; justify-content: center; width: 100%; " > <el-image v-if="scoreDetail.avatar" style="width: 120px; height: 120px; border-radius: 10%" :src="getAvatarUrl(scoreDetail.avatar)" :preview-src-list="[getAvatarUrl(scoreDetail.avatar)]" @error="handleFormImageError" > <div slot="error" class="image-error" style=" width: 120px; height: 120px; display: flex; align-items: center; justify-content: center; " /> </el-image> <!-- 无图像时的占位符:居中显示 --> <div v-else style=" width: 120px; height: 120px; border-radius: 10%; background-color: #f5f5f5; display: flex; align-items: center; justify-content: center; color: #ccc; font-size: 14px; " > 暂无图像 </div> </div> </div> </el-col> </el-row> <!-- 第6行 --> <el-row> <el-col :span="6"> <el-form-item label="制单人" prop="creator"> <el-input v-model="scoreDetail.creator" style="width: 180px" ></el-input> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="制单日期" prop="createDate"> <el-date-picker v-model="scoreDetail.createDate" type="date" placeholder="选择日期" style="width: 180px" ></el-date-picker> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="备注" prop="remarks"> <el-input v-model="scoreDetail.remarks" style="width: 100%" ></el-input> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="审核状态" prop="auditStatus"> <!-- 显示汉字状态而非数字 --> <el-input v-model="currentAuditStatusText" style="width: 100px" disabled ></el-input> </el-form-item> </el-col> </el-row> <!-- 审核区域 --> <div v-if="['初审', '终审'].includes(scoreDetailDialog.title)"> <el-row> <el-col :span="8"> <el-form-item label="审核意见" prop="auditOpinion" :rules="getAuditOpinionRules()" > <el-input v-model="scoreDetail.auditOpinion" type="textarea" :rows="2" style="width: 100%" ></el-input> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="审核人员"> <el-input v-model="currentAuditUser" disabled style="width: 100%" ></el-input> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="审核时间"> <el-input v-model="currentAuditTime" disabled style="width: 100%" ></el-input> </el-form-item> </el-col> <el-col :span="8"> <el-form-item> <el-button type="success" @click="handleAuditApprove" >审核通过</el-button > <el-button @click="handleAuditCancel">取消审核</el-button> <el-button type="danger" @click="handleAuditReject" >审核驳回</el-button > </el-form-item> </el-col> </el-row> </div> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click="scoreDetailDialog.visible = false">取消</el-button> <el-button type="primary" @click="onConfirm" v-if=" ['新增分数详情', '编辑分数详情'].includes(scoreDetailDialog.title) " >确定</el-button > </div> </el-dialog> <!-- 积分标准选择窗口 --> <el-dialog :title="standardSelectDialog.title" :visible.sync="standardSelectDialog.visible" width="60%" > <!-- 保持不变 --> <el-form :model="standardSearchModel" ref="standardSearchForm" label-width="80px" :inline="true" size="small" style="margin-bottom: 10px" > <el-form-item label="事项类别"> <el-input v-model="standardSearchModel.category" placeholder="请输入事项类别" style="width: 220px" ></el-input> </el-form-item> <el-form-item label="积分标准"> <el-input v-model="standardSearchModel.standard" placeholder="请输入积分标准" style="width: 220px" ></el-input> </el-form-item> <el-form-item> <el-button type="primary" icon="el-icon-search" @click="searchStandards()" >查询</el-button > </el-form-item> </el-form> <el-table :data="standardList" :height="standardTableHeight" border stripe class="el-table-ellipsis" style="width: 100%; margin-bottom: 10px" > <el-table-column prop="id" label="序号" width="80" align="center" fixed="left" ></el-table-column> <el-table-column prop="category" label="事项类别" width="200" header-align="center" ></el-table-column> <el-table-column prop="standard" label="事项标准" header-align="center" ></el-table-column> <el-table-column prop="score" label="分值" width="120" header-align="center" ></el-table-column> <el-table-column prop="remarks" label="备注" header-align="center" ></el-table-column> <!-- 操作列 --> <el-table-column label="操作" align="center" width="120" fixed="right"> <template slot-scope="scope"> <el-button icon="el-icon-check" type="success" size="small" @click="selectStandard(scope.row)" >选择</el-button > </template> </el-table-column> </el-table> <!-- 积分标准选择窗口分页工具栏 --> <el-pagination v-if="standardTotal > 0" background @size-change="handleStandardSizeChange" @current-change="handleStandardCurrentChange" :current-page="standardPageNum" :page-sizes="[10, 20, 30, 40, 50]" :page-size="standardPageSize" layout="total, sizes, prev, pager, next, jumper" :total="standardTotal" ></el-pagination> <div slot="footer" class="dialog-footer"> <el-button @click="standardSelectDialog.visible = false" >取消</el-button > </div> </el-dialog> <!-- 新增:选择执行扣分人对话框 --> <el-dialog :title="personSelectDialog.title" :visible.sync="personSelectDialog.visible" width="20%" > <el-form :model="personSearchModel" ref="personSearchForm" label-width="80px" :inline="true" size="small" style="margin-bottom: 10px" > <el-form-item label="人员姓名"> <el-input v-model="personSearchModel.name" placeholder="请输入人员姓名" style="width: 220px" ></el-input> </el-form-item> <el-form-item> <el-button type="primary" icon="el-icon-search" @click="searchPersons()" >查询</el-button > </el-form-item> </el-form> <el-table :data="personList" height="400" border stripe class="el-table-ellipsis" style="width: 100%; margin-bottom: 10px" > <el-table-column prop="id" label="序号" width="80" align="center" ></el-table-column> <el-table-column prop="name" label="姓名" width="120" header-align="center" > <template slot-scope="scope"> <el-button type="text" @click="selectPerson(scope.row)"> {{ scope.row.name }} </el-button> </template> </el-table-column> <!-- 操作列 --> </el-table> <div slot="footer" class="dialog-footer"> <el-button @click="personSelectDialog.visible = false">取消</el-button> </div> </el-dialog> <!-- 新增:错误类型选择对话框 --> <el-dialog :title="errorTypeDialog.title" :visible.sync="errorTypeDialog.visible" width="30%" > <el-form :model="errorTypeSearchModel" ref="errorTypeSearchForm" label-width="80px" :inline="true" size="small" style="margin-bottom: 10px" > <el-form-item label="错误类型"> <el-input v-model="errorTypeSearchModel.name" placeholder="请输入错误类型" style="width: 220px" ></el-input> </el-form-item> <el-form-item> <el-button type="primary" icon="el-icon-search" @click="searchErrorTypes()" >查询</el-button > </el-form-item> </el-form> <el-table :data="errorTypeList" height="400" border stripe style="width: 100%; margin-bottom: 10px" > <el-table-column prop="id" label="序号" width="80" align="center" ></el-table-column> <el-table-column prop="name" label="错误类型" header-align="center"> <!-- 修改:点击文本即可选择 --> <template slot-scope="scope"> <el-button type="text" @click="selectErrorType(scope.row)"> {{ scope.row.name }} </el-button> </template> </el-table-column> </el-table> <div slot="footer" class="dialog-footer"> <el-button @click="errorTypeDialog.visible = false">取消</el-button> </div> </el-dialog> </el-main> </template> <script> import { getScoreDetails, addScoreDetail, updateScoreDetail, deleteScoreDetail, getErrorCount, getScoreErrorTypes, } from "@/api/company/hr/scoreDetail"; import { getScoreStandards } from "@/api/company/hr/scoreStandard"; import { getScorePersons } from "@/api/company/hr/scorePerson"; import { getToken, getUsername } from "@/utils/auth"; import axios from "axios"; export default { name: "scoreDetailList", data() { return { // 新增:奖惩类型,默认奖分 scoreType: "reward", // 错误类型对话框相关数据 errorTypeDialog: { title: "选择错误类型", visible: false, }, errorTypeSearchModel: { errorType: "", pageNum: 1, pageSize: 10, }, errorTypeList: [], errorTypePageNum: 1, errorTypePageSize: 10, errorTypeTotal: 0, // 当前审核记录在列表中的索引(用于自动跳转) currentAuditIndex: -1, // 审核状态映射(数字转汉字) auditStatusMap: { 0: "待审核", 1: "已初审", 2: "初审驳回", 3: "已终审", 4: "终审驳回", }, // 查询条件 searchModel: { name: "", category: "", auditStatus: "", // 审核状态:空-全部,0-待审核,1-已初审,2-初审驳回,3-已终审,4-终审驳回 pageNum: 1, pageSize: 10, }, // 表格数据 scoreDetailList: [], tableHeight: 0, pageNum: 1, pageSize: 10, total: 0, // 分数详情表单 scoreDetail: { id: "", recordDate: new Date(), name: this.$store.getters.name, // 当前登录用户 category: "", score: "", originalScore: "", executor: "", errorType: "", mistakeCount: "", redEnvelope: "", details: "", creator: "", createDate: new Date(), remarks: "", auditStatus: 0, auditOpinion: "", firstAuditUser: "", firstAuditTime: "", finalAuditUser: "", finalAuditTime: "", avatar: "", // 图像字段 }, // 积分标准选择对话框数据 standardSelectDialog: { title: "选择积分标准", visible: false, }, standardSearchModel: { category: "", standard: "", pageNum: 1, pageSize: 10, }, standardList: [], standardTableHeight: 0, standardPageNum: 1, standardPageSize: 10, standardTotal: 0, // 表单验证规则 rules: { name: [{ required: true, trigger: "blur", message: "请输入姓名" }], recordDate: [ { required: true, trigger: "blur", message: "请选择日期" }, ], category: [ { required: true, trigger: "blur", message: "请输入事项类别" }, ], score: [{ required: true, trigger: "blur", message: "请输入奖惩积分" }], }, // 对话框 scoreDetailDialog: { title: "", visible: false, }, // 导入导出相关 uploadHeaders: { token: "" }, importExcelUrl: process.env.VUE_APP_BASE_API + "api/scoreDetail/import/easyExcel", // 图像上传相关配置 uploadFileUrl: process.env.VUE_APP_BASE_API + "files/upload", // 图像上传接口 uploadAvatarFileUrl: process.env.VUE_APP_BASE_API + "files/", // 图像显示基础路径 // 审核相关数据 currentAuditType: "", // 'first' 或 'final' currentAuditUser: "", currentAuditTime: "", currentAuditAction: "", // 'approve' 或 'reject' // 审核状态控制 auditStatusControl: { firstAudit: { enabled: true, // 始终启用初审 status: 0, // 0:待审核, 1:已初审, 2:初审驳回 }, finalAudit: { enabled: true, // 始终启用终审 status: 0, // 0:待终审, 1:已终审, 2:终审驳回 }, }, // 新增:选择执行扣分人对话框数据 personSelectDialog: { title: "选择执行扣分人", visible: false, }, personSearchModel: { name: "", pageNum: 1, pageSize: 10, }, personList: [], personTotal: 0, personPageNum: 1, personPageSize: 10, }; }, computed: { currentToken() { return getToken(); }, currentUsername() { return this.$store.getters.name; }, // 计算属性:当前审核状态文本 currentAuditStatusText() { const statusMap = { 0: "待审核", 1: "已初审", 2: "初审驳回", 3: "已终审", 4: "终审驳回", }; // 处理新增时的默认状态 return this.scoreDetail.id ? statusMap[this.scoreDetail.auditStatus] || "未知状态" : "待审核"; }, }, watch: { currentToken(newVal) { this.uploadHeaders.token = newVal; }, // 监听对话框标题变化,更新审核相关数据 "scoreDetailDialog.title"(newVal) { if (newVal === "初审") { this.currentAuditType = "first"; this.currentAuditUser = this.scoreDetail.firstAuditUser || this.currentUsername; this.currentAuditTime = this.scoreDetail.firstAuditTime; this.scoreDetail.auditOpinion = this.scoreDetail.firstAuditOpinion || ""; // 更新审核状态控制 this.auditStatusControl.firstAudit.status = this.scoreDetail.auditStatus; } else if (newVal === "终审") { this.currentAuditType = "final"; this.currentAuditUser = this.scoreDetail.finalAuditUser || this.currentUsername; this.currentAuditTime = this.scoreDetail.finalAuditTime; this.scoreDetail.auditOpinion = this.scoreDetail.finalAuditOpinion || ""; // 更新审核状态控制 this.auditStatusControl.finalAudit.status = this.scoreDetail.auditStatus; } }, }, methods: { // 新增:表格合计方法 getSummaries(param) { const { columns, data } = param; const sums = []; columns.forEach((column, index) => { if (index === 0) { // 第一列显示"合计" sums[index] = '合计'; return; } // 只对奖惩积分列进行合计 if (column.property === 'score') { const values = data.map(item => Number(item.score)); if (!values.every(value => isNaN(value))) { const sum = values.reduce((prev, curr) => { const value = Number(curr); return isNaN(value) ? prev : prev + value; }, 0); // 格式化合计值(保留两位小数,千分位分隔) sums[index] = sum.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); } else { sums[index] = ''; } } else { // 其他列不显示合计 sums[index] = ''; } }); return sums; }, // 新增:处理奖惩类型变更 handleScoreTypeChange(val) { // 当切换为奖分时清空扣分相关字段 if (val === "reward") { this.scoreDetail.originalScore = ""; this.scoreDetail.mistakeCount = ""; this.scoreDetail.redEnvelope = ""; this.scoreDetail.executor = ""; this.scoreDetail.errorType = ""; } }, // 打开错误类型对话框 openErrorTypeDialog() { this.errorTypeSearchModel = { errorType: "", pageNum: 1, pageSize: 10, }; this.searchErrorTypes(); this.errorTypeDialog.visible = true; }, // 查询错误类型列表 async searchErrorTypes() { try { const res = await getScoreErrorTypes({ ...this.errorTypeSearchModel, pageNum: this.errorTypePageNum, pageSize: this.errorTypePageSize, }); if (res.code === 200) { this.errorTypeList = res.data.rows || []; this.errorTypeTotal = res.data.total || 0; } else { this.$message.error(res.message || "查询错误类型失败"); } } catch (error) { this.$message.error("查询错误类型请求异常"); } }, // 选择错误类型 - 简化逻辑 async selectErrorType(row) { // 直接使用row.name作为错误类型值 this.scoreDetail.errorType = row.name; this.errorTypeDialog.visible = false; // 强制触发视图更新 this.$forceUpdate(); // 自动更新犯错次数 await this.updateMistakeCount(); }, // 更新犯错次数 async updateMistakeCount() { if ( this.scoreDetail.recordDate && this.scoreDetail.name && this.scoreDetail.errorType ) { try { // 从日期中提取年份 const year = new Date(this.scoreDetail.recordDate).getFullYear(); // 调用API获取错误次数 const res = await getErrorCount({ name: this.scoreDetail.name, year: year, errorType: this.scoreDetail.errorType, }); if (res.code === 200) { // 使用$set确保响应式更新 const newCount = (res.data || 0) + 1; this.$set(this.scoreDetail, "mistakeCount", newCount); // 再次强制更新,确保视图同步 this.$nextTick(() => { this.$forceUpdate(); }); } else { this.$message.error(res.message || "获取错误次数失败"); } } catch (error) { console.error("获取错误次数请求异常:", error); this.$message.error( `获取错误次数失败: ${error.message || "网络错误"}` ); } } else { this.$message.warning("请先填写日期、姓名和错误类型"); } }, // 日期格式化辅助函数 formatDate(date) { const d = new Date(date); let month = "" + (d.getMonth() + 1); let day = "" + d.getDate(); const year = d.getFullYear(); if (month.length < 2) month = "0" + month; if (day.length < 2) day = "0" + day; return [year, month, day].join("-"); }, // 新增:打开选择执行扣分人对话框 openPersonSelectDialog() { this.personSearchModel = { name: "", pageNum: 1, pageSize: 10, }; this.searchPersons(); this.personSelectDialog.visible = true; }, // 新增:查询执行扣分人列表 async searchPersons() { try { const res = await getScorePersons({ ...this.personSearchModel, pageNum: this.personPageNum, pageSize: this.personPageSize, }); if (res.code === 200) { this.personList = res.data.rows || []; this.personTotal = res.data.total || 0; } else { this.$message.error(res.message || "查询人员列表失败"); } } catch (error) { this.$message.error("查询人员列表请求异常"); } }, // 新增:选择执行扣分人 selectPerson(row) { this.scoreDetail.executor = row.name; this.personSelectDialog.visible = false; }, // 获取审核意见的验证规则 getAuditOpinionRules() { return this.currentAuditAction === "reject" ? { required: true, message: "请输入驳回意见", trigger: "blur" } : []; }, // 打开初审窗口 firstAudit(row) { this.scoreDetailDialog.title = "初审"; this.scoreDetailDialog.visible = true; this.scoreDetail = { ...row }; // 记录当前索引 this.currentAuditIndex = this.scoreDetailList.findIndex( (item) => item.id === row.id ); // 初始化当前审核人 this.currentAuditUser = this.currentUsername; this.currentAuditType = "first"; // 更新审核状态控制 this.auditStatusControl.firstAudit.status = this.scoreDetail.auditStatus; }, // 打开终审窗口 finalAudit(row) { // 允许对任何状态记录进行终审操作 this.scoreDetailDialog.title = "终审"; this.scoreDetailDialog.visible = true; this.scoreDetail = { ...row }; this.currentAuditIndex = this.scoreDetailList.findIndex( (item) => item.id === row.id ); this.currentAuditUser = this.currentUsername; this.currentAuditType = "final"; // 更新审核状态控制 this.auditStatusControl.finalAudit.status = this.scoreDetail.auditStatus; }, // 审核通过 async handleAuditApprove() { this.currentAuditAction = "approve"; // 设置当前操作为通过 this.$refs.scoreDetailForm.validate(async (valid) => { if (!valid) return; const now = new Date(); const auditTime = now.toISOString().slice(0, 19).replace("T", " "); if (this.currentAuditType === "first") { this.scoreDetail.auditStatus = 1; this.scoreDetail.firstAuditUser = this.currentUsername; this.scoreDetail.firstAuditTime = auditTime; this.scoreDetail.firstAuditOpinion = this.scoreDetail.auditOpinion; this.auditStatusControl.firstAudit.status = 1; // 更新状态为已初审 } else { this.scoreDetail.auditStatus = 3; this.scoreDetail.finalAuditUser = this.currentUsername; this.scoreDetail.finalAuditTime = auditTime; this.scoreDetail.finalAuditOpinion = this.scoreDetail.auditOpinion; this.auditStatusControl.finalAudit.status = 1; // 更新状态为已终审 } await this.saveAuditInfo(); this.$message.success(`${this.scoreDetailDialog.title}通过`); this.jumpToNextAuditRecord(this.currentAuditType === "first" ? 0 : 1); }); }, // 取消审核 async handleAuditCancel() { if (this.currentAuditType === "first") { this.scoreDetail.auditStatus = 0; this.scoreDetail.firstAuditOpinion = ""; this.scoreDetail.firstAuditTime = null; this.auditStatusControl.firstAudit.status = 0; // 更新状态为待审核 } else { // 终审取消,回到初审通过状态 this.scoreDetail.auditStatus = 1; this.scoreDetail.finalAuditOpinion = ""; this.scoreDetail.finalAuditTime = null; this.auditStatusControl.finalAudit.status = 0; // 更新状态为待终审 } await this.saveAuditInfo(); this.$message.success(`已取消${this.scoreDetailDialog.title}`); this.scoreDetailDialog.visible = false; }, // 审核驳回 async handleAuditReject() { this.currentAuditAction = "reject"; // 设置当前操作为驳回 this.$refs.scoreDetailForm.validate(async (valid) => { if (!valid) return; const now = new Date(); const auditTime = now.toISOString().slice(0, 19).replace("T", " "); if (this.currentAuditType === "first") { this.scoreDetail.auditStatus = 2; this.scoreDetail.firstAuditUser = this.currentUsername; this.scoreDetail.firstAuditTime = auditTime; this.scoreDetail.firstAuditOpinion = this.scoreDetail.auditOpinion; this.auditStatusControl.firstAudit.status = 2; // 更新状态为初审驳回 } else { this.scoreDetail.auditStatus = 4; this.scoreDetail.finalAuditUser = this.currentUsername; this.scoreDetail.finalAuditTime = auditTime; this.scoreDetail.finalAuditOpinion = this.scoreDetail.auditOpinion; this.auditStatusControl.finalAudit.status = 2; // 更新状态为终审驳回 } await this.saveAuditInfo(); this.$message.success(`${this.scoreDetailDialog.title}驳回`); this.jumpToNextAuditRecord(this.currentAuditType === "first" ? 0 : 1); }); }, // 保存审核信息到后端 async saveAuditInfo() { try { const res = await updateScoreDetail(this.scoreDetail); if (res.code === 200) { this.search(); // 刷新列表 } else { this.$message.error(res.message); } } catch (error) { this.$message.error("审核操作失败"); } }, // 自动跳转到下一个符合条件的记录 jumpToNextAuditRecord(targetStatus) { const nextIndex = this.scoreDetailList.findIndex( (item, index) => index > this.currentAuditIndex && item.auditStatus === targetStatus ); if (nextIndex > -1) { const nextRecord = this.scoreDetailList[nextIndex]; this.scoreDetailDialog.visible = false; // 根据目标状态决定打开初审还是终审 targetStatus === 0 ? this.firstAudit(nextRecord) : this.finalAudit(nextRecord); } else { this.scoreDetailDialog.visible = false; this.$message.info("已无符合条件的下一条记录"); } }, // 表格列格式化审核状态 formatAuditStatus(status) { return this.auditStatusMap[status] || "未知状态"; }, // 初始化组件时获取用户名 initUserInfo() { this.scoreDetail.name = this.currentUsername; this.scoreDetail.creator = this.currentUsername; }, // 分数详情列表查询 async search() { try { const res = await getScoreDetails(this.searchModel); if (res.code === 200) { this.scoreDetailList = res.data.rows || []; this.total = res.data.total || 0; } else { this.$message.error(res.message || "查询失败"); } } catch (error) { this.$message.error("请求异常"); } }, // 重置查询条件 resetValue() { this.searchModel = { name: "", category: "", auditStatus: "", // 重置为全部 pageNum: 1, pageSize: 10, }; this.search(); }, // 分页事件处理 handleSizeChange(size) { this.searchModel.pageSize = size; this.search(); }, handleCurrentChange(page) { this.searchModel.pageNum = page; this.search(); }, // 打开新增窗口(优化:确保表单完全重置) openAddWindow() { // 先销毁表单验证状态,再重置字段 if (this.$refs.scoreDetailForm) { this.$refs.scoreDetailForm.clearValidate(); // 清除所有验证状态 this.$refs.scoreDetailForm.resetFields(); // 重置字段值 } // 初始化新增表单数据 this.scoreType = "reward"; // 默认奖分 this.scoreDetail = { recordDate: new Date(), createDate: new Date(), name: this.currentUsername, creator: this.currentUsername, auditStatus: 0, category: "", score: "", avatar: "", }; this.scoreDetailDialog.title = "新增分数详情"; this.scoreDetailDialog.visible = true; }, // 编辑分数详情 handleEdit(row) { this.scoreDetail = { ...row }; // 设置奖惩类型 this.scoreType = row.originalScore || row.mistakeCount || row.redEnvelope ? "punish" : "reward"; // 日期格式转换 if (this.scoreDetail.recordDate) { this.scoreDetail.recordDate = new Date(this.scoreDetail.recordDate); } if (this.scoreDetail.createDate) { this.scoreDetail.createDate = new Date(this.scoreDetail.createDate); } this.scoreDetailDialog.title = "编辑分数详情"; this.scoreDetailDialog.visible = true; }, // 打开积分标准选择对话框 openStandardDialog() { this.standardSearchModel = { category: "", standard: "", pageNum: 1, pageSize: 10, }; this.searchStandards(); this.standardSelectDialog.visible = true; }, // 查询积分标准 async searchStandards() { try { const res = await getScoreStandards({ ...this.standardSearchModel, pageNum: this.standardPageNum, pageSize: this.standardPageSize, }); if (res.code === 200) { this.standardList = res.data.rows || []; this.standardTotal = res.data.total || 0; } else { this.$message.error(res.message || "查询积分标准失败"); } } catch (error) { this.$message.error("查询积分标准请求异常"); } }, // 积分标准分页大小变更 handleStandardSizeChange(size) { this.standardPageSize = size; this.standardSearchModel.pageSize = size; this.searchStandards(); }, // 积分标准分页页码变更 handleStandardCurrentChange(page) { this.standardPageNum = page; this.standardSearchModel.pageNum = page; this.searchStandards(); }, // 选择积分标准 selectStandard(row) { // 给事项类别、积分标准、奖惩积分赋值 this.scoreDetail.category = row.category; this.scoreDetail.standard = row.standard; this.scoreDetail.score = row.score; // 手动触发表单验证 if (this.$refs.scoreDetailForm) { this.$refs.scoreDetailForm.validateField(["category", "score"]); } // 关闭选择窗口 this.standardSelectDialog.visible = false; }, // 保存分数详情 async onConfirm() { this.$refs.scoreDetailForm.validate(async (valid) => { if (!valid) return; try { const res = this.scoreDetail.id ? await updateScoreDetail(this.scoreDetail) : await addScoreDetail(this.scoreDetail); if (res.code === 200) { this.$message.success(res.message); this.scoreDetailDialog.visible = false; this.search(); } else { this.$message.error(res.message); } } catch (error) { this.$message.error("操作失败"); } }); }, // 删除分数详情 async handleDelete(row) { try { await this.$confirm("确定删除该分数详情?", "提示", { type: "warning", }); const res = await deleteScoreDetail(row.id); if (res.code === 200) { this.$message.success(res.message); this.search(); } else { this.$message.error(res.message); } } catch (error) { // 取消删除 } }, // 导出Excel async exportExcel() { try { const instance = axios.create({ baseURL: process.env.VUE_APP_BASE_API, headers: { token: getToken() }, responseType: "blob", }); const response = await instance.get( "/api/scoreDetail/export/easyExcel", { params: { name: this.searchModel.name, }, } ); const fileName = response.headers["content-disposition"] ? decodeURIComponent( response.headers["content-disposition"].split("filename=")[1] ).replace(/"/g, "") : "scoreDetails_export.xls"; const link = document.createElement("a"); link.href = URL.createObjectURL(new Blob([response.data])); link.download = fileName; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(link.href); } catch (error) { this.handleExportError(error); } }, // 导入Excel importExcel(response) { if (response.code === 200) { this.search(); this.$message.success("导入成功"); } else { this.$message.error(response.message || "导入失败"); } }, // 导入文件校验 beforeUpload(file) { const allowedTypes = [ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.ms-excel", ]; if (!allowedTypes.includes(file.type)) { this.$message.error("仅支持 .xls 或 .xlsx 格式文件"); return false; } return true; }, // 导出错误处理 handleExportError(error) { if (error.response?.status === 401) { this.$message.error("登录已过期,请重新登录"); this.$store.dispatch("user/logout"); this.$router.push("/login"); } else if (error.response?.data instanceof Blob) { const reader = new FileReader(); reader.onload = () => { try { const errorData = JSON.parse(reader.result); this.$message.error(errorData.message || "导出失败"); } catch { this.$message.error("导出文件解析失败"); } }; reader.readAsText(error.response.data); } else { this.$message.error(error.message || "导出失败"); } }, // 图像上传相关方法 // 获取图像完整URL getAvatarUrl(avatar) { if (!avatar) return ""; const timestamp = Date.now(); return `${this.uploadAvatarFileUrl}${encodeURIComponent(avatar)}?token=${ this.currentToken }&t=${timestamp}`; }, // 处理图片加载错误 handleImageError(row) { console.error("图片加载失败:", row.avatar); // 简单的错误处理 this.$set(row, "avatar", ""); }, // 表单图片加载错误处理 handleFormImageError() { console.error("表单图片加载失败"); this.scoreDetail.avatar = ""; }, // 图像上传前验证 beforeAvatarUpload(file, row) { const isImage = file.type.startsWith("image/"); const isLt5M = file.size / 1024 / 1024 < 5; if (!isImage) { this.$message.error("只能上传图片文件!"); } if (!isLt5M) { this.$message.error("图像图片大小不能超过5MB!"); } return isImage && isLt5M; }, // 处理表单中的图像上传成功 handleFormAvatarUpload(response) { if (response.code === 200) { this.scoreDetail.avatar = response.data; this.$message.success("图像上传成功"); } else { this.$message.error(response.message || "图像上传失败"); } }, // 处理行内图像上传成功 handleRowAvatarUpload(row, response) { if (response.code === 200) { // 更新当前行的图像信息 this.$set(row, "avatar", response.data); this.$message.success("图像上传成功"); // 同步更新到后端 const updateData = { id: row.id, avatar: response.data, }; updateScoreDetail(updateData) .then((res) => { if (res.code !== 200) { this.$message.warning("图像信息同步失败"); } }) .catch(() => { this.$message.warning("图像信息同步失败"); }); } else { this.$message.error(response.message || "图像上传失败"); } }, // 处理图像上传失败 handleAvatarUploadError(row, error) { console.error("图像上传失败:", error); this.$message.error("图像上传失败,请重试"); }, }, created() { this.search(); }, mounted() { this.uploadHeaders.token = getToken(); this.initUserInfo(); this.$nextTick(() => { this.tableHeight = window.innerHeight - 220; this.standardTableHeight = window.innerHeight - 300; }); }, }; </script> <style> /* 全局单元格样式 */ .el-table-ellipsis .cell { white-space: nowrap !important; /* 强制不换行 */ overflow: hidden !important; text-overflow: ellipsis !important; } /* 禁用操作列的省略号效果 */ .el-table-ellipsis .no-ellipsis .cell { white-space: normal !important; /* 恢复默认换行 */ overflow: visible !important; text-overflow: clip !important; } /* 可选:表头对齐方式 */ .el-table-ellipsis th > .cell { display: block; /* 解决表头与内容列宽度轻微错位问题 */ } .dialog-footer { display: flex; justify-content: flex-end; gap: 10px; } /* 图片错误占位样式 */ .image-error { width: 100%; height: 100%; background-color: #f5f5f5; display: flex; align-items: center; justify-content: center; color: #ccc; } .image-error::after { content: "图片错误"; font-size: 12px; } /* 新增:合计行样式 */ .el-table .el-table__footer .cell { font-weight: bold; color: #409EFF; } </style> 报错: vue.runtime.esm.js:620 [Vue warn]: Property or method "showSettings1" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties. found in ---> <Layout> at src/layout/index.vue <App> at src/App.vue <Root> 6 vue.runtime.esm.js:620 [Vue warn]: Property or method "formatNumber" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties. found in ---> <ScoreTotal> at src/views/company/hr/scoreTotal.vue <AppMain> at src/layout/components/AppMain.vue <Layout> at src/layout/index.vue <App> at src/App.vue <Root> 合计数没有展示出来,优化代码
08-06
<template> <div class="table-box"> <ProTable ref="proTable" :columns="columns" :request-api="getTableList" :data-callback="dataCallback" > </ProTable> </div> </template> <script setup lang="tsx" name="operationLog"> import { ref, reactive, } from "vue"; import ProTable from "@/components/ProTable/index.vue"; import { setValueClildList } from '@/api/modules/public'; import { assetListOpList } from "@/api/modules/assetAllocation"; import { ProTableInstance, ColumnProps } from "@/components/ProTable/interface"; import { Metering } from "@/api/interface"; import { OperationType } from "@/utils/dict"; const emit = defineEmits(['previous-info']); // ProTable 实例 const proTable = ref<ProTableInstance>(); // 保存 id 的状态 const currentId = ref<string | undefined>(undefined); // ProTable 请求数据的方法 const getTableList = (params: any) => { // 添加 id 参数 if (currentId.value) { params.assetId = currentId.value; } if (params.createTime) { params.startTime = params.createTime[0] + ' 00:00:00'; params.endTime = params.createTime[1] + ' 23:59:59'; delete params.createTime; } return assetListOpList(params); } const dataCallback = (data: any) => { return { list: data.dataList, total: data.totalCount, pageNum: data.pageNum, pageSize: data.pageSize }; } interface AssetDetailData { id?: string; } interface DrawerProps { row?: Partial<AssetDetailData>; } const drawerProps = ref<DrawerProps>({ row: {}, }) const refreshTable = () => { proTable.value!.pageable.pageNum = 1; proTable.value?.refreshData(); }; // 父组件传过来的数据 const setDrawerProps = async (params: DrawerProps) => { drawerProps.value = { ...params } // 更新 currentId currentId.value = params.row?.id; // 手动触发 ProTable 的刷新 await refreshTable(); } // 表格配置项 const columns = reactive<ColumnProps<Metering.pageList>[]>([ { prop: "createUserName", label: "操作人" }, { prop: "userName", label: "操作人",isShow:false, search: { el: "input" }}, { prop: "optType", label: "操作类型", isShow:false, enum: async () => { // 获取资产来源 const data = await setValueClildList({ dictCode: 'LOG_OPERATION_TYPE' }); if(data.code != 0) return false const list = data?.data.filter(item => item.enableStatus == 1); return { data: list } }, fieldNames: { label: "itemLabel", value: "itemValue" }, search: { el: "select", props: { filterable: true }}, }, { prop: "optTypeName", label: "操作类型" }, { prop: "content", label: "操作内容",search: { el: "input" } }, { prop: "orderNo", label: "关联单据", search: { el: "input" }, copy: false, render: (scope) => { return ( <span style="color: #49c625" onClick={() => handleAssetCodeClick(scope.row)}> {scope.row.orderNo} </span> ); } }, { prop: "createTime", label: "操作时间", search: { el: "date-picker", span: 2, props: { type: "daterange", valueFormat: "YYYY-MM-DD" }, }, }, ]) const handleAssetCodeClick = async (row: any) => { emit('previous-info',row); // 触发父组件事件 } defineExpose({ setDrawerProps }); </script> <template> <el-drawer v-model="drawerVisible" :append-to-body="true" :destroy-on-close="true" size="70%" :show-close="false" :with-header="false" class="no-header-drawer" > <div class="asset_details_header"> <!-- 头部内容 --> <div class="header_title"> <div class="header_left"> <div class="header_zcInfo"> <span class="header_zcInfo_name">{{ infos.baseInfo.assetName }}</span> <!-- 资产标记 --> <span class="header_zcInfo_status" v-if="infos.markTags?.length"> <span v-for="(item, index) in markStatusList" :key="index"> <span class="span-zc" :style="`color:${item.color}`">{{ item.name }}</span> </span> </span> </div> <div class="header_userInfo"> <span>新增人:{{ infos.baseInfo.createUserName }}</span> <span>新增时间:{{ infos.baseInfo.createTime }}</span> <span>修改人:{{ infos.baseInfo.updateUserName }}</span> <span>修改时间:{{ infos.baseInfo.updateTime }}</span> </div> </div> <div class="header_right"> <div class="trapezoid-isosceles" :style="statusStyle" > <span>{{ statusText }}</span> </div> </div> </div> <div class="header_btns"> <el-button type="primary" v-if="hasBtnPermission('asset:inventory:update')" @click="deleteData" > <el-icon class="el-icon--left"><Delete /></el-icon>删除 </el-button> <el-button type="primary" @click="openTagPrint" v-if="hasBtnPermission('asset:inventory:printMark')" > <el-icon class="el-icon--left"><Printer /></el-icon>打印资产标签 </el-button> </div> </div> <div class="asset_details_content"> <el-tabs v-model="activeName" class="demo-tabs"> <div class="content-height"> <el-tab-pane label="资产信息" name="first"> <basicDetails ref="basicDetailsRef" @previous-info="previousInfo"/> </el-tab-pane> <el-tab-pane label="操作日志" name="second"> <div class="sty-second" :style="{ height: windowHeight+'px' }"> <operationLog ref="operationLogRef" /> </div> </el-tab-pane> </div> </el-tabs> </div> </el-drawer> </template> <script setup lang="ts" name="assetInfo"> import { ref, computed,nextTick,inject } from "vue"; import { ElMessage } from 'element-plus'; import operationLog from "./operationLog.vue"; import basicDetails from "./basicDetails.vue"; import { markStatusType } from "@/utils/dict"; import { printAssetMark, assetListInfo, deleteAssetList } from "@/api/modules/assetAllocation"; import { useHandleData } from "@/hooks/useHandleData"; import { AssetClassification } from "@/api/interface"; const windowHeight: number = window.innerHeight - 210; interface DrawerProps { title: string; row?: Partial<AssetClassification.pageList>; isView: boolean; api?: (params: any) => Promise<any>; refreshTable?: () => void; configuration?: any } const hasBtnPermission: any = inject('hasBtnPermission'); const previousInfo = (row:any) => { console.log('rrr',row) } const activeName = ref('first'); const drawerVisible = ref(false); const drawerProps = ref<DrawerProps>({ isView: false, title: "", row: {} }); const infos = ref({ id: "", baseInfo: {} as any, markTags: [] }); const markStatusList = ref<Array<{name: string; color: string}>>([]); const basicDetailsRef = ref(); const operationLogRef = ref(); // 计算属性 const statusStyle = computed(() => { const status = infos.value.baseInfo?.assetStatus; const colorMap = { '1': '#49c625', '2': '#ff7f00', '3': '#1890ff' }; return { 'border-color': colorMap[status] || '#1890ff' }; }); const statusText = computed(() => { const status = infos.value.baseInfo?.assetStatus; const textMap = { '1': '空闲', '2': '在用', '3': '借用' }; return textMap[status] || ''; }); const acceptParams = async (params: DrawerProps) => { infos.value = { baseInfo: {}, markTags: [], id: "" }; markStatusList.value = []; drawerProps.value = params; activeName.value = 'first' try { type reqType = { code?: number, data?: any, msg?: string } const { code, data, msg } = await assetListInfo({ id: params.row!.id as string }) as reqType; if (code === 0) { infos.value = data as any; drawerVisible.value = true; // 处理标记状态 if (data.markTags?.length) { markStatusList.value = data.markTags .map(tag => { const status = markStatusType.find(item => item.label === tag); return status ? { name: tag, color: status.color } : null; }) .filter(Boolean); } nextTick(() => { basicDetailsRef.value?.setDrawerProps({ row: data, configuration: params.configuration }); operationLogRef.value?.setDrawerProps({ row:data }) }); } else { ElMessage.error(msg); } } catch (error) { ElMessage.error('获取资产信息失败'); console.error(error); } }; // 删除资产 const deleteData = async () => { await useHandleData( deleteAssetList, { idList: [infos.value.id] }, `确认删除` ); drawerVisible.value = false; drawerProps.value.refreshTable?.(); }; // 打印标签 const openTagPrint = async () => { try { const { code, msg } = await printAssetMark({ idList: [drawerProps.value!.row!.id], type: 'baseInfo' }); if (code === 0) { ElMessage.success(msg); drawerProps.value.refreshTable?.(); } else { ElMessage.error(msg); } } catch (error) { ElMessage.error('打印失败'); console.error(error); } }; defineExpose({ acceptParams }); </script> <style lang="scss" scoped> .no-header-drawer { .el-drawer__body { padding: 0; .asset_details_header { .header_title { border-bottom: 1px solid #ebeef5; margin: 0 0 12px 0; display: flex; padding-bottom: 10px; .header_left { flex: 1; .header_zcInfo { margin-bottom: 10px; .header_zcInfo_name { color: #303133; font-size: 20px; font-weight: 600; padding-right: 15px; } .span-zc { border-radius: 10px; border: 1px solid; padding: 2px 5px; font-size: 12px; margin-right: 4px; } } .header_userInfo { color: #606266; font-size: 14px; span { margin-right: 25px; } } } .header_right { .trapezoid-isosceles { content: ""; display: block; height: 0; border-width: 0px 19px 35px; border-style: none solid solid; position: absolute; transform: rotate(44deg); right: -32px; top: 16px; width: 94px; span { line-height: 35px; text-align: center; display: block; color: #ffffff; font-size: 18px; } } } } } .asset_details_content { height: calc(100% - 115px); overflow-y: auto; } } } .no-header-drawer { .el-drawer__body { padding: 10px 20px; overflow: hidden; } header.el-drawer__header { border: none !important; padding: 0 !important; } } </style> <template> <div class="table-box"> <ProTable ref="proTable" :columns="columns" :request-api="getTableList" :data-callback="dataCallback"> <!-- 表格 header 按钮 --> <template #tableHeader="scope"> <el-button type="primary" v-if="hasBtnPermission('asset:inventory:save')" @click="addNewData('新增资产', 'add', {})">新增资产</el-button> <el-button type="primary" v-if="hasBtnPermission('asset:inventory:update')" @click="batcEdit(scope.selectedListIds)">批量编辑</el-button> <el-button type="primary" v-if="hasBtnPermission('asset:inventory:delete')" @click="batchDelete(scope.selectedListIds)">批量删除</el-button> <el-dropdown style="margin-left: 10px" v-if="hasBtnPermission('asset:inventory:downloadData')" @command="batchExport"> <el-button type="primary"> 批量导出<i class="el-icon-arrow-down el-icon--right"></i> </el-button> <template #dropdown> <el-dropdown-menu> <el-dropdown-item command="1">导出所选数据</el-dropdown-item> <el-dropdown-item command="2">导出全部</el-dropdown-item> </el-dropdown-menu> </template> </el-dropdown> <el-button type="primary" @click="openTagPrint(scope.selectedListIds)" v-if="hasBtnPermission('asset:inventory:printMark')" style="margin-left: 10px">打印资产标签</el-button> </template> <!-- 图片 --> <template #imageUrl="{ row }"> <div class="more_imgs" v-if="row.imageUrlList && row.imageUrlList.length > 0"> <viewer :images="row.imageUrlList"> <span class="viewImage" v-for="(itemImg, index) in row.imageUrlList" :key="index"> <img v-if="itemImg" :src="itemImg" style="width: 100%; height: 100%" /> </span> </viewer> </div> </template> <template #operation="scope" v-if="hasBtnPermission('asset:inventory:update')"> <el-button type="primary" link @click="editData('编辑资产', 'edit', scope.row)">编辑</el-button> </template> </ProTable> <!-- 选择新增资产类型 --> <div class="new-Dialog-type" v-if="dialogFormVisible"> <el-dialog v-model="dialogFormVisible" title="选择资产类型" width="450" draggable> <el-form ref="ruleFormRef" :model="form" :rules="rules" label-width="93px"> <el-form-item label="类型" prop="type"> <el-select v-model="form.type" placeholder="请选择"> <el-option v-for="item in assetType" :key="item.value" :label="item.label" :value="item.value"></el-option> </el-select> </el-form-item> <el-form-item label="非标准资产" v-if="form.type === 2" prop="nonStandardAssetsId"> <el-select v-model="form.nonStandardAssetsId" placeholder="请选择"> <el-option v-for="item in nonstandardData" :key="item.id" :label="item.name" :value="item.id" :disabled="item.status == 0"></el-option> </el-select> </el-form-item> </el-form> <template #footer> <div class="dialog-footer"> <el-button @click="closeDialog">取消</el-button> <el-button type="primary" @click="nextTips">下一步</el-button> </div> </template> </el-dialog> </div> <!-- 编辑,批量编辑,新增组件 --> <addAsset ref="addAssetRef" @previous-step="handlePreviousStep" /> <!-- 详情公共组件 --> <assetInfo ref="assetInfoRef"></assetInfo> </div> </template> <script setup lang="tsx" name="assetInventory"> import { ref, reactive, inject, onMounted, nextTick } from "vue"; import ProTable from "@/components/ProTable/index.vue"; import { assetListData, addAssetList, deleteAssetList, editBatchAssetList, assetListInfo, editAssetList } from "@/api/modules/assetAllocation"; import { ProTableInstance, ColumnProps } from "@/components/ProTable/interface"; import { formatToTree, extractSelectedNodes } from "@/utils/tools"; import { assetClassificationList, getPositionList, setValueClildList, nonstandardList, getOrgSubjectList, getInstitution } from '@/api/modules/public'; import { getUserDepartment } from "@/api/modules/user"; import { assetListType, assetType, markStatusType } from "@/utils/dict"; import addAsset from "./mode/addAsset.vue"; import assetInfo from "./mode/assetInfo.vue"; import { useHandleData } from "@/hooks/useHandleData"; import { ElMessage, FormInstance } from "element-plus"; import { printAssetMark } from "@/api/modules/assetAllocation"; import moment from "moment"; import axios from 'axios'; type nonstandardType = { id: string, name: string, status: number } const hasBtnPermission: any = inject('hasBtnPermission'); // ProTable 实例 const proTable = ref<ProTableInstance>(); // 部门级联树数据 const cascaderTreeData = ref([]); // 子界面需要用到的设置值 const configuration = reactive({ assetCategory: [] as any[], // 资产分类 positionList: [], // 存放地点 departmentList: [] as any[], // 使用部门 sourceList: [] as any[], // 资产来源 nonstandardList: [] as nonstandardType[], // 非标准资产 unitList: [] as any[], // 计量单位 institutionalEntity: [] as any[], //机构主体 assentityList: [] as any[], // 主体 assinstitutional: [] as any[],//机构 }) const selectedIds = ref<string[]>([]); // 在组件顶部定义 // 非标准资产 const nonstandardData = ref<nonstandardType[]>([]); const assentityList = ref<any[]>([]) const assinstitutional = ref<any[]>([]) // 资产类型弹窗 const dialogFormVisible = ref(false) type formType = { type: string | number, nonStandardAssetsId: string } const form = reactive<formType>({ type: '', nonStandardAssetsId: '' }) const rules = reactive({ type: [{ required: true, message: "请选择资产类型", trigger: ["blur", "change"] }], nonStandardAssetsId: [{ required: true, message: "请选择非标准资产", trigger: ["blur", "change"] }], }) const getTableList = (params: any) => { if (params.purchaseDate) { params.purchaseDateStart = params.purchaseDate[0] + ' 00:00:00'; params.purchaseDateEnd = params.purchaseDate[1] + ' 23:59:59'; delete params.purchaseDate; } if (params.maintenanceExpirationDate) { params.maintenanceExpirationDateStart = params.maintenanceExpirationDate[0] + ' 00:00:00'; params.maintenanceExpirationDateEnd = params.maintenanceExpirationDate[1] + ' 23:59:59'; delete params.maintenanceExpirationDate; } if (params.useUserNameData) { params.useUserNameList = params.useUserNameData.split('\n'); delete params.useUserNameData } if(params.assetCodeData) { const filteredArray = params.assetCodeData.split('\n'); params.assetCodeList = filteredArray.filter(item => item.trim() !== ''); delete params.assetCodeData } let deptNoList: any[] = []; // 部门级联数据处理 if (params.useDepartmentId && params.useDepartmentId.length > 0) { // 根据级联值获取所有选中的部门集合,如果子节点全部选中,父节点也要获取 deptNoList = extractSelectedNodes(params.useDepartmentId, cascaderTreeData.value); } if (deptNoList.length > 0) { params.useDepartmentIdList = deptNoList; } delete params.useDepartmentId; // 清除表格勾选项 if (proTable.value) { proTable.value.clearSelection(); } return assetListData(params) } const refreshTable = () => { proTable.value!.pageable.pageNum = 1; proTable.value?.refreshData(); // 清除表格勾选项 if (proTable.value) { proTable.value.clearSelection(); } }; const dataCallback = (data: any) => { const dataList = data?.dataList || []; const processedList = dataList.map(item => { try { return { ...item, imageUrlList: typeof item?.imageUrl === 'string' ? item.imageUrl.split(',') : [], purchaseDate: item.purchaseDate ? item.purchaseDate.split(" ")[0] : '' }; } catch (error) { return { ...item, imageUrlList: [] }; } }); return { list: processedList, total: data?.totalCount, pageNum: data?.page, pageSize: data?.pageSize }; }; // 查询计量单位 const getUnitList = async () => { const response = await setValueClildList({ dictCode: 'UNIT_MEASUREMENT' }); if (Array.isArray(response.data)) { configuration.unitList = response.data || []; } } // 查询机构主体 const getOrgSubjectListData = async () => { // 机构 const responseAss = await getInstitution({ id: 'ASS_INSTITUTIONAL' }); const data = responseAss.data || []; if (Array.isArray(data) && data.length > 0) { configuration.assinstitutional = data assinstitutional.value = data } // 主体 const response = await getInstitution({ id: 'OFFICIAL_SEAL_ORG' }); const data1 = response.data || []; if (Array.isArray(data1) && data1.length > 0) { configuration.assentityList = data1 assentityList.value = data1 } // 机构主体(二和一接口),用来把主体,机构以及部门三者关联起来,单独调用上面接口,主要是为了排序好看,无语子...... const res = await getOrgSubjectList({}, false); const data2 = res.data || []; if (Array.isArray(data) && data.length > 0) { configuration.institutionalEntity = data2 as any[]; } } const formatToDepTree = (arr, pid = 0) => { let result: any[] = []; for (let i = 0; i < arr.length; i++) { if (arr[i].pid === pid) { arr[i].label = arr[i].name let children = formatToDepTree(arr, arr[i].workOADepartmentId); if (children.length > 0) { arr[i].children = children; } result.push(arr[i]); } } return result; } // 表格配置项 const columns: ColumnProps[] = [ { type: "selection", fixed: "left", width: 50, }, { prop: "assetStatus", label: "资产状态", fixed: "left", minWidth: 100, enum: assetListType, search: { el: "select", props: { filterable: true } }, render: scope => { if (scope.row.assetStatus == '1') { return ( <span style="color: #49c625">空闲</span> ); } else if (scope.row.assetStatus == '2') { return ( <span style="color: #ff7f00">在用</span> ); } else if (scope.row.assetStatus == '3') { return ( <span style="color: #1890ff">已处置</span> ); } } }, { prop: "markStatus", label: "资产标记", isShow: false, enum: markStatusType, search: { el: "select", props: { filterable: true } }, fieldNames: { label: "label", value: "value" } }, { prop: "markTagsName", label: "资产标记", fixed: "left", minWidth: 100, render: scope => { if (scope.row.markTags == '0') { return ( <span style="color: #49c625">派发待领用</span> ); } else if (scope.row.markTags == '1') { return ( <span style="color: #ff7f00">领用审批中</span> ); } else if (scope.row.markTags == '2') { return ( <span style="color: #ff7f00">退还审批中</span> ); } else if (scope.row.markTags == '3') { return ( <span style="color: #ff7f00">借用审批中</span> ); } else if (scope.row.markTags == '4') { return ( <span style="color: #1890ff">借用</span> ); } else if (scope.row.markTags == '5') { return ( <span style="color: #ff7f00">调拨审批中</span> ); } else if (scope.row.markTags == '6') { return ( <span style="color: #ff7f00">维修审批中</span> ); } else if (scope.row.markTags == '7') { return ( <span style="color: #ff7f00">处置审批中</span> ); } else if (scope.row.markTags == '8') { return ( <span style="color: #ff0000">待处理</span> ); } else if (scope.row.markTags == '9') { return ( <span style="color: #ff7f00">归还审批中</span> ); } } }, { prop: "assetCodeData", label: "资产编码", isShow: false, search: { el: "input", type: 'textarea', placeholder: '多个编码请换行' }, minWidth: 100, }, { prop: "assetCode", label: "资产编码", fixed: "left", copy: false, minWidth: 100, render: (scope) => { return ( <span style="color: #49c625" onClick={() => handleAssetCodeClick(scope.row)}> {scope.row.assetCode} </span> ); } }, { prop: "imageUrl", label: "图片", minWidth:100, copy: false }, { prop: "assetCategoryIdList", label: "资产分类", isShow:false, enum: async () => { // 获取资产分类数据,扁平数据 const { data } = await assetClassificationList({}); if (Array.isArray(data)) { const treeData = formatToTree(data); configuration.assetCategory = treeData; return { data: treeData } } return { data: [] } }, fieldNames: { label: "categoryName", value: "id" }, search: { el: "tree-select", props: { filterable: true, multiple: true, checkStrictly: true, // 允许选择父节点 nodeKey: "id", // 每个节点的唯一标识字段 props: { label: "label", value: "id", children: "children" } } }, }, { prop: "assetName", label: "资产名称",isShow:false, search: { el: "input" },minWidth:100 }, { prop: "assetName", label: "资产名称", fixed: "left",minWidth:100 }, { prop: "assetCategoryName", label: "资产分类", minWidth:100 , }, { prop: "nonStandardAssetsId", label: "资产类型", minWidth: 100, isShow: false, }, { prop: "type", label: "资产类型", minWidth: 100, enum: assetType, search: { el: "select", props: { filterable: true } }, }, { prop: "useUserName", label: "使用人" }, { prop: "useUserNameData", label: "使用人", isShow: false, search: { el: "input", type: 'textarea', placeholder: '多个使用人请换行' } }, { prop: "useOrgIdList", label: "使用机构", search: { el: "select", props: { filterable: true, multiple: true } }, minWidth: 100, enum: assinstitutional, isShow: false, fieldNames: { label: "name", value: "detailCode" }, }, { prop: "useOrgName", label: "使用机构", minWidth: 100, }, { prop: "useSubjectId", label: "使用主体", search: { el: "select" }, minWidth: 100, enum: assentityList, isShow: false, fieldNames: { label: "remarks", value: "detailCode" }, }, { prop: "useSubjectName", label: "使用主体", minWidth: 100, }, { prop: "useDepartmentId", label: "使用部门", isShow: false, enum: async () => { // 获取组织架构数据,扁平数据 const { data } = await getUserDepartment(); data.forEach(item => { item.pid = item.extMap.parentWorkOADepartmentId item.workOADepartmentId = item.value item.id = item.value item.name = item.label }) // 将组织架构数据处理成树结构 const treeData = formatToDepTree(data); configuration.departmentList = treeData; return { data: treeData } }, search: { el: "cascader", props: { props: { multiple: true } } } }, { prop: "useDepartmentName", label: "使用部门", minWidth:100 , }, { prop: "storageLocationIdList", label: "存放地点", minWidth: 100, isShow: false, enum: async () => { // 获取存放地点 const res = await getPositionList({ pageNum: 1, pageSize: 9999 }); const data = res.data as any; const deepCopy = JSON.parse(JSON.stringify(data['dataList'])); configuration.positionList = deepCopy; return { data: data['dataList'] }; }, fieldNames: { label: "position", value: "id" }, search: { el: "select", props: { filterable: true, multiple: true } }, }, { prop: "storageLocationName", label: "存放地点", minWidth: 100, }, { prop: "adminName", label: "管理员", search: { el: "input" } }, { prop: "affiliatedInstitutionName", label: "所属机构", minWidth: 100 }, { prop: "affiliatedInstitutionIdList", label: "所属机构", isShow: false, search: { el: "select", props: { filterable: true, multiple: true } }, minWidth: 100, enum: assinstitutional, fieldNames: { label: "name", value: "detailCode" }, }, { prop: "affiliatedSubjectName", label: "所属主体", minWidth: 100 }, { prop: "affiliatedSubjectId", label: "所属主体", isShow: false, search: { el: "select" }, minWidth: 100, enum: assentityList, fieldNames: { label: "remarks", value: "detailCode" } }, { prop: "assetSourceTypeList", label: "资产来源", isShow: false, enum: async () => { // 获取资产来源 const data = await setValueClildList({ dictCode: 'SOURCE_ASSETS' }); configuration.sourceList = data['data'] as any[]; return { data: data['data'] } }, fieldNames: { label: "itemLabel", value: "itemValue" }, search: { el: "select", props: { filterable: true, multiple: true } }, }, { prop: "sourceCode", label: "资产来源", minWidth: 100, }, { prop: "brand", label: "品牌", search: { el: "input" }, }, { prop: "specificationModel", label: "规格型号", search: { el: "input" }, minWidth: 100 }, { prop: "serialNumber", label: "序列号", search: { el: "input" } }, { prop: "measurementUnit", label: "计量单位", minWidth: 100 }, { prop: "remarks", label: "备注", search: { el: "input" } }, { prop: "supplierName", label: "供应商", search: { el: "input" }, }, { prop: "inBoundNo", label: "入库单号", minWidth: 100 }, { prop: "nonStandardAssetsId", label: "非标准资产", enum: async () => { // 获取非标准资产 const data = await nonstandardList({}); if (Array.isArray(data)) { nonstandardData.value = data.filter(item => item.status == 1); configuration.nonstandardList = data } return { data: data } }, isShow: false, fieldNames: { label: "name", value: "id" }, search: { el: "select", props: { filterable: true } }, }, { prop: "purchaseDate", label: "购入日期", minWidth: 148, search: { el: "date-picker", props: { type: "daterange", valueFormat: "YYYY-MM-DD" }, }, }, { prop: "maintenanceExpirationDate", label: "维保到期日期", isShow: false, search: { el: "date-picker", props: { type: "daterange", valueFormat: "YYYY-MM-DD" }, }, }, { prop: "operation", label: "操作", fixed: "right", isShow: true, sortable: false } ] // 批量导出 const batchExport = async (command: any) => { try { const selectedIds = proTable.value?.selectedListIds || []; // 验证选择(如果command不是2,则需要选择数据) if (command != 2 && selectedIds.length === 0) { ElMessage.error({ message: `请选择要操作的数据` }); return; } const params = { idList: command === 2 ? [] : selectedIds // command=2表示导出全部 }; const response = await axios.post('/api/asset/inventory/downloadData', params, { responseType: 'blob' } ); let filename = `资产清单_${moment().format('YYYYMMDDHHmmss')}.xlsx`;// 设置下载文件的名称 const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', filename); document.body.appendChild(link); link.click(); link.remove(); // 清除表格勾选项 if (proTable.value) { proTable.value.clearSelection(); } } catch (error) { console.error("导出失败:", error); } }; // 批量删除 const batchDelete = async (ids: string[]) => { if (ids && ids.length === 0) { ElMessage.error({ message: `请选择要操作的数据` }); return } await useHandleData(deleteAssetList, { idList: ids }, `确认删除`); refreshTable() } // 批量编辑 const batcEdit = async (ids: string[]) => { if (ids && ids.length === 0) { ElMessage.error({ message: `请选择要操作的数据` }); return; } // 从表格中获取当前所有选中的行数据 const selectedRows = proTable.value?.selectedList || []; const types = selectedRows.map(row => row.type); const nonStandardAssets = selectedRows.map(row => row.nonStandardAssetsId); const uniqueTypes = [...new Set(types)]; const uniqueNoStandar = [...new Set(nonStandardAssets)]; if (uniqueTypes.length > 1) { ElMessage.warning("只能选择相同类型的资产进行批量编辑"); return; } if (uniqueNoStandar.length > 1) { ElMessage.warning("只能选择相同类型的非标准资产进行批量编辑"); return } selectedIds.value = ids; form.type = uniqueTypes.join(); form.nonStandardAssetsId = uniqueNoStandar.join(); editBatchData('批量编辑', 'batchEdit', {}); } // 打印标签 const openTagPrint = async (ids: string[]) => { if (ids && ids.length === 0) { ElMessage.error({ message: `请选择要操作的数据` }); return } const data = await printAssetMark({ idList: ids, type: 'baseInfo' }); if (data.code == 0) { ElMessage.success({ message: data.msg }); refreshTable() } else { ElMessage.error({ message: data.msg }); } } const closeDialog = () => { dialogFormVisible.value = false // 清除表格勾选项 if (proTable.value) { proTable.value.clearSelection(); } } // 子组件的上一步操作 const handlePreviousStep = () => { dialogFormVisible.value = true; // 重新打开对话框 // if( Type.value == 'batchEdit') {} // 回显之前选择的数据(form 已在 openDrawer 时保存) nextTick(() => { ruleFormRef.value?.clearValidate(); // 清除校验状态 }); // proTable.value!.setCheckedRows(proTable.value?.selectedList); // 回显之前选择的数据 }; const Title = ref(""); const Type = ref('add') const Row = ref({}) // 新增 const addNewData = (title: string, type: string, row: any = {}) => { Title.value = title Type.value = type Row.value = row // 清空表单值 form.type = ''; form.nonStandardAssetsId = ''; // 重置表单校验状态 nextTick(() => { ruleFormRef.value?.resetFields(); }); dialogFormVisible.value = true } // 编辑 const editData = async (title: string, type: string, row: any = {}) => { const { code, data, msg } = await assetListInfo({ id: row.id }); if (code == 0) { form.type = row.type form.nonStandardAssetsId = '' let listData = [data] Title.value = title Type.value = type Row.value = listData openDrawer() } else { ElMessage.error(msg); } } // 批量编辑 const editBatchData = (title: string, type: string, row: any = {}) => { Title.value = title Type.value = type Row.value = row openDrawer() } // 查看详情 const assetInfoRef = ref<InstanceType<typeof addAsset> | null>(null); const handleAssetCodeClick = async (row: any) => { const params = { row: { ...row }, api: deleteAssetList, configuration: configuration, refreshTable: () => { proTable.value!.pageable.pageNum = 1; proTable.value?.refreshData(); } } assetInfoRef.value?.acceptParams(params as any) } // 下一步 const nextTips = () => { ruleFormRef.value!.validate(async valid => { if (!valid) return; try { openDrawer() } catch (error) { console.log(error); } }) } // 新增/编辑 const ruleFormRef = ref<FormInstance>(); const addAssetRef = ref<InstanceType<typeof addAsset> | null>(null); const openDialog = () => { // 清空表单值 form.type = ''; form.nonStandardAssetsId = ''; // 重置表单校验状态 nextTick(() => { ruleFormRef.value?.resetFields(); }); dialogFormVisible.value = true } const openDrawer = () => { if (Type.value === 'add') { dialogFormVisible.value = false const params = { title: Title.value, type: Type.value, row: { ...Row.value }, form: { ...form }, configuration: configuration, isView: false, api: addAssetList, refreshTable: () => { proTable.value!.pageable.pageNum = 1; proTable.value?.refreshData(); } } addAssetRef.value?.acceptParams(params) } else if (Type.value === 'edit') { const params = { title: Title.value, type: Type.value, // configuration: configuration, isView: false, row: {}, form: { ...form }, infoRow: { ...Row.value }, api: editAssetList, refreshTable: () => { proTable.value!.pageable.pageNum = 1; proTable.value?.refreshData(); } } addAssetRef.value?.acceptParams(params) } else { dialogFormVisible.value = false const params = { title: Title.value, type: Type.value, configuration: configuration, isView: false, form: { ...form }, row: { selectedIds: selectedIds.value }, api: editBatchAssetList, refreshTable: () => { proTable.value!.pageable.pageNum = 1; proTable.value?.refreshData(); } } addAssetRef.value?.acceptParams(params) } } onMounted(() => { getUnitList(); getOrgSubjectListData(); }) </script> <style lang="scss" scoped> .more_imgs { div { display: inline-flex; } .viewImage { width: 25px; height: 25px; cursor: pointer; } } /* 确保选择列可见 */ ::v-deep .el-table__fixed-left { .el-table__cell.is-hidden>* { visibility: visible !important; } .el-checkbox { display: inline-block; } } </style> operationLog孙子界面的点击handleAssetCodeClick,并且带参数,在assetInventory界面的assetInfo组件返回中能调用
09-09
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值