| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- <template>
- <el-dialog
- :title="'导入号码'"
- v-model="state.dialog.visible"
- width="75%"
- destroy-on-close
- :close-on-click-modal="false"
- :close-on-press-escape="false"
- draggable
- class="pd0 dialog-padding-none"
- >
- <el-tabs class="demo-tabs">
- <el-tab-pane>
- <template #label>
- <span class="custom-tabs-label">
- <SvgIcon name="ele-Grid"></SvgIcon>
- <span>Excel导入</span>
- </span>
- </template>
- <el-button @click="handleOpenFile" plain type="success" class="mt5"> 请选择excel文件上传导入</el-button>
- <el-text type="primary" class="ml5">{{ state.uploadFileName }} <SvgIcon v-if="state.uploadFileName" name="ele-Remove" @click="reset" color="var(--el-color-danger)"></SvgIcon></el-text>
- <!-- <ext-upload
- v-model="state.excelForm.file"
- placeholder="请选择上传文件"
- tips="请选择excel文件上传导入"
- style="width: 100%"
- :limit="1"
- mime="excel"
- @on-success="handleUploadFileSuccess">
- </ext-upload>-->
- </el-tab-pane>
- </el-tabs>
- <div class="w100 mt5">
- <div class="w100">
- <el-scrollbar @scroll="handleFieldHeaderScroll" ref="fieldHeaderScrollRef" :min-size="0">
- <div class="model-field-select-wrapper">
- <div class="model-field-select-header" v-for="(field,idx) in state.excelForm.columns"
- :key="'select_'+idx">
- <template v-if="idx===0">
- <div style="width: 135px;height: 32px;line-height:32px;border:1px solid #eee;text-align: center;">导入列选择</div>
- </template>
- <el-select-v2 v-else
- v-model="state.excelForm.importFields[idx]"
- :options="state.excelForm.selectFields"
- style="width: 135px;height: 36px;border:none;display: inline-block;flex-shrink: 0;margin-right: 10px;"
- filterable
- clearable>
- </el-select-v2>
- </div>
- </div>
- </el-scrollbar>
- </div>
- <vxe-table
- ref="excelRef"
- border="full"
- show-header-overflow
- :show-footer="false"
- :max-height="state.tableHeight"
- :loading="false"
- header-cell-class-name="task-list-header"
- header-align="left"
- empty-text=" "
- @cell-click="handleCellClick"
- :data="state.excelForm.data"
- @scroll="handleDataTableScroll"
- :row-config="{isHover:true,isCurrent:true}"
- :tooltip-config="{zIndex:9999}"
- :scroll-x="{enabled: true, gt: 100}"
- :scroll-y="{enabled: true, gt: 100}">
- <vxe-column
- v-for="(field,idx) in state.excelForm.columns"
- :key="idx"
- :field="field.field"
- :width="135"
- :title="field.name"
- show-overflow="title">
- <template v-if="field.field==='idx'" #default="{row,rowIndex}">
- <div class="w100 flex flex-align-items-center flex-justify-center hover-parent">
- <el-dropdown @command="handleRow($event,row,rowIndex)">
- <el-text type="primary" class="hover-child ml5 cursor-pointer font12"> <span>{{ rowIndex+1}}</span></el-text>
- <template #dropdown>
- <el-dropdown-item command="setHeader" style="color:var(--el-color-success)" class="font12">设为表头</el-dropdown-item>
- <el-dropdown-item command="delete" style="color:var(--el-color-danger)" class="font12">删除本行</el-dropdown-item>
- </template>
- </el-dropdown>
- </div>
- </template>
- </vxe-column>
- </vxe-table>
- </div>
- <template #footer>
- <span class="dialog-footer">
- <el-button @click="onClose" size="default">取 消</el-button>
- <el-button type="primary" @click="handleConfirm" :loading="state.importLoading" size="default">导入</el-button>
- </span>
- </template>
- </el-dialog>
- </template>
- <script setup lang="ts" name="EndpointImportDialog">
- import {reactive, onMounted, nextTick, ref, toRaw, unref} from 'vue';
- //定义初始变量,重置使用
- import {useFileDialog} from '@vueuse/core'
- import {$body, $post} from "/@/utils/request";
- import {Msg} from "/@/utils/message";
- import {VxeTable, VxeColumn, VxeTableInstance} from "vxe-table";
- import 'vxe-table/lib/style.css'
- import {useDebounceFn, useThrottleFn} from '@vueuse/core'
- import {ElScrollbar} from 'element-plus'
- import * as XLSX from 'xlsx'
- const fieldHeaderScrollRef = ref<InstanceType<typeof ElScrollbar>>();
- const excelRef = ref<VxeTableInstance>();
- const {files, open: handleOpenFile, reset, onChange:handleFileChange} = useFileDialog(
- {
- multiple: false,
- accept: '.xls,.xlsx, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel'
- })
- handleFileChange((files)=>{
- parseExcel()
- })
- const initState = () => ({
- dialog: {
- visible: false,
- type: '',
- title: '',
- submitTxt: '',
- },
- initColumnList: [{field: 'idx', name: '#', fixed: 'left'}],
- excelForm: {
- file: '',
- rowHeaderIndex: 0,
- rowContentIndex: 1,
- columns: [] as any[],
- sheet: '',
- sheets: [] as string[],
- data: [],
- loading: false,
- importFields: [] as string[],
- selectFields: []
- },
- uploadFileName: '' as String | null,
- importLoading: false,
- tableHeight: 400,
- fieldList:[
- {label:'手机号',value:'mobilePhone'},
- ]
- })
- // 定义变量内容
- const state = reactive(initState());
- const emit = defineEmits(['on-import-finish']);
- onMounted(() => {
- })
- const open = () => {
- state.dialog.visible = true;
- nextTick(() => {
- let clientHeight = document.body.clientHeight;
- let th = clientHeight - 60 - 120 - 300
- state.tableHeight = th;
- })
- state.excelForm.selectFields = state.fieldList.map((k: any) => {
- return {
- value: k.value,
- label: k.label
- }
- })
- }
- // 关闭弹窗
- const onClose = () => {
- state.dialog.visible = false;
- Object.assign(state, initState())
- reset();
- };
- const handleCellClick = (e: any) => {
- let {row, rowIndex, $rowIndex, column, columnIndex, $columnIndex} = e;
- if (columnIndex === 0) {
- return;
- }
- let val = state.excelForm.data[rowIndex][column.property]
- Msg.prompt(`修改导入的数据`, '修改',
- {
- draggable: true,
- type: 'primary',
- value: val
- }
- ).then((res: any) => {
- let {value, action} = res;
- if (action === 'confirm') {
- state.excelForm.data[rowIndex][column.property] = value
- }
- })
- }
- const handleConfirm = () => {
- let checks: Array<string> = [];
- let checkPass= true;
- state.excelForm.importFields.forEach(key => {
- if (key) {
- if (checks.includes(key)) {
- checkPass = false;
- Msg.message('表头不可重复', 'error')
- return false;
- } else {
- checks.push(key)
- }
- }
- })
- if(!checkPass)return;
- debounceImport();
- }
- const debounceImport = useThrottleFn(() => {
- state.importLoading = true;
- let fieldIndexes: Array<number> = []
- state.excelForm.importFields.forEach((key, idx) => {
- if (key) {
- fieldIndexes.push(idx - 1);
- }
- })
- let fields=state.excelForm.importFields.filter(k => !!k);
- let dataList : Array<any> = [];
- state.excelForm.data.forEach(data => {
- let item ={}
- let arr: Array<any> = []
- fieldIndexes.forEach((idx, i) => {
- item[fields[i]] = data[`f${idx}`] || ""
- })
- dataList.push(item)
- })
- let params = {
- fields: state.excelForm.importFields.filter(k => !!k),
- fieldIndexes,
- dataList
- }
- emit('on-import-finish',params)
- state.dialog.visible = false;
- state.importLoading = false;
- /* $body(`station/importStation`, params).then(() => {
- Msg.message(`导入成功`)
- state.importLoading = false;
- emit('on-import-finish')
- state.dialog.visible = false;
- }).catch(() => {
- state.importLoading = false;
- })*/
- }, 1500)
- //表头选择器滚动
- const handleFieldHeaderScroll = (ev: any) => {
- let {scrollLeft, scrollTop} = ev;
- // console.log(scrollLeft, scrollTop, ev)
- if (scrollLeft >= 0) {
- let st = excelRef.value.getScroll();
- const el = excelRef.value?.$el.querySelector('.vxe-table--body-wrapper')
- if (el) {
- el.scrollLeft = scrollLeft
- }
- }
- }
- //数据表格滚动
- const handleDataTableScroll = (ev: any) => {
- let {scrollLeft} = ev;
- // console.log(type, scrollLeft, scrollHeight)
- if (scrollLeft >= 0) {
- fieldHeaderScrollRef.value?.setScrollLeft(scrollLeft);
- }
- }
- const handleRow = (command: string, row: any, rowIndex: number) => {
- if (command === 'setHeader') {
- let tmpHeaders: any[] = []
- let tmpHeader = state.excelForm.data[rowIndex]
- Object.keys(tmpHeader).forEach((key, i) => {
- if (key.startsWith("f")) {
- let header = tmpHeader[key]
- let find = state.fieldList.find((k: any) => k.name == header);
- if (find) {
- state.excelForm.importFields[i + 1] = find.label;
- } else {
- state.excelForm.importFields[i + 1] = "";
- }
- tmpHeaders.push({
- field: `f${i}`,
- name: header
- });
- }
- })
- state.excelForm.columns = state.initColumnList.concat(tmpHeaders)
- state.excelForm.data.splice(rowIndex, 1)
- excelRef.value?.reloadData(state.excelForm.data);
- } else if (command === 'delete') {
- state.excelForm.data.splice(rowIndex, 1)
- excelRef.value?.reloadData(state.excelForm.data);
- }
- }
- const parseExcel = (sheetName: string = "") => {
- // console.log(sheetName, state.excelForm.sheet,files)
- // if(sheetName==state.excelForm.sheet&&state.excelForm.sheet){
- // return;
- // }
- if (!files || !files.value || !files.value[0]) {
- state.excelForm.columns = []
- excelRef.value?.reloadData([])
- state.uploadFileName = null;
- state.excelForm.sheets = []
- return;
- }
- // console.log(files)
- Msg.showLoading('解析中...')
- state.uploadFileName = files.value[0].name;
- let reader = new FileReader();
- reader.onload = function () {
- // console.log(reader)
- let fileData = reader.result;
- let wb = XLSX.read(fileData, {type: 'binary', cellDates: true});
- state.excelForm.sheets = wb.SheetNames;
- // {header:1} 取消标题列.
- // console.log(wb.SheetNames)
- let sheet = sheetName || wb.SheetNames[0];
- state.excelForm.sheet = sheet;
- let rowList: (any) = XLSX.utils.sheet_to_json(wb.Sheets[sheet], {header: 1});
- // console.log(rowList)
- let maxColumnLength = 1;
- rowList.forEach((row: any, idx: number) => {
- // console.log(row)
- if (idx < 10) {
- maxColumnLength = Math.max(maxColumnLength, row.length);
- }
- })
- // console.log(maxColumnLength, rowList)
- let tmpHeaders: Array<any> = []
- let headers = rowList[state.excelForm.rowHeaderIndex];
- for (let i = 0; i < maxColumnLength; i++) {
- let header = i >= headers.length ? '' : headers[i];
- let find = state.fieldList.find((k: any) => k.name == header);
- if (find) {
- state.excelForm.importFields[i + 1] = find.cname;
- } else {
- state.excelForm.importFields[i + 1] = "";
- }
- tmpHeaders.push({
- field: `f${i}`,
- name: header
- });
- }
- state.excelForm.columns = state.initColumnList.concat(tmpHeaders)
- // console.log(state.excelForm.columns)
- let tmpContents: any[] = []
- for (let i = state.excelForm.rowContentIndex; i < rowList.length; i++) {
- let dl = rowList[i];
- let rowItem = {}
- dl.forEach((rowValue: any, columnIdx: number) => {
- rowItem[`f${columnIdx}`] = rowValue
- })
- tmpContents.push(rowItem)
- }
- state.excelForm.data = tmpContents;
- state.excelForm.loading = false;
- excelRef.value?.reloadData(state.excelForm.data)
- // data.exportTableData = rowObj;
- Msg.hideLoading();
- };
- // 已二进制的形式读取文件
- reader.readAsBinaryString(unref(files)[0]);
- // 导入标识改为true
- // data.exportSign = true;
- }
- const handleClick = (sheet: string) => {
- parseExcel(sheet)
- // handleRow("setHeader",state.excelForm.data[0],0)
- }
- /*
- onChange = ((files) => {
- parseExcel();
- })
- */
- defineExpose({
- open
- })
- </script>
- <style scoped lang="scss">
- .custom-tabs-label {
- display: inline-flex;
- align-items: center;
- align-content: center;
- justify-content: space-between;
- }
- .model-field-select-wrapper {
- width: 100%;
- display: inline-flex;
- }
- .sheet-item {
- width: 135px;
- border-right: 2px solid #ddd;
- border-bottom: 2px solid #ddd;
- text-align: center;
- cursor: pointer;
- }
- .model-field-select-header {
- width: 135px;
- height: 36px;
- //overflow-x: auto;
- //display: inline-flex;
- //flex-wrap: wrap;
- :deep(.el-select-v2__wrapper) {
- border: 1px solid #eee !important;
- border-radius: 0px !important;
- }
- }
- :deep(.vxe-loading) {
- display: none !important;
- }
- .pd0 {
- :deep(.el-dialog__body) {
- padding: 0 !important;
- }
- }
- .vxe-table--tooltip-wrapper{
- z-index: 10000 !important;
- }
- </style>
|