buildadmin中header的导入功能

发布时间:2023年12月22日

序言:根据buildadmin提供的模块数据导入管理进行改写,变成当前模块下进行当前表格导入

首先在控制器的index.vue文件中进行如下操作

目的:旨在先将header中的导入按钮显示出来

<!-- 表格顶部菜单 -->
<!-- 自定义按钮请使用插槽,甚至公共搜索也可以使用具名插槽渲染,参见文档 -->
<TableHeader
:buttons="['refresh', 'add', 'edit', 'delete', 'unfold', 'comSearch', 'quickSearch', 'columnDisplay']"
:quick-search-placeholder="t('Quick search placeholder', { fields: t('treetable.quick Search Fields') })"
>
<el-button v-blur class="table-header-operate" type="success" style="margin-left: 12px" @click="stick">
    <Icon color="#ffffff" name="el-icon-Upload" />
    <span class="table-header-operate-text">{{ t('treetable.import') }}</span>
</el-button>
</TableHeader>

第二步:点击导入显示出导入上传的弹窗

因为第一步中存在<@click="stick">点击事件

const stick = () => {
    baTable.table.extend!.showPreImport = true  //点击才显示导入弹窗
    baTable.form.loading = true                    //加载样式
    baTable.form.extend!.fileUploadStatus = 'wait'   //上传状态
    setTimeout(() => {
        baTable.form.loading = false                //定时任务:1s后关闭加载样式
    }, 1000)
    close()
}

第三步:弹窗页面完善,首先需要在index.vue注册,并且进行引入弹窗页面


//注册
import dialogCom from '/@/components/treetable/dialogCom.vue'    //导入弹窗
import preImportDialogs from '/@/components/treetable/preImportDialogs.vue' //导入后预览
/**
* 引入
* 建议放在<PopupForm />后
*/
<dialogCom />        
<preImportDialogs />
<template>
    <el-dialog class="ba-operate-dialog" v-model="baTable.table.extend!.showPreImport" width="50%">
        <template #header>
            <div class="title" v-drag="['.ba-operate-dialog', '.el-dialog__header']" v-zoom="'.ba-operate-dialog'">导入</div>
        </template>
        <el-scrollbar v-loading="baTable.form.loading" class="ba-table-form-scrollbar">
            <div
                class="ba-operate-form"
                :class="'ba-' + baTable.form.operate + '-form'"
                :style="'width: calc(100% - ' + baTable.form.labelWidth! / 2 + 'px)'"
            >
                <el-form
                    v-if="!baTable.form.loading"
                    ref="formRef"
                    @submit.prevent=""
                    @keyup.enter="baTable.onSubmit(formRef)"
                    :model="baTable.form.items"
                    label-position="right"
                    :label-width="baTable.form.labelWidth + 'px'"
                >
                    <el-form-item label="导入数据" prop="file">
                        <el-upload class="upload-xls" :show-file-list="false" accept=".xlsx,.xls" drag :auto-upload="false" @change="uploadXls">
                            <div v-if="baTable.form.extend!.fileUploadStatus == 'wait'" class="upload-file-box">
                                <Icon size="50px" color="#909399" name="el-icon-UploadFilled" />
                                <div class="el-upload__text">拖拽 .xls[x] 文件至此处 <em>或点击我上传</em></div>
                            </div>
                            <div v-if="baTable.form.extend!.fileUploadStatus == 'uploading'" class="upload-file-box">
                                <Icon size="50px" color="#ffffff" v-loading="true" name="el-icon-UploadFilled" />
                                <div class="el-upload__text">上传中...</div>
                            </div>
                            <div v-if="baTable.form.extend!.fileUploadStatus == 'success'" class="upload-file-box">
                                <Icon size="50px" color="#ffffff" v-loading="true" name="el-icon-UploadFilled" />
                                <div class="el-upload__text">文件上传成功,正在处理...</div>
                            </div>
                        </el-upload>
                    </el-form-item>
                    <el-form-item>
                        <el-alert title="提示" class="import-tips" type="success">
                            <p>1、导入数据内无`主键`字段或`主键留空`则可以使用主键自动递增</p>
                            <p>2、若数据表有设计`create_time`、`update_time`字段且导入数据内未设定这两个字段的值,则自动填充</p>
                            <p>
                                3、所有已设定值的导入数据,将原样导入,比如:`create_time`字段,数据表设计为时间戳则请导入时间戳,`status:0=隐藏,1=开启`,请导入`0`或`1`
                            </p>
                        </el-alert>
                    </el-form-item>
                </el-form>
            </div>
        </el-scrollbar>
        <template #footer>
            <div :style="'width: calc(100% - ' + baTable.form.labelWidth! / 1.8 + 'px)'">
                <el-button @click="baTable.table.extend!.showPreImport = false">{{ t('Cancel') }}</el-button>
            </div>
        </template>
    </el-dialog>
</template>

<script setup lang="ts">
import {ref, inject, watch } from 'vue'
import type baTableClass from '/@/utils/baTable'
import type { ElForm, UploadFile } from 'element-plus'
import { useI18n } from 'vue-i18n'
import { handleXls } from '/@/api/backend/treetable'
import { fileUpload } from '/@/api/common'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'

const formRef = ref<InstanceType<typeof ElForm>>()
const baTable = inject('baTable') as baTableClass
const { t } = useI18n()


const uploadXls = (file: UploadFile) => {
    if (!file || !file.raw) return

    NProgress.configure({ showSpinner: false })
    NProgress.start()

    baTable.form.extend!.fileUploadStatus = 'uploading'

    let fd = new FormData()
    fd.append('file', file.raw!)
    console.log(1111)
    fileUpload(fd, {}, true, {
        onUploadProgress: (evt) => {
            NProgress.set(evt.progress!)
        },
    })
        .then((res) => {
            console.log(2222)
            if (res.code == 1) {
                handleXls('treetable', res.data.file.url)
                    .then((handleRes) => {                  
                        baTable.table.extend!.showPreImports = true
                        baTable.table.extend!.fields = handleRes.data.fields
                        baTable.table.extend!.rowCount = handleRes.data.rowCount
                        baTable.table.extend!.data = handleRes.data.data
                        baTable.table.extend!.file_url = res.data.file.url
                        baTable.form.extend!.fileUploadStatus = 'success'
                    })
                    .catch(() => {
                        baTable.form.extend!.fileUploadStatus = 'wait'
                    })
            }
        })
        .catch(() => {
            baTable.form.extend!.fileUploadStatus = 'wait'
        })
        .finally(() => {
            NProgress.done()
        })
}


watch(
    () => baTable.table.extend!.showPreImports,
    (newVal) => {
        if (newVal === false) {
            baTable.form.extend!.fileUploadStatus = 'wait'
        }
    }
)
</script>

<style scoped lang="scss">
.template-text-success {
    color: var(--el-color-success);
    cursor: pointer;
    user-select: none;
}
.template-text-info {
    color: var(--el-color-info);
}
.upload-xls {
    width: 100%;
}
.import-tips {
    line-height: 16px;
}
</style>
<template>
    <div>
        <el-dialog title="导入预览" width="80%" v-model="baTable.table.extend!.showPreImports" class="pre-import-dialog" top="5vh">
            <el-alert
                :title="'总计 ' + baTable.table.extend!.rowCount + ' 条数据' + (baTable.table.extend!.rowCount > 101 ? ',请目检导入数据的前面50条及最后50条~':'。')"
                class="import-tips"
                :closable="false"
                type="success"
            ></el-alert>
            <el-table :data="baTable.table.extend!.data" style="width: 100%" height="600">
                <el-table-column
                    v-for="(item,idx) in baTable.table.extend!.fields"
                    :key="idx"
                    :label="item.COLUMN_COMMENT ? item.COLUMN_COMMENT : ''"
                >
                    <el-table-column :prop="item.COLUMN_NAME" :label="item.COLUMN_NAME" />
                </el-table-column>
            </el-table>
            <template #footer>
                <div :style="'width: calc(100% - ' + baTable.form.labelWidth! / 1.8 + 'px)'">
                    <el-button @click="baTable.table.extend!.showPreImports = false">{{ $t('Cancel') }}</el-button>
                    <el-button v-blur :loading="state.importBtnLoading" type="primary" @click="onImport">导入</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>

<script setup lang="ts">
import { inject, reactive } from 'vue'
import type baTableClass from '/@/utils/baTable'
import { importXls } from '/@/api/backend/treetable'

const baTable = inject('baTable') as baTableClass

const state = reactive({
    importBtnLoading: false,
})

const onImport = () => {
    state.importBtnLoading = true
    importXls('treetable', baTable.table.extend!.file_url)
        .then(() => {
            baTable.table.extend!.showPreImports = false
            baTable.toggleForm()
            baTable.onTableHeaderAction('refresh', {})
        })
        .finally(() => {
            state.importBtnLoading = false
        })
}
</script>

<style scoped lang="scss">
:deep(.pre-import-dialog) .el-dialog__body {
    padding: 10px 20px;
}
.import-tips {
    margin-bottom: 10px;
}
</style>

?创建当前控制的treetable.ts文件,供页面进行调用

import createAxios, { getUrl } from '/@/utils/axios'
const controllerUrl = '/admin/treetable/'

export function handleXls(table: string, url: string) {
    return createAxios({
        url: controllerUrl + 'handleXls',
        method: 'get',
        params: {
            file: url,
            table: table,
        },
    })
}

export function importXls(table: string, url: string) {
    return createAxios(
        {
            url: controllerUrl + 'handleXls',
            method: 'post',
            params: {
                file: url,
                table: table,
            },
        },
        {
            showSuccessMessage: true,
        }
    )
}

最后:重点控制器中编写关于导入的方法

?

/**
     * 导入方法
     * @return void
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     */
    public function handleXls()
    {
        $file  = $this->request->request('file', '');
        $table = $this->request->request('table', '');
        if (!$table) {
            $this->error('请选择数据表!');
        }
        if (!$file) {
            $this->error('请上传导入数据!');
        }
        

        // 读取xls文件内容
        $filePath    = Filesystem::fsFit(public_path() . $file);
        $spreadsheet = IOFactory::load($filePath);
        $sheet       = $spreadsheet->getSheet(0);
        $rowCount    = $sheet->getHighestRow();
        $data        = $sheet->toArray();
        $fields      = get_table_fields($table);
        


        // 寻找字段对应数据所在的 key 值
        // 字段名、字段备注、字段名(字段备注)、字段名(字段备注+字段字典)
        $importKeys = [];
        foreach ($fields as $key => $field) {
            $title    = $field['COLUMN_NAME'] . ($field['COLUMN_COMMENT'] ? '(' . $field['COLUMN_COMMENT'] . ')' : '');
            $titleKey = array_search($title, $data[0]);
            if ($titleKey !== false) {
                $importKeys[$field['COLUMN_NAME']] = $titleKey;
                continue;
            }

            $nameKey = array_search($field['COLUMN_NAME'], $data[0]);
            if ($nameKey !== false) {
                $importKeys[$field['COLUMN_NAME']] = $nameKey;
                continue;
            }

            if ($field['COLUMN_COMMENT']) {
                $commentKey = array_search($field['COLUMN_COMMENT'], $data[0]);
                if ($commentKey !== false) {
                    $importKeys[$field['COLUMN_NAME']] = $commentKey;
                    continue;
                }

                if (strpos($field['COLUMN_COMMENT'], ':')) {
                    $comment      = explode(':', $field['COLUMN_COMMENT']);
                    $cleanComment = $comment[0];
                    $commentKey   = array_search($cleanComment, $data[0]);
                    if ($commentKey !== false) {
                        $importKeys[$field['COLUMN_NAME']] = $commentKey;
                        continue;
                    }

                    $titleCleanComment = $field['COLUMN_NAME'] . '(' . $cleanComment . ')';
                    $commentKey        = array_search($titleCleanComment, $data[0]);
                    if ($commentKey !== false) {
                        $importKeys[$field['COLUMN_NAME']] = $commentKey;
                    }
                    $fields[$key]['COLUMN_COMMENT'] = $cleanComment;
                }
            }
        }

        $importPre = [];
        foreach ($data as $key => $item) {
            if ($key == 0) continue;
            $importPreItem = [];
            foreach ($importKeys as $importKey => $importValueKey) {
                $importPreItem[$importKey] = $item[$importValueKey];
            }
            $importPre[] = $importPreItem;
        }
        
        if ($this->request->isPost()) {
            // 导入到表
            $nowTime    = time();
            $nowYmdHis  = date('Y-m-d H:i:s');
            $timeFields = ['createtime', 'create_time', 'updatetime', 'update_time'];
            foreach ($importPre as &$item) {
                foreach ($timeFields as $timeField) {
                    if (array_key_exists($timeField, $fields) && (!isset($item[$timeField]) || !$item[$timeField])) {
                        if ($fields[$timeField]['DATA_TYPE'] == 'int' || $fields[$timeField]['DATA_TYPE'] == 'bigint') {
                            $item[$timeField] = $nowTime;
                        } elseif ($fields[$timeField]['DATA_TYPE'] == 'datetime') {
                            $item[$timeField] = $nowYmdHis;
                        }
                    }
                }
            }
            Db::startTrans();
            $res = 0;
            try {
                $res = Db::name($table)->strict(false)->limit(500)->insertAll($importPre);
                // dump(1111);
                Db::name('dataimport')->insert([
                    'data_table'             => $table,
                    'admin_id'               => $this->auth->id,
                    'file'                   => $file,
                    'records'                => $rowCount - 1,
                    'import_success_records' => $res,
                    'radio'                  => 'import',
                    'create_time'            => $nowTime,
                ]);
                Db::commit();
                @unlink($filePath);
            } catch (Throwable $e) {
                Db::rollback();
                $this->error($e->getMessage());
            }
            $this->success('总计' . ($rowCount - 1) . '行数据,成功导入' . $res . '条!', [
                'data' => $importPre,
            ]);
        }

        if ($rowCount > 101) {
            $importPre = array_merge(array_slice($importPre, 0, 50), array_slice($importPre, $rowCount - 51, $rowCount));
        }

        $this->success('', [
            'fields'   => $fields,
            'rowCount' => ($rowCount - 1),
            'data'     => $importPre,
        ]);
    }

文章来源:https://blog.csdn.net/qq_53457276/article/details/135149612
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。