当http请求的参数需要借用到上一次http请求参数的结果时,利用promise或者利用更方便简洁的async/await

本文探讨了在需要连续发起多次HTTP请求,且后续请求依赖于前一次请求结果的情况下,如何利用Promise的then方法及async/await语法来简化代码,提高代码的可读性和维护性。

有时候会遇到一些情况,比如在点击事件触发的时候,我需要发送两次或以上的 http 请求,而这两次请求时相关的,即第二次 http 请求的参数需要携带第一次 http 请求的结果,这种时候,一般的处理如下:

function f() {
    $.get('xxx1.json', function(res1) {
        var m = res1.id // 假设返回一个对象,该对象的属性id,需要作为参数再次发送请求
        $.post('xxx2.json', {id: m}, function(res2) {
            console.log(res2) // 这里返回的 res2 就是我想要的结果
        })
    })
}

上述写法,很麻烦,如果遇到两次以上的请求时,会容易出错。

这时候,我们可以利用 promise 的 then 的写法进行封装:

function f1() {
    return new Promise((resolve, reject) => {
        // 这里用 setTimeout 模拟 http 请求
        setTimeout(() => {
            var result = {
                id: 10
            }
            
            resolve(result)  // 假设这个 result 就是第一次请求返回的结果,这个结果的 id 值将作为参数传递给第二次请求
        }, 2000)
    })
}

function f2(param) {
    // 这里的 param 参数就是第一次 http 请求的结果(result.id的值),这里将作为第二次 http 请求的参数
    return new Promise((resolve, reject) => {
        // 这里用 setTimeout 模拟 http 请求
        setTimeout(() => {
            var n = 20
            resolve(n)  // 假设这里的 n 的值就是第二次请求利用 result.id 作为实参的结果
        }, 1000)
    })
}

// promise.then 的写法
f1().then(res1 => {
    var id = res1.id
    f2(id).then(res2 => {
        console.log(res2)
    })
})

上述方法同样可以用 async/await 实现:


// async/await 的写法
async function test() {
    var s1 = await f1() // s1 表示第一次 http 返回的结果
    var s2 = await f2(s1.id) // s2 表示利用第一次 http 返回的结果(result.id),作为第二次 http 请求的参数,而得到的结果
    console.log(s2)
}
test()

如此看来,利用 async/await 写法,使代码结构和逻辑更清晰、易读。

补充实例:对于看不懂的朋友,我写了一份实例,如下:

getInfo = () => {
    return request({
        method: 'get',
        url: '/info',
        header: {
            "Content-type": "application/json",
        }
    })
}

getDetails = (id) => {
    return request({
        method: 'get',
        data: {
            userId: id
        },
        url: '/details',
        header: {
            "Content-type": "application/json"
        }
    })
}

function f1() {
    return new Promise((resolve, reject) => {
        getInfo().then(res => {
            var res = {
                id: 1,
                name: 'sonovabitch'
            }
            resolve(res)
        })
    })
}

function f2(param) {
    return new Promise((resolve, reject) => {
        getDetails(param).then(res => {
            var res = {
                name: 'bitch',
                age: 99
            }
            resolve(res)
        })
    })
}

// 第一种写法

f1().then(res1 => {
    f2(res1.id).then(res2 => {
        console.log(res2.name) // 'bitch'
    })
})

// 第二种写法
async function test() {
    var s1 = await f1()
    var s2 = await f2(s1.id)
    console.log(s2.name) // 'bitch'
}

 

<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
<think> 我们需要解决的是:在operationLog组件中点击“关联单据”,触发事件并传递参数,然后在assetInventory组件中能够接收到这个参数并调用assetInfo组件的方法。 分析: 1. operationLog组件中,当点击“关联单据”,会调用`handleAssetCodeClick`方法,并传递当前行数据。 ```javascript const handleAssetCodeClick = async (row: any) => { emit('previous-info',row); // 触发父组件事件 } ``` 这里通过`emit`触发了一个名为`previous-info`的自定义事件,并将行数据`row`作为参数传递。 2. operationLog组件的父组件是assetInfo(在assetInfo.vue中引用了operationLog): ```html <operationLog ref="operationLogRef" /> ``` 在assetInfo组件中,我们需要监听operationLog发出的`previous-info`事件,并进一步处理。 3. 在assetInfo组件中,我们有: ```javascript <operationLog ref="operationLogRef" /> ``` 我们需要在assetInfo组件中监听operationLog组件的`previous-info`事件。 4. 但是,我们的目标是将这个事件一直传递到assetInventory组件,因为assetInventory组件中包含了assetInfo组件,并且assetInventory组件中有一个方法`handleAssetCodeClick`,用于打开资产详情。 5. 因此,我们需要在assetInfo组件中,当监听到operationLog组件的`previous-info`事件,再次触发一个事件(比如`previous-info`)给它的父组件(即assetInventory组件)。 6. 在assetInventory组件中,我们引用了assetInfo组件,并给它注册了`previous-info`事件的处理: ```javascript <assetInfo ref="assetInfoRef" @previous-info="handleAssetCodeClick" /> ``` 注意:这里我们修改了assetInfo组件的使用方式,添加了事件监听。 步骤: 第一步:在assetInfo组件中,给operationLog组件添加事件监听。 修改assetInfo.vue中operationLog组件的使用: ```html <operationLog ref="operationLogRef" @previous-info="handlePreviousInfo" /> ``` 然后在assetInfo组件的setup中添加方法: ```javascript const handlePreviousInfo = (row) => { // 当收到operationLog的事件,触发assetInfo组件自身的previous-info事件,将row传递出去 emit('previous-info', row); } ``` 同,在assetInfo组件的defineEmits中声明事件: ```javascript const emit = defineEmits(['previous-info']); ``` 第二步:在assetInventory组件中,使用assetInfo组件监听`previous-info`事件。 修改assetInventory组件中assetInfo组件的使用: ```html <assetInfo ref="assetInfoRef" @previous-info="handleAssetCodeClick" /> ``` 这样,当operationLog组件触发`previous-info`事件,会依次经过: operationLog -> assetInfo(监听并转发)-> assetInventory 在assetInventory组件中,`handleAssetCodeClick`方法会被调用,并传入row数据。 注意:assetInventory组件中已经存在`handleAssetCodeClick`方法,它用于打开资产详情。 第三步:确保assetInfo组件的`previous-info`事件能够传递到assetInventory组件。 但是,我们注意到assetInfo组件在assetInventory组件中是通过ref引用的,并没有直接监听事件。所以我们需要修改assetInventory组件的模板,添加事件监听。 修改assetInventory组件的模板部分: ```html <assetInfo ref="assetInfoRef" @previous-info="handleAssetCodeClick" /> ``` 这样,当assetInfo组件触发`previous-info`事件,assetInventory组件的`handleAssetCodeClick`方法就会被调用。 总结事件传递链: 1. operationLog组件内部点击触发 -> emit('previous-info', row) 2. assetInfo组件中的operationLog组件监听到该事件,触发自己的handlePreviousInfo方法 -> 在该方法中emit('previous-info', row) 3. assetInventory组件中的assetInfo组件监听到`previous-info`事件,调用自己的handleAssetCodeClick方法。 代码修改: 1. 修改assetInfo.vue组件: 在template中找到operationLog组件,添加事件监听: ```html <operationLog ref="operationLogRef" @previous-info="handlePreviousInfo" /> ``` 在script中: ```javascript const emit = defineEmits(['previous-info']); // 如果之前没有,加上 const handlePreviousInfo = (row: any) => { emit('previous-info', row); } ``` 2. 在assetInventory.vue组件中,修改assetInfo组件的使用,添加事件监听: ```html <assetInfo ref="assetInfoRef" @previous-info="handleAssetCodeClick" /> ``` 这样,当在operationLog中点击关联单据,最终会触发assetInventory中的handleAssetCodeClick方法,并传递row参数,从而打开对应的资产详情。 注意:由于assetInventory组件中已经有一个`handleAssetCodeClick`方法,所以不需要再额外定义,直接使用即可。 但是,我们还需要注意:在assetInventory组件中,`handleAssetCodeClick`方法原本是通过ProTable的render函数触发的,现在又多了一个事件来源(来自operationLog的事件链)。所以我们需要确保这个方法能够处理两种来源的数据(实际上都是row数据,结构一致)。 现有的`handleAssetCodeClick`方法: ```javascript 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) } ``` 这个方法接受一个row参数,然后构造params,调用assetInfoRef.value?.acceptParams方法。 因此,无论事件从哪里来,只要传递的是row,就可以正常打开资产详情。 所以,我们只需要确保从operationLog传递过来的row数据与assetInventory中ProTable的row数据结构一致即可。 由于operationLog组件中的row是从操作日志接口返回的,而assetInventory中的row是从资产清单接口返回的,两者的数据结构可能不同。因此,我们需要调整operationLog传递的row数据,使其能够被assetInventory中的`handleAssetCodeClick`方法处理。 问题:两个row的结构不同,如何处理? 解决方案: 在operationLog组件中,我们传递的row是操作日志的行数据,其中包含一个`orderNo`(关联单据号),而assetInventory中需要的row应该包含资产编码(`assetCode`)或者资产id(`id`)。操作日志的行数据中可能没有资产id或资产编码。 因此,我们需要在操作日志的行数据中,能够获取到对应的资产id或资产编码。如果操作日志的行数据中没有资产id,那么我们就无法在assetInventory中打开资产详情。 建议: 1. 确认操作日志的行数据中是否包含资产id(assetId)或资产编码(assetCode)?从代码中看,操作日志接口返回的数据中,每一行应该有一个`assetId`(因为请求参数中有assetId)。我们可以通过操作日志的行数据中的`assetId`来获取资产详情。 2. 修改assetInventory中的`handleAssetCodeClick`方法,使其能够根据不同的参数(可能是资产id,也可能是资产编码)来打开详情。但是,assetInfo组件的`acceptParams`方法需要的是包含资产id的row对象。 观察assetInfo组件的`acceptParams`方法: ```javascript const acceptParams = async (params: DrawerProps) => { // ... const { code, data, msg } = await assetListInfo({ id: params.row!.id as string }); // ... } ``` 所以,它需要row对象中包含id(资产id)。 因此,在operationLog的行数据中,我们需要能够获取到资产id。如果操作日志接口返回的数据中没有资产id,那么我们需要调整接口返回,或者从其他字段中获取。 但是,从operationLog组件的代码中,我们可以看到,它是在一个资产详情的操作日志标签页中,这个资产详情已经有一个资产id(currentId),所以点击的操作日志条目是属于这个资产的吗?实际上,操作日志可能是针对这个资产的,也可能不是(比如调拨可能涉及两个资产?)。但是,操作日志中的`orderNo`可能是其他单据(如领用单、调拨单等),并不是资产本身的单据。 因此,我们的需求可能是:点击操作日志中的关联单据,打开的是这个关联单据的详情,而不是资产详情。但是目前我们的设计是打开资产详情。 所以,这里可能需要重新考虑需求。 如果需求是点击操作日志中的关联单据,打开的是这个关联单据对应的资产详情(即操作日志所操作的资产),那么我们可以这样处理: 在operationLog组件中,我们其实已经有一个currentId(当前资产详情页的资产id)。那么,在点击操作日志的关联单据,我们并不需要从行数据中取资产id,而是直接使用currentId。 修改operationLog组件的`handleAssetCodeClick`方法: ```javascript const handleAssetCodeClick = async (row: any) => { // 我们使用当前资产的id(currentId.value)来触发事件 emit('previous-info', { id: currentId.value }); } ``` 这样,传递给父组件的就是当前资产的id。 然后,在assetInventory组件的`handleAssetCodeClick`方法中,我们接收到的row对象中就包含id属性(资产id),就可以正常打开资产详情了。 但是,这样操作日志中每一行关联单据都指向同一个资产(当前资产详情页的资产),这可能不符合实际业务。因为操作日志可能是针对其他资产的操作。 所以,我们需要在操作日志的每一行数据中,包含被操作的资产的id。这个需要后端接口返回。 如果后端在操作日志接口中返回了被操作的资产id(比如字段名为assetId),那么我们可以这样修改: ```javascript const handleAssetCodeClick = async (row: any) => { // 假设row中有assetId字段 emit('previous-info', { id: row.assetId }); } ``` 这样,每一行操作日志都可以打开对应的资产详情。 综上所述,我们需要: 1. 确保操作日志接口返回的数据中包含被操作的资产id(assetId)。 2. 修改operationLog组件的`handleAssetCodeClick`方法,传递资产id。 如果后端无法返回assetId,那么可能需要重新考虑需求或方案。 鉴于当前代码中没有这样的字段,我们先按照有assetId的情况处理。如果实际返回字段名不同,请替换。 修改operationLog组件的handleAssetCodeClick方法: ```javascript const handleAssetCodeClick = async (row: any) => { // 假设row中有一个assetId字段,表示被操作的资产id if (row.assetId) { emit('previous-info', { id: row.assetId }); } else { // 如果没有,可能需要提示或者使用当前资产的id(currentId)作为后备 emit('previous-info', { id: currentId.value }); } } ``` 这样,我们就将资产id传递给了父组件。 然后,在assetInventory组件的`handleAssetCodeClick`方法中,它会使用这个id去调用资产详情接口。 注意:assetInventory组件的`handleAssetCodeClick`方法原本是接收一个row对象(来自资产清单的行数据),现在也可能接收一个只包含id的对象(来自操作日志事件)。所以我们需要调整这个方法,使其兼容两种情况。 修改assetInventory组件的`handleAssetCodeClick`方法: ```javascript const handleAssetCodeClick = async (row: any) => { // 如果row中直接有id属性,我们直接使用 // 如果row是一个对象但没有id,但是有assetId(比如操作日志的行数据)?不过我们现在在operationLog中已经构造了{id: row.assetId},所以这里row应该是一个包含id的对象 // 但是,在资产清单中,row是完整的资产行数据,其中包含id和assetCode等 // 所以,我们只需要row.id const assetId = row.id; // 因为我们在传递都保证了有id属性 const params = { row: { id: assetId }, // 只需要id,因为assetInfo组件的acceptParams方法中取的是row.id api: deleteAssetList, configuration: configuration, refreshTable: () => { proTable.value!.pageable.pageNum = 1; proTable.value?.refreshData(); } } assetInfoRef.value?.acceptParams(params as any) } ``` 这样修改后,无论从资产清单的表格行点击,还是从操作日志的关联单据点击,都能正确打开资产详情。 但是,注意在资产清单的表格行中,我们原本传递的是整个row,现在只需要row.id。而在操作日志中,我们传递的是{id: assetId}。所以这个方法可以兼容。 不过,在资产清单的render函数中,我们调用handleAssetCodeClick传递的是scope.row(整个行对象)。所以,在handleAssetCodeClick方法中,我们使用row.id是可以的,因为资产清单的行数据中有id字段。 因此,我们只需要修改operationLog组件的handleAssetCodeClick方法,使其传递一个包含id字段的对象即可。 步骤总结: 1. 修改operationLog组件的handleAssetCodeClick方法,传递资产id(从行数据中取assetId,或者使用currentId作为后备)。 2. 确保assetInventory组件的handleAssetCodeClick方法能够处理只包含id字段的对象。 3. 在assetInfo组件中,将operationLog组件的previous-info事件转发给assetInventory组件。 4. 在assetInventory组件中,为assetInfo组件添加@previous-info事件监听,绑定到handleAssetCodeClick方法。 代码修改示例: operationLog.vue: ```javascript const handleAssetCodeClick = async (row: any) => { // 尝试从行数据中获取资产id,如果行数据中没有,则使用当前资产的id(currentId.value) const assetId = row.assetId || currentId.value; emit('previous-info', { id: assetId }); } ``` assetInfo.vue: ```html <operationLog ref="operationLogRef" @previous-info="handlePreviousInfo" /> ``` ```javascript // 在setup中 const emit = defineEmits(['previous-info']); const handlePreviousInfo = (row: any) => { // 将事件转发 emit('previous-info', row); } ``` assetInventory.vue: ```html <assetInfo ref="assetInfoRef" @previous-info="handleAssetCodeClick" /> ``` ```javascript // handleAssetCodeClick方法不变,因为它已经可以处理包含id的行对象 ``` 注意:如果操作日志行数据中没有assetId,那么我们需要后端在返回操作日志数据,加上被操作的资产id(assetId)字段。 如果后端无法提供,那么可能需要根据业务逻辑调整,比如当前操作日志是在某个资产详情页下的,那么操作日志都是针对这个资产的,所以可以直接使用currentId。 请根据实际业务情况调整。 由于代码较长,以上仅提供关键修改点。请根据实际项目情况进行调整。 </think> 根据你的需求,我们需要实现从 `operationLog` 组件到 `assetInventory` 组件的跨层级事件传递,使得在 `assetInventory` 组件中能够调用 `assetInfo` 组件的方法。以下是详细的解决方案: ### 解决方案 我们需要在三个组件之间传递事件: 1. `operationLog` 组件触发事件 → 2. `assetInfo` 组件接收并转发事件 → 3. `assetInventory` 组件接收事件并调用 `assetInfo` 组件方法 ### 实现步骤 #### 1. 在 `operationLog` 组件中触发事件 修改 `handleAssetCodeClick` 方法,触发自定义事件并传递行数据: ```typescript const handleAssetCodeClick = async (row: any) => { // 触发自定义事件并传递行数据 emit('log-row-click', row); } ``` #### 2. 在 `assetInfo` 组件中转发事件 修改 `assetInfo.vue` 文件: - 监听 `operationLog` 组件的 `log-row-click` 事件 - 转发该事件给父组件 (`assetInventory`) ```typescript <script setup lang="ts" name="assetInfo"> // 添加事件定义 const emit = defineEmits(['log-row-click']); // 监听 operationLog 组件的事件 const onLogRowClick = (row: any) => { // 转发事件给父组件 (assetInventory) emit('log-row-click', row); } </script> <template> <!-- ...其他代码... --> <operationLog ref="operationLogRef" @log-row-click="onLogRowClick" /> </template> ``` #### 3. 在 `assetInventory` 组件中处理事件 修改 `assetInventory.vue` 文件: - 监听 `assetInfo` 组件的 `log-row-click` 事件 - 调用 `assetInfo` 组件的 `acceptParams` 方法 ```typescript // 在模板中添加事件监听 <assetInfo ref="assetInfoRef" @log-row-click="handleLogRowClick" /> // 添加事件处理方法 const handleLogRowClick = (row: any) => { // 调用 assetInfo 组件的 acceptParams 方法 assetInfoRef.value?.acceptParams({ row: { ...row }, api: deleteAssetList, configuration: configuration, refreshTable: () => { proTable.value!.pageable.pageNum = 1; proTable.value?.refreshData(); } }); } ``` ### 完整代码修改示例 #### `operationLog.vue` ```typescript // 修改 handleAssetCodeClick 方法 const handleAssetCodeClick = async (row: any) => { // 触发自定义事件 emit('log-row-click', row); } ``` #### `assetInfo.vue` ```typescript <script setup lang="ts" name="assetInfo"> // 添加事件定义 const emit = defineEmits(['log-row-click']); // 添加转发方法 const onLogRowClick = (row: any) => { emit('log-row-click', row); } </script> <template> <!-- ...其他代码... --> <operationLog ref="operationLogRef" @log-row-click="onLogRowClick" /> </template> ``` #### `assetInventory.vue` ```typescript <template> <!-- 添加事件监听 --> <assetInfo ref="assetInfoRef" @log-row-click="handleLogRowClick" /> </template> <script setup lang="tsx" name="assetInventory"> // 添加事件处理方法 const handleLogRowClick = (row: any) => { assetInfoRef.value?.acceptParams({ row: { ...row }, api: deleteAssetList, configuration: configuration, refreshTable: () => { proTable.value!.pageable.pageNum = 1; proTable.value?.refreshData(); } }); } </script> ``` ### 关键点解释 1. **事件命名**:使用 `log-row-click` 作为跨组件事件名确保一致性 2. **事件转发**: - `operationLog` → `assetInfo` (直接监听) - `assetInfo` → `assetInventory` (通过 emit 转发) 3. **方法调用**:在 `assetInventory` 中通过组件引用 (`assetInfoRef.value`) 调用 `acceptParams` 方法 4. **参数传递**:保持与原始 `handleAssetCodeClick` 相同的参数结构 ### 注意事项 1. 确保所有相关的组件都已正确设置 `ref` 属性 2. 验证事件名称在所有层级保持一致 (`log-row-click`) 3. 如果 `row` 数据结构有变化,需要在事件传递链中保持一致 ### 相关问题
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值