位置: IT常识 - 正文

el-table大数据量渲染卡顿问题(eltable数据多 卡)

编辑:rootadmin
el-table大数据量渲染卡顿问题 1、场景描述

推荐整理分享el-table大数据量渲染卡顿问题(eltable数据多 卡),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:es做大数据存储,eltable数据多 卡,eltable数据多 卡,eltable数据多 卡,easyexcel大数据量 原理,el-table data,eltable数据多 卡,el-table data,内容如对您有帮助,希望把文章链接给更多的朋友!

在项目开发中,遇到在表格中一次性加载完的需求,且加载数量不少,有几百几千条,并且每条都可能有自己的下拉框,输入框来做编辑功能,此时普通的el-table肯定会导致浏览器卡死,那么怎么办呢?

2、解决方案

当然很多童鞋肯定会想到利用插件,其实我本人是不咋喜欢插件的,能自己写就自己写,毕竟插件可能也有bug或者啥的,万一出现了,作者不去改咋办,所以我总结了下面几个解决方法

提示:本篇博客基本都用的tsx + vue3 composition-api体验版 来写的噢,用vue2或者vue3模板语法写会更简单噢,照葫芦画瓢逻辑都是一样的,我这里就不写了,想了解相关的vue3知识我另一篇博客上有噢~

Vue3知识点学习

1、滚动触底分页(良)

当纵向滚动条触底的时候,加载新的数据到当前表格中,逻辑如下:

table.scrollTop + table.clientHeight === table.scrollHeight

当上述成立时候触发加载,table为表格dom, 但是如果数据很多的话,每次滚动都会将新的tr加入到表格中,那表格tr dom总数还是会依次递增,dom一多照样卡死

2、滚动区间分页(良+)

如果你没有表格编辑功能,全是展示数据的话,那么这个解决方案已经完全可以了

比如你当前表格可显示区域能够展示十条数据,那么首次进来时,显示数据的区间为 [0, 9],每次表格滚动时,都动态的去获取当前展示的区间,其实这种方式是比较好的,为啥呢?因为不管你几千几万条数据,我同一时刻就只有10行,完全不会因为tr数量过多导致浏览器渲染卡顿,当然这可视区域能展示多少条数据,是有你表格可视高度和单行tr高度一起决定的

const selectWrap = table.querySelector('.el-table__body-wrapper');const selectRow = table.querySelector('table tr');展示tr数量 = Math.ceil(selectWrap.clientHeight / selectRow.clientHeight)

tsx:页面

setup() {  return () => (    <el-table      data={visibleResult.value} // 可视区域的数据    >    </el-table>  )}

ts:逻辑

/** 表格上展示的数据 */ const visibleResult = computed(() => { return result.value.filter((_item, index) => { if (index < curStartIndex.value) { return false; } else if (index > curEndIndex.value) { return false; } else { return true; } }); })

那么如何去控制这个滚动区间呢?这个方法很多,监听滚动条的scroll,当向下滚动或向上滚动,我们都可以监听到,然后改变curStartIndex和curEndIndex的值就可以改变啦,这样的话,光是只看数据倒是解决了,但是要是表格要实现编辑效果咋办?每行数据有十几个下拉框和输入框,你要知道,el-select dom层级很高,像这种el-select数量一多,就算你当前展示区域没有多少条数据,也会导致渲染卡顿的,所以就有下面的优化版方案

3、滚动区间分页 + 表格编辑(优)

当前表格可视区域有30条数据,每条数据有10个el-select和5个el-input(当然可能有童鞋会说,el-select dom层级高,那我就自己写select鸭~但是你自己写的未必有el-select好看且功能相当)。此时首次加载就很卡顿了,原因就是el-select多了,那么我首先想的是这些el-select又不是直接要用,为啥不在我点击这个单元格时候再弹出下拉呢?不点击单元格时候,就直接展示文本效果(el-select没有值时展示 '请选择', 有值时展示你选择的值)

例图如下:

 滚动区间分页

 不管你有多少条数据,我始终首次只加载这么十多个tr,tr数量不变,变化的是每次的区间取值,大家会发现下面有个tr id为 virtual-scroll,那这是干什么 的呢?其实核心思路是:

显示区的高度 + 已经滚动过的高度 + 虚拟滚动条高度 === 总的数据高度table-wrapper.clientHeight + table-wrapper.scrollTop + virtual-scroll.height === data.lentth * tr.clientHeight

 是不是发现和方案1类似,但是区别不同的是,虚拟条高度可是一来就会被计算出来的,因为开始时候scrollTop为0, 那么 虚拟条高度 就是 总的数据高度 - 显示区高度

tsx: 通过自定义指令来监听表格的滚动,返回值触发loadMore方法,来决定显示区展示数据的区间

setup() { return () => ( <el-table data={visibleResult.value} // 可视区域的数据 {...{ directives: [{ name: 'load-more', value: methods.loadMore }] }} > </el-table> )}

ts: 逻辑

/** 表格上展示的数据 */ const visibleResult = computed(() => { return result.value.filter((_item, index) => { if (index < curStartIndex.value) { return false; } else if (index > curEndIndex.value) { return false; } else { return true; } }); })const methods = { /** * 懒加载回调 * @param startIndex 区段位置开始索引 * @param endIndex 区段位置结束索引 */ loadMore(startIndex: number, endIndex: number) { curStartIndex.value = startIndex curEndIndex.value = endIndex },}

那上面是实现滚动区间的代码,那说的表格编辑相关在哪里呢?下面即是:

表格编辑

当我们表格中有很多下拉框和输入框时,其实拖垮性能的多半是el-select,那解决方法是将渲染input和select的逻辑提出来,input不做处理,select当前单元格row,column索引和focusCell的值一致时说明单元格被聚焦了,就显示el-select,否则直接展示文本

el-table大数据量渲染卡顿问题(eltable数据多 卡)

关键方法及属性讲解:

inputChange:输入框回调

selectChange:下拉框选择回调

selectPerofrmance:下拉框当前值渲染

domPropsInnerHTML: 等同于v-html,但是jsx中不能用v-html

decorateHeader:表格各列数据我都是动态配置的,后续我会出一期博客来讲解vue3+tsx下如何封装表格

然后效果大致如下,总结下就是同一时间最多只会存在一个el-select,既然el-select dom减少了,那么表格渲染速度就自然而然快了

 上面例图中被黄色圈中的就是聚焦,没有被聚焦的都展示文本,源码讲解如下:

const focusCell = ref<string>('0,0') // 表格数据第0行第0列

 你在el-table 里有 cell-click 这个事件,它会将当前row, column全都回调回去,那么你就会知道你当前点击单元格的索引值, 我们将索引值生成, 在同一时间,focusCell只会有一条数据,所以我们直接用字符串来存储就好

<el-table  on-cell-click={methods.cellClick}></el-table>const methods = {  cellClick(row, column) {    if (focusCell.value !== `${row.index},${column.index}`) {        focusCell.value = `${row.index},${column.index}`      }  }}

那么关键来了,下拉框单元格聚焦的时候,我们才显示下拉框,其他时候展示文本,输入框类型单元格聚焦的时候不做处理,代码该如何写呢?

setup() { return () => { /** 输入框类型渲染 */ const inputDomRender = (scope, item) => ( <el-input value={scope.row[item.prop]} on-input={e => methods.inputChange(e, scope, item)} /> ) /** 下拉框类型渲染 */ const selectDomRender = (scope, item) => ( (focusCell.value === `${scope.row.autoIndex},${scope.column.index}` ? <el-select value-key='id' value={scope.row[item.prop]} onChange={e => methods.selectChange(e, scope, item)} > { item.selects.map(item1 => { return <el-option key={item1.id} label={item1.label} value={item1.id} > </el-option> }) } </el-select> : <div domPropsInnerHTML={methods.selectPerofrmance(scope.row[item.prop], item.prop)}></div>) ) return <el-table on-cell-click={methods.cellClick} > { decorateHeader.map((item: TableLabel) => { return <el-table-column width={item.width} label={item.label} align={item.align ? item.align : 'center'} prop={item.prop} scopedSlots={{ default: scope => { return <div > { item.mode !== 'input' ? selectDomRender(scope, item) : inputDomRender(scope, item) } </div> } }} > </el-table-column> }) } </el-table> }}

自此上述两步优化,其实就能使我们一次性加载几千条可编辑数据不会卡顿了~

3、v-load-more自定义指令

源码:

import { VNodeDirective} from 'vue'let timeout;/** 设置表格滚动区间 */const setRowScrollArea = (topNum, showRowNum, binding) => { if (timeout) { clearTimeout(timeout); } timeout = setTimeout(() => { binding.value.call(null, topNum, topNum + showRowNum); });};const loadMore= { bind(el: Element, _binding) { setTimeout(() => { // 创建虚拟滚动条 const selectWrap = el.querySelector('.el-table__body-wrapper'); const selectTbody = selectWrap.querySelector('table tbody'); const createElementTR = document.createElement('tr'); createElementTR.id = 'virtual-scroll' selectTbody.append(createElementTR); // 先行将虚拟滚动条加入进来 }) }, componentUpdated(el: Element, binding: VNodeDirective, vnode, oldVnode) { setTimeout(() => { const dataSize = vnode.data.attrs['data-size']; const oldDataSize = oldVnode.data.attrs['data-size']; // 当数量相同时,表明当前未发生更新,减少后续操作 if (dataSize === oldDataSize) { return; } const selectWrap = el.querySelector('.el-table__body-wrapper'); const selectTbody = selectWrap.querySelector('table tbody'); const selectRow = selectWrap.querySelector('table tr'); // 当一行都没有,说明无数据渲染,但一般逻辑都不会进入这里 if (!selectRow) { return; } const rowHeight = selectRow.clientHeight; // 能够在当前显示区的展示条数,本项目就是11条 const showRowNum = Math.round(selectWrap.clientHeight / rowHeight); const createElementTRHeight = (dataSize - showRowNum) * rowHeight; const createElementTR = selectTbody.querySelector('#virtual-scroll') // 监听滚动后事件 selectWrap.addEventListener('scroll', function() { let topPx = this.scrollTop; let topNum = Math.round(topPx / rowHeight); const minTopNum = dataSize - showRowNum; if (topNum > minTopNum) { topNum = minTopNum; } if (topNum < 0) { topNum = 0; topPx = 0; } selectTbody.setAttribute('style', `transform: translateY(${topPx}px)`); // 本来触底的话,应该设置为0,但是触底后 就没有滚动条了 createElementTR.setAttribute('style', `height: ${createElementTRHeight - topPx > 0 ? createElementTRHeight - topPx : rowHeight}px;`); setRowScrollArea(topNum, showRowNum, binding); }) }); }}export default loadMore

 不太了解自定义指令是啥的可以参考我另一篇博客

vue学习(6)自定义指令详解及常见自定义指令

4、有趣拓展1、我想在上述表格中对指定列实现高亮搜索怎么做?

当有值时滚动到指定位置,无值时不动,那首先在加载数据时,要先写下面代码

// 先让他触发滚动,才能让virtual-scroll高度生成table.$el.querySelector('.el-table__body-wrapper').scrollTo({ top: 1, behavior: 'smooth' })

输入框执行逻辑如下,防抖肯定是要的,然后搜索的列是 originName,当发现有搜索到值时,找到第一个被匹配到的行索引,然后去计算表格应该滚动到哪个高度位置,然后滚动

/** * 滚动定位到表格指定位置 * @param flag 是否能执行滚动的标志 * @returns */ scrollToTable: () => $debounce(function() { // 当没有值时,不进行搜索 if (dialogSearchKey.value) { const vmEl = table.value.$el; const selectWrap = vmEl.querySelector('.el-table__body-wrapper') if (vmEl) { const autoIndex = result.value.find((item: TableDataItem) => { return item.originName.indexOf(dialogSearchKey.value) !== -1 })?.autoIndex ?? -1 if (autoIndex !== -1) { scrollToIndex(selectWrap, autoIndex) } } } }, 500, false), /** * 表格滚动到指定索引值行 * @param selectWrap 表格dom * @param autoIndex 索引 */ scrollToIndex(selectWrap, autoIndex) { const showNum = 12 // 当显示条数小于次数时,不进行滚动操作 const topPx = autoIndex * columnHeight.value if (autoIndex > showNum) { selectWrap.scrollTo({ top: topPx, behavior: 'smooth' }) } }

 然后高亮被搜索文字源码如下:

setup() { return () => { return <el-table on-cell-click={methods.cellClick} > { decorateHeader.map((item: TableLabel) => { return <el-table-column width={item.width} label={item.label} align={item.align ? item.align : 'center'} prop={item.prop} scopedSlots={{ default: scope => { return <div > <div class='multiline' domPropsInnerHTML={methods.textRender(scope.row[item.prop], item.prop)} /> </div> } }} > </el-table-column> }) } </el-table> }}

 props.heightLight  为输入框的搜索关键词

/** * 文字渲染 * @param word 被渲染的文字 * @param prop 属性名 * @returns 替换后的渲染文字 */ textRender(word: string, prop: string): string { const reg = new RegExp(`${props.heightLight}`, 'ig') // 有搜索关键词 && 是否有该子字符串 if (props.heightLight && word.indexOf(props.heightLight) !== -1) { return word.replace(reg, `<font color='red'>$&</font>`) // 正常返回的列 } else { return word } } 2、前端实现表格导出excel

需要依赖如下:

import * as XLSX2 from 'xlsx';import XLSX from 'xlsx-style';

存在需要对依赖源码进行打补丁的地方:

1、/node_modules/xlsx-style/dist/cpexcel.js错误源码:var cpt = require('./cpt' + 'able');应修改为:var cpt = cptable;2、/node_modules/xlsx-style/dist/ods.js错误源码:return require('../' + 'xlsx').utils;应修改为:return require('./' + 'xlsx').utils;

变量名讲解:

// props.headerDisplay: 导出excel头部{ autoIndex: '序号', originName: '视频文件',}// exportData: 导出文件数据格式[ { autoIndex: 1, originName: 'xxx' }, { autoIndex: 2, originName: 'xxx' }]// headProp: 导出excel头部属性名数组['autoIndex', 'originName']

 导出excel源码: 

exportTransfer(exportData, header) { nextTick(() => { const newData = [props.headerDisplay, ...exportData] // 封装组合后的数据 const headProp = header.map(item => item.prop) // 头部属性数组 // 把json转为worksheet对象 后续用这种方法 const wb = XLSX2.utils.json_to_sheet(newData, { header: headProp, skipHeader: true }) // return const widthList = header.map(item => item.width ? Number(item.width) : 150) // 举例一共有14列(包括序号,不包括操作栏) wb['!cols'] = [] // 先初始化列数组配置 for (let i = 0; i < 14; i++) { wb['!cols'][i] = { wpx: widthList[i] } } // 样式的文档地址 // https://www.npmjs.com/package/xlsx-style for (const key in wb) { if (key.indexOf('!') === -1) { // 非excel配置类,带!都是配置类,这里对非配置类进行样式修改 wb[key].s = { font: { // 字体设置 sz: 13, bold: false, color: { // 只有DEFG第一行(标题行)才是红色,其余皆是黑色 rgb: new RegExp(/^[DEFG]1{1}$/).test(key) ? 'D9001B' : '000000' // 十六进制,不带#, 除去文件类型, 视频来源, 视频版权, 视频分类 这四栏标题行标红外,其他都是黑色 } }, alignment: { // 文字居中 horizontal: 'center', vertical: 'center', wrapText: 1 // 换行 }, border: { // 设置边框 top: { style: 'thin' }, bottom: { style: 'thin' }, left: { style: 'thin' }, right: { style: 'thin' } } } } } const filedata = sheet2blob(wb) openDownloadDialog(filedata, `xxx`) }) }, /** * 将一个sheet转成最终的excel文件的blob对象,然后利用URL.createObjectURL下载 * @param sheet excel对象 * @param sheetName * @returns */ sheet2blob(sheet, sheetName?: string) { const s2ab = (s) => { const buf = new ArrayBuffer(s.length); const view = new Uint8Array(buf); for (let i = 0; i !== s.length; ++i) { view[i] = s.charCodeAt(i) & 0xFF; } return buf; } sheetName = sheetName || 'sheet1'; const workbook = { SheetNames: [sheetName], Sheets: {} }; workbook.Sheets[sheetName] = sheet; // 生成excel的配置项 const wopts = { bookType: 'xlsx', // 要生成的文件类型 bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性 type: 'binary' }; const wbout = XLSX.write(workbook, wopts); const blob = new Blob([s2ab(wbout)], { // 字符串转ArrayBuffer type: 'application/octet-stream' }); return blob; }, /** * 创建excel地址并下载到本地 * @param url 文件blob二进制路径 * @param saveName 文件名 */ openDownloadDialog(url, saveName) { if (typeof url === 'object' && url instanceof Blob) { url = URL.createObjectURL(url); // 创建blob地址 } const aLink = document.createElement('a'); aLink.href = url; aLink.download = `${saveName}.xlsx`; // HTML5新增的属性,指定保存文件名 let event; if (window.MouseEvent) { event = new MouseEvent('click'); } else { event = document.createEvent('MouseEvents'); // 事件抛出 event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); } aLink.dispatchEvent(event); // 事件派发 }

有不理解的或有更好想法的可以底下评论喔~

本文链接地址:https://www.jiuchutong.com/zhishi/300569.html 转载请保留说明!

上一篇:flex布局之flex-direction(flex布局用法)

下一篇:SPL工业智能:发现时序数据的异常(工业 智能)

  • 盘点早期qq群使用的推广方式(最早的qq群)

    盘点早期qq群使用的推广方式(最早的qq群)

  • 早期最简单的赚钱方式,你造吗?(最简单最赚钱的行业)

    早期最简单的赚钱方式,你造吗?(最简单最赚钱的行业)

  • 苹果垃圾短信怎么设置过滤(苹果垃圾短信怎么举报骚扰)

    苹果垃圾短信怎么设置过滤(苹果垃圾短信怎么举报骚扰)

  • ios14有息屏显示功能吗(ios14.3息屏显示)

    ios14有息屏显示功能吗(ios14.3息屏显示)

  • 为什么iphone连接电脑不显示照片(为什么iphone连接不上)

    为什么iphone连接电脑不显示照片(为什么iphone连接不上)

  • iphone照片做壁纸太大怎么办(苹果手机照片怎么用作壁纸)

    iphone照片做壁纸太大怎么办(苹果手机照片怎么用作壁纸)

  • 华为荣耀v30pro是90hz刷新吗(华为荣耀x50i)

    华为荣耀v30pro是90hz刷新吗(华为荣耀x50i)

  • 电脑三原色英文叫什么(电脑三原色英文怎么表示)

    电脑三原色英文叫什么(电脑三原色英文怎么表示)

  • 充电宝鼓起来了(充电宝鼓起来了是怎么回事)

    充电宝鼓起来了(充电宝鼓起来了是怎么回事)

  • 插上耳机音量乱跳原因(插上耳机音量乱跳是手机问题还是耳机问题)

    插上耳机音量乱跳原因(插上耳机音量乱跳是手机问题还是耳机问题)

  • ios13横条动不了(苹果13横条)

    ios13横条动不了(苹果13横条)

  • 微信通话中断00是什么意思(微信通话中断原因有哪些)

    微信通话中断00是什么意思(微信通话中断原因有哪些)

  • 作业帮直播课学分有什么用(作业帮直播课学生端下载)

    作业帮直播课学分有什么用(作业帮直播课学生端下载)

  • photoshop是什么意思(ps什么意思)

    photoshop是什么意思(ps什么意思)

  • 20 gb的硬盘表示容量约为(20 gb的硬盘表示容量约为多少一个字节)

    20 gb的硬盘表示容量约为(20 gb的硬盘表示容量约为多少一个字节)

  • 小米6x最高支持几w快充(小米6x最高支持多少瓦)

    小米6x最高支持几w快充(小米6x最高支持多少瓦)

  • 微信群里相片多久失效(微信群多的图片)

    微信群里相片多久失效(微信群多的图片)

  • 手机自拍不了怎么办(手机怎么自拍不了)

    手机自拍不了怎么办(手机怎么自拍不了)

  • 华为多任务界面在哪里(华为多任务界面怎么调成重叠)

    华为多任务界面在哪里(华为多任务界面怎么调成重叠)

  • 电脑版qq怎么打印(电脑版qq怎么打开小程序)

    电脑版qq怎么打印(电脑版qq怎么打开小程序)

  • iphone11有5g吗(iphone11有5g功能吗)

    iphone11有5g吗(iphone11有5g功能吗)

  • 快手用户有多少(快手用户有多少亿2023)

    快手用户有多少(快手用户有多少亿2023)

  • 快手缓存的视频在哪里(快手缓存的视频怎么找)

    快手缓存的视频在哪里(快手缓存的视频怎么找)

  • 1660和1660ti区别(1660ti跟1660的区别)

    1660和1660ti区别(1660ti跟1660的区别)

  • 华为天际通如何使用(华为天际通如何续费)

    华为天际通如何使用(华为天际通如何续费)

  • wps投影宝有什么功能(wps投影宝只能放ppt吗)

    wps投影宝有什么功能(wps投影宝只能放ppt吗)

  • 路由器设置好了不能上网(路由器设置好了电脑不能上网怎么办)

    路由器设置好了不能上网(路由器设置好了电脑不能上网怎么办)

  • 【2022.3】尚硅谷Vue.js从入门到精通基础笔记(理论+实操+知识点速查)(尚硅谷百度贴吧)

    【2022.3】尚硅谷Vue.js从入门到精通基础笔记(理论+实操+知识点速查)(尚硅谷百度贴吧)

  • 所得税申报表的营业成本包括费用吗
  • 所得税汇算清缴后发现有误怎么办
  • 增值税计算为什么是销项减进项
  • 股票发行费用属于资本成本中的筹资费用
  • 独立核算的优点
  • 普通发票,供货怎么开
  • 员工报销会计分录怎么做
  • 购买软件平台信息服务费怎么做账?
  • 公司研发阶段的产品领料怎么处理?
  • 雇主责任险保费计算公式
  • 企业购买房产可以抵扣增值税吗
  • 内部交易增值税怎么算
  • 增值税税收返还资料
  • 广告宣传费用的计算方法
  • 在文具公司工作怎么样
  • 平台服务费如何开票
  • 一般纳税人哪些项目可以简易征收
  • 以下凭证免征印花税的有
  • 合并后的新企业有哪些
  • key介质费入哪个科目?
  • 公司单位员工餐费怎么算
  • 计算房产税租金会计分录
  • 已预缴的城建税会计分录
  • 什么发票可以抵成本
  • 股东投资如何做账务处理
  • 域名解析错误怎么解决mac
  • 物业专项维修资金可以退还吗
  • PHP:xml_parser_get_option()的用法_XML解析器函数
  • 税务部门罚没收入计入什么科目
  • 公司的贷款过桥怎么办
  • 企业发放职工薪酬属于资金的运用
  • php缓存数据到内存
  • php二分查找算法两种方法
  • 莫尼莫克房车
  • 小微企业没有进账,可以不报税吗
  • 公司登记注册费每年都要交吗
  • 委托加工的材料成本包括辅助材料成本吗
  • Smarty3配置及入门语法
  • 企业新产品销售收入数据
  • 微前端Qiankun
  • openresty php
  • YOLOv5网络结构组成
  • open是什么含义
  • react受控和不受控组件的区别
  • 农产品收购发票是普票还是专票
  • 质保金如果以后可以退吗
  • 分公司能给总公司担保吗
  • mongodb 入门
  • 购入画图软件
  • 工资走公账和私账哪个好
  • mysql怎么恢复数据
  • 什么是一般公共预算财政拨款
  • 社保局退的工伤保险怎么记账
  • 未达起征点怎么填
  • 怎么才能不开发票
  • 利润分配未分配利润在报表里怎么体现
  • 其他业务收入的现金流放哪里?
  • 接受捐赠后怎么发表感言
  • 企业清算状态还要报税吗
  • 冲销销售收入分录
  • 发票代码和发票号码是唯一的吗
  • 实缴资本和注册资本的比例
  • 发票上的数量怎么填写
  • 搜狗拼音输入法xp系统
  • 给Windows Server 2008设一个简单密码
  • linux文件系统的根目录的i节点号为
  • unity判断点击ui
  • linux命令find用法详解
  • js设置窗口大小
  • nodejs操作mysql
  • shell脚本编程100例
  • 超详细的!!!2023澳门六开彩
  • vue组件精讲
  • Eclipse ctrl+shift+r
  • 朵朵舞百科
  • 安卓app压力测试
  • 陕西省税务局发来信息通知
  • 个人所得税赡养老人可以填两个吗
  • 天猫主体变更是什么意思
  • 下载国税网上办税服务厅
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设