SpringBoot+Vue實現el-table表頭篩選排序(附源碼)

👨?💻作者簡介:在笑大學牲

🎟?個人主頁:無所謂^_^

?ps:點贊是免費的,卻可以讓寫博客的作者開心好幾天😎

前言

后臺系統對table組件的需求是最常見的,不過element-ui的el-table組件只是能滿足最基本的需求而已。本篇文章就是對table組件進行自定義,實現列的自定義排序、篩選功能。替換掉原來的輸入框搜索。

一、項目介紹

項目下載(本篇文章的源碼在工程目錄通用后臺管理系統中)

gitee:https://gitee.com/wusupweilgy/springboot-vue.git

1.項目運行效果

2.技術棧

前端:vue2、element-ui組件、axios

后端:springboot、mybatis-plus、redis

3.功能

  • 表頭自定義篩選
  • 表頭自定義排序

4.流程圖

二、前端實現

1.定義表頭篩選組件:

該組件在src/components/FilterHeader/inddex.vue中,可以實現字典、數字、文本、日期的篩選排序功能

<template><div class="app-container"><el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"><el-form-item label="字典名稱" prop="dictName"><el-inputv-model="queryParams.dictName"placeholder="請輸入字典名稱"clearablestyle="width: 240px"@keyup.enter.native="handleQuery"/></el-form-item><el-form-item label="字典類型" prop="dictType"><el-inputv-model="queryParams.dictType"placeholder="請輸入字典類型"clearablestyle="width: 240px"@keyup.enter.native="handleQuery"/></el-form-item><el-form-item label="狀態" prop="status"><el-selectv-model="queryParams.status"placeholder="字典狀態"clearablestyle="width: 240px"><el-optionv-for="dict in dict.type.sys_normal_disable":key="dict.value":label="dict.label":value="dict.value"/></el-select></el-form-item><el-form-item label="創建時間"><el-date-pickerv-model="dateRange"style="width: 240px"value-format="yyyy-MM-dd"type="daterange"range-separator="-"start-placeholder="開始日期"end-placeholder="結束日期"></el-date-picker></el-form-item><el-form-item><el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button><el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button></el-form-item></el-form><el-row :gutter="10" class="mb8"><el-col :span="1.5"><el-buttontype="primary"plainicon="el-icon-plus"size="mini"@click="handleAdd"v-hasPermi="['system:dict:add']">新增</el-button></el-col><el-col :span="1.5"><el-buttontype="success"plainicon="el-icon-edit"size="mini":disabled="single"@click="handleUpdate"v-hasPermi="['system:dict:edit']">修改</el-button></el-col><el-col :span="1.5"><el-buttontype="danger"plainicon="el-icon-delete"size="mini":disabled="multiple"@click="handleDelete"v-hasPermi="['system:dict:remove']">刪除</el-button></el-col><el-col :span="1.5"><el-buttontype="warning"plainicon="el-icon-download"size="mini"@click="handleExport"v-hasPermi="['system:dict:export']">導出</el-button></el-col><el-col :span="1.5"><el-buttontype="danger"plainicon="el-icon-refresh"size="mini"@click="handleRefreshCache"v-hasPermi="['system:dict:remove']">刷新緩存</el-button></el-col><right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar></el-row><el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange"><el-table-column type="selection" width="55" align="center" /><el-table-column label="字典編號" align="center" prop="dictId" /><el-table-column label="字典名稱" align="center" prop="dictName" :show-overflow-tooltip="true" /><el-table-column label="字典類型" align="center" :show-overflow-tooltip="true"><template slot-scope="scope"><router-link :to="'/system/dict-data/index/' + scope.row.dictId" class="link-type"><span>{{ scope.row.dictType }}</span></router-link></template></el-table-column><el-table-column label="狀態" align="center" prop="status"><template slot-scope="scope"><dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/></template></el-table-column><el-table-column label="備注" align="center" prop="remark" :show-overflow-tooltip="true" /><el-table-column label="創建時間" align="center" prop="createTime" width="180"><template slot-scope="scope"><span>{{ parseTime(scope.row.createTime) }}</span></template></el-table-column><el-table-column label="操作" align="center" class-name="small-padding fixed-width"><template slot-scope="scope"><el-buttonsize="mini"type="text"icon="el-icon-edit"@click="handleUpdate(scope.row)"v-hasPermi="['system:dict:edit']">修改</el-button><el-buttonsize="mini"type="text"icon="el-icon-delete"@click="handleDelete(scope.row)"v-hasPermi="['system:dict:remove']">刪除</el-button></template></el-table-column></el-table><paginationv-show="total>0":total="total":page.sync="queryParams.pageNum":limit.sync="queryParams.pageSize"@pagination="getList"/><!-- 添加或修改參數配置對話框 --><el-dialog :title="title" :visible.sync="open" width="500px" append-to-body><el-form ref="form" :model="form" :rules="rules" label-width="80px"><el-form-item label="字典名稱" prop="dictName"><el-input v-model="form.dictName" placeholder="請輸入字典名稱" /></el-form-item><el-form-item label="字典類型" prop="dictType"><el-input v-model="form.dictType" placeholder="請輸入字典類型" /></el-form-item><el-form-item label="狀態" prop="status"><el-radio-group v-model="form.status"><el-radiov-for="dict in dict.type.sys_normal_disable":key="dict.value":label="dict.value">{{dict.label}}</el-radio></el-radio-group></el-form-item><el-form-item label="備注" prop="remark"><el-input v-model="form.remark" type="textarea" placeholder="請輸入內容"></el-input></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button type="primary" @click="submitForm">確 定</el-button><el-button @click="cancel">取 消</el-button></div></el-dialog></div>
</template><script>
import { listType, getType, delType, addType, updateType, refreshCache } from "@/api/system/dict/type";export default {name: "Dict",dicts: ['sys_normal_disable'],data() {return {// 遮罩層loading: true,// 選中數組ids: [],// 非單個禁用single: true,// 非多個禁用multiple: true,// 顯示搜索條件showSearch: true,// 總條數total: 0,// 字典表格數據typeList: [],// 彈出層標題title: "",// 是否顯示彈出層open: false,// 日期范圍dateRange: [],// 查詢參數queryParams: {pageNum: 1,pageSize: 10,dictName: undefined,dictType: undefined,status: undefined},// 表單參數form: {},// 表單校驗rules: {dictName: [{ required: true, message: "字典名稱不能為空", trigger: "blur" }],dictType: [{ required: true, message: "字典類型不能為空", trigger: "blur" }]}};},created() {this.getList();},methods: {/** 查詢字典類型列表 */getList() {this.loading = true;listType(this.addDateRange(this.queryParams, this.dateRange)).then(response => {this.typeList = response.rows;this.total = response.total;this.loading = false;});},// 取消按鈕cancel() {this.open = false;this.reset();},// 表單重置reset() {this.form = {dictId: undefined,dictName: undefined,dictType: undefined,status: "0",remark: undefined};this.resetForm("form");},/** 搜索按鈕操作 */handleQuery() {this.queryParams.pageNum = 1;this.getList();},/** 重置按鈕操作 */resetQuery() {this.dateRange = [];this.resetForm("queryForm");this.handleQuery();},/** 新增按鈕操作 */handleAdd() {this.reset();this.open = true;this.title = "添加字典類型";},// 多選框選中數據handleSelectionChange(selection) {this.ids = selection.map(item => item.dictId)this.single = selection.length!=1this.multiple = !selection.length},/** 修改按鈕操作 */handleUpdate(row) {this.reset();const dictId = row.dictId || this.idsgetType(dictId).then(response => {this.form = response.data;this.open = true;this.title = "修改字典類型";});},/** 提交按鈕 */submitForm: function() {this.$refs["form"].validate(valid => {if (valid) {if (this.form.dictId != undefined) {updateType(this.form).then(response => {this.$modal.msgSuccess("修改成功");this.open = false;this.getList();});} else {addType(this.form).then(response => {this.$modal.msgSuccess("新增成功");this.open = false;this.getList();});}}});},/** 刪除按鈕操作 */handleDelete(row) {const dictIds = row.dictId || this.ids;this.$modal.confirm('是否確認刪除字典編號為"' + dictIds + '"的數據項?').then(function() {return delType(dictIds);}).then(() => {this.getList();this.$modal.msgSuccess("刪除成功");}).catch(() => {});},/** 導出按鈕操作 */handleExport() {this.download('system/dict/type/export', {...this.queryParams}, `type_${new Date().getTime()}.xlsx`)},/** 刷新緩存按鈕操作 */handleRefreshCache() {refreshCache().then(() => {this.$modal.msgSuccess("刷新成功");});}}
};
</script>

2.在main.js中全局注冊組件:

并且還需要注冊全局事件總線用于組件之間的通信

// 表頭篩選組件
import FilterHeader from '@/components/FilterHeader'
Vue.component('FilterHeader', FilterHeader)
new Vue({router,store,render: h => h(App),beforeCreate(){Vue.prototype.$bus = this	//安裝全局事件總線}
}).$mount('#app')
/*** @param: fileName - 文件名稱* @param: 數據返回 1) 無后綴匹配 - false* @param: 數據返回 2) 匹配圖片 - image* @param: 數據返回 3) 匹配 txt - txt* @param: 數據返回 4) 匹配 excel - excel* @param: 數據返回 5) 匹配 word - word* @param: 數據返回 6) 匹配 pdf - pdf* @param: 數據返回 7) 匹配 ppt - ppt* @param: 數據返回 8) 匹配 視頻 - video* @param: 數據返回 9) 匹配 音頻 - radio* @param: 數據返回 10) 其他匹配項 - other* @author: ljw**/export function fileSuffixTypeUtil(fileName){// 后綴獲取var suffix = "";// 獲取類型結果var result = "";try {var flieArr = fileName.split(".");suffix = flieArr[flieArr.length - 1];} catch (err) {suffix = "";}// fileName無后綴返回 falseif (!suffix) {result = false;return result;}// 圖片格式var imglist = ["png", "jpg", "jpeg", "bmp", "gif"];// 進行圖片匹配result = imglist.some(function (item) {return item == suffix;});if (result) {result = "image";return result;}// 匹配txtvar txtlist = ["txt"];result = txtlist.some(function (item) {return item == suffix;});if (result) {result = "txt";return result;}// 匹配 excelvar excelist = ["xls", "xlsx"];result = excelist.some(function (item) {return item == suffix;});if (result) {result = "excel";return result;}// 匹配 wordvar wordlist = ["doc", "docx"];result = wordlist.some(function (item) {return item == suffix;});if (result) {result = "word";return result;}// 匹配 pdfvar pdflist = ["pdf"];result = pdflist.some(function (item) {return item == suffix;});if (result) {result = "pdf";return result;}// 匹配 pptvar pptlist = ["ppt"];result = pptlist.some(function (item) {return item == suffix;});if (result) {result = "ppt";return result;}// 匹配 視頻var videolist = ["mp4", "m2v", "mkv","ogg", "flv", "avi", "wmv", "rmvb"];result = videolist.some(function (item) {return item == suffix;});if (result) {result = "video";return result;}// 匹配 音頻var radiolist = ["mp3", "wav", "wmv"];result = radiolist.some(function (item) {return item == suffix;});if (result) {result = "radio";return result;}// 其他 文件類型result = "other";return result;
};

三、后端實現

1.表頭篩選數據庫結構

CREATE TABLE `sys_header_filter` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主鍵',`user_name` varchar(32) DEFAULT NULL COMMENT '用戶名',`page_name` varchar(32) DEFAULT NULL COMMENT '當前頁面的路由名',`table_name` varchar(32) DEFAULT NULL COMMENT '字段所屬表',`field_name` varchar(32) DEFAULT NULL COMMENT '屬性名稱',`condition_type` varchar(16) DEFAULT NULL COMMENT '條件',`text` varchar(64) DEFAULT NULL COMMENT '文本值',`start_value` varchar(64) DEFAULT '\0' COMMENT '開始值',`del_flag` varbinary(16) DEFAULT '0' COMMENT '邏輯刪除',`end_value` varchar(64) DEFAULT NULL COMMENT '結束值',`type` varchar(16) DEFAULT NULL COMMENT '類型',`order_type` varchar(16) DEFAULT NULL COMMENT '排序條件',`checkbox` varchar(64) DEFAULT NULL COMMENT '多選框值',`create_by` varchar(32) DEFAULT NULL COMMENT '創建人',`update_by` varchar(32) DEFAULT NULL COMMENT '最后更新人',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新時間',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=295 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='用戶默認表頭篩選表'

2.后端主要代碼:Mybatis自定義實現sql攔截器

package com.wusuowei.common.utils.mybatis;import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.ast.SQLOrderingSpecification;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.parser.SQLExprParser;
import com.alibaba.druid.sql.parser.SQLParserUtils;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.util.JdbcUtils;
import com.alibaba.fastjson2.JSON;
import com.wusuowei.common.utils.ServletUtils;
import com.wusuowei.common.utils.StringUtils;
import com.wusuowei.common.web.domain.BaseEntity;
import com.wusuowei.common.web.page.ConditionDomain;
import com.wusuowei.common.web.page.TableSupport;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Iterator;
import java.util.List;/*** Mybagis攔截器,攔截分頁查詢帶篩選條件的請求,該攔截器在分頁攔截器之后執行** @author liguangyao* @date 2023/9/5*/
@Component
//攔截StatementHandler類中參數類型為Statement的prepare方法(prepare=在預編譯SQL前加入修改的邏輯)
//即攔截 Statement prepare(Connection var1, Integer var2) 方法
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class HeadFilterInterceptor implements Interceptor {private static final Logger log = LoggerFactory.getLogger(HeadFilterInterceptor.class);/*** 獲取分頁請求表頭篩選的條件** @param request* @return*/private BaseEntity getParamsPlusFromRequest(HttpServletRequest request) {if (HttpMethod.GET.name().equals(request.getMethod()) && ObjectUtil.isNotNull(request.getParameter(TableSupport.PARAMS_PLUS))) {BaseEntity baseEntity = new BaseEntity();baseEntity.setParamsPlus(request.getParameter(TableSupport.PARAMS_PLUS));baseEntity.setDatabaseTable(request.getParameter(TableSupport.DATABASE_TABLE));baseEntity.setPageNum(request.getParameter(TableSupport.PAGE_NUM));baseEntity.setPageSize(request.getParameter(TableSupport.PAGE_SIZE));return baseEntity;} else if (HttpMethod.POST.name().equals(request.getMethod())) {BaseEntity baseEntity = new BaseEntity();StringBuilder sb = new StringBuilder();try (BufferedReader reader = request.getReader();) {char[] buff = new char[1024];int len;while ((len = reader.read(buff)) != -1) {sb.append(buff, 0, len);}if (StrUtil.isBlank(sb)) {return null;}// 判斷是否是分頁請求if (!sb.toString().contains(TableSupport.PAGE_NUM) || !sb.toString().contains(TableSupport.PAGE_SIZE) || !sb.toString().contains(TableSupport.PARAMS_PLUS)) {return null;}baseEntity = JSON.parseObject(sb.toString(), BaseEntity.class);if (StringUtils.isBlank(baseEntity.getPageNum()) || StringUtils.isBlank(baseEntity.getPageSize())) {return null;}} catch (Exception e) {log.error("表頭篩選參數JSON轉換異常:{}", e);}// 判斷是否存在sql注入if (ObjectUtil.isNull(baseEntity) || MySqlUtil.sqlInjectionVerification(baseEntity.getParamsPlus()) || StringUtils.isBlank(baseEntity.getParamsPlus())) {return null;}// 將json格式的篩選條件字符串轉換成集合return baseEntity;}return null;}@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 判斷是否是前臺的請求if (ObjectUtil.isEmpty(ServletUtils.getRequestAttributes())) {return invocation.proceed();}HttpServletRequest request = ServletUtils.getRequest();// 獲取表頭篩選條件BaseEntity baseEntity = this.getParamsPlusFromRequest(request);if (ObjectUtil.isNull(baseEntity)) {return invocation.proceed();}List<ConditionDomain> paramsPlus = JSON.parseArray(baseEntity.getParamsPlus(), ConditionDomain.class);StatementHandler statementHandler = (StatementHandler) invocation.getTarget();BoundSql boundSql = statementHandler.getBoundSql();// 獲取到原始sql語句String sql = boundSql.getSql();// 如果獲取不到該sql中的數據庫名,執行原語句String tableName = MySqlUtil.getTableName(sql, baseEntity.getDatabaseTable());if (StringUtils.isBlank(tableName)) {return invocation.proceed();}// 根據條件拼接sqlString mSql = resetSQL(tableName, sql, paramsPlus);// 如果拼接的sql不正確直接執行原sqlif (!MySqlUtil.isSqlValid(mSql)) {return invocation.proceed();}// 通過反射修改sql語句Field field = boundSql.getClass().getDeclaredField("sql");field.setAccessible(true);field.set(boundSql, mSql);log.debug("原來的SQL====>" + sql);log.debug("拼接后的SQL====>" + mSql);return invocation.proceed();}/*** 獲取拼接后的完整sql** @param tableName* @param sql* @param paramsPlus* @return*/private String resetSQL(String tableName, String sql, List<ConditionDomain> paramsPlus) {// 獲取表的別名String tableAliases = tableName + ".";SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, JdbcUtils.MYSQL);List<SQLStatement> stmtList = parser.parseStatementList();SQLStatement stmt = stmtList.get(0);if (stmt instanceof SQLSelectStatement) {// 根據參數拼接的where條件sqlString whereStr = splicingWhereSQL(tableAliases, sql, paramsPlus);// 拿到SQLSelectSQLSelectStatement selectStmt = (SQLSelectStatement) stmt;SQLSelect sqlselect = selectStmt.getSelect();SQLSelectQueryBlock query = (SQLSelectQueryBlock) sqlselect.getQuery();if (ObjectUtil.isNotEmpty(whereStr)) {SQLExprParser constraintsParser = SQLParserUtils.createExprParser(whereStr, JdbcUtils.MYSQL);SQLExpr constraintsExpr = constraintsParser.expr();SQLExpr whereExpr = query.getWhere();// 修改where表達式if (whereExpr == null) {query.setWhere(constraintsExpr);} else {SQLBinaryOpExpr newWhereExpr = new SQLBinaryOpExpr(whereExpr, SQLBinaryOperator.BooleanAnd, constraintsExpr);query.setWhere(newWhereExpr);}}// 創建新的排序項for (ConditionDomain item : paramsPlus) {SQLIdentifierExpr newOrderByExpr = new SQLIdentifierExpr(tableAliases + StringUtils.toUnderScoreCase(item.getFieldName()));SQLSelectOrderByItem newOrderByItem = null;// 判斷字段升序降序boolean isAsc = SQLOrderingSpecification.ASC.toString().equalsIgnoreCase(item.getOrderType());if (isAsc) {newOrderByItem = new SQLSelectOrderByItem(newOrderByExpr, SQLOrderingSpecification.ASC);} else {newOrderByItem = new SQLSelectOrderByItem(newOrderByExpr, SQLOrderingSpecification.DESC);}// 將新的排序項添加到已有的排序項后面SQLOrderBy orderBy = query.getOrderBy();// 判斷原sql是否有排序規則if (orderBy == null) {SQLOrderBy sqlOrderBy = new SQLOrderBy();sqlOrderBy.addItem(newOrderByItem);query.addOrderBy(sqlOrderBy);} else {orderBy.addItem(newOrderByItem);}}return sqlselect.toString();}return sql;}/*** where條件拼接sql (table.name = '李四' AND table.age = 18) 帶括號和表名稱的格式** @param paramsPlus* @param tableAliases* @return*/private String splicingWhereSQL(String tableAliases, String sql, List<ConditionDomain> paramsPlus) {StringBuffer whereBuffer = new StringBuffer();Iterator<ConditionDomain> keyIter = paramsPlus.iterator();// 找到第一個where條件進行拼接while (keyIter.hasNext()) {ConditionDomain conditionDomain = keyIter.next();String codition = ConditionChoseMap.getCodition(conditionDomain);if (ObjectUtil.isNotEmpty(conditionDomain.getTableName())) {whereBuffer.append(MySqlUtil.getTableAlias(conditionDomain.getTableName(), sql)).append(".").append(StringUtils.toUnderScoreCase(conditionDomain.getFieldName())).append(ConditionChoseMap.getCodition(conditionDomain));break;}// 如果查詢if (ObjectUtil.isNotEmpty(codition)) {whereBuffer.append(tableAliases).append(StringUtils.toUnderScoreCase(conditionDomain.getFieldName())).append(ConditionChoseMap.getCodition(conditionDomain));break;}}// 后面的where條件用AND進行拼接while (keyIter.hasNext()) {ConditionDomain conditionDomain = keyIter.next();String codition = ConditionChoseMap.getCodition(conditionDomain);if (ObjectUtil.isNotEmpty(conditionDomain.getTableName())) {whereBuffer.append(MySqlUtil.getTableAlias(conditionDomain.getTableName(), sql)).append(".").append(StringUtils.toUnderScoreCase(conditionDomain.getFieldName())).append(ConditionChoseMap.getCodition(conditionDomain));break;}if (ObjectUtil.isNotEmpty(codition)) {whereBuffer.append(" AND ").append(tableAliases).append(StringUtils.toUnderScoreCase(conditionDomain.getFieldName())).append(ConditionChoseMap.getCodition(conditionDomain));}}return whereBuffer.toString();}
}

四、使用

<template><div><div style="margin: 10px 0"><right-toolbar @handleQuery="handleQuery" @resetFilter="resetFilter" @queryTable="getList"></right-toolbar></div><div style="margin: 10px 0"><el-buttontype="primary"plainicon="el-icon-top"size="mini"@click="showUploadDialog">點擊上傳</el-button><el-popconfirmclass="ml-5"confirm-button-text='確定'cancel-button-text='我再想想'icon="el-icon-info"icon-color="red"title="您確定批量刪除這些數據嗎?"@confirm="delBatch"><el-button style="margin: 0 5px" icon="el-icon-delete" size="mini" type="danger" slot="reference" plain>批量刪除</el-button></el-popconfirm></div><el-table :data="tableData" border stripe v-loading="loading"@selection-change="handleSelectionChange"><el-table-column type="selection" width="55"></el-table-column><el-table-column prop="id" label="ID" width="80"><template slot="header" slot-scope="scope"><filter-header@handleQuery="handleQuery":paramsPlusTemp.sync="paramsPlusTemp":column="scope.column"field-name="type"filter-type="number"></filter-header></template></el-table-column><el-table-column prop="fileName" width="160" label="文件名稱" :show-overflow-tooltip="true"><template slot="header" slot-scope="scope"><filter-header@handleQuery="handleQuery":paramsPlusTemp.sync="paramsPlusTemp":column="scope.column"field-name="type"filter-type="text"></filter-header></template><template slot-scope="scope" v-if="scope.row.fileName"><span @click="copyText(scope.row.fileName)" style="cursor: pointer">{{scope.row.fileName}}</span></template></el-table-column><el-table-column prop="fileType" align="center" label="文件類型"><template slot="header" slot-scope="scope"><filter-header@handleQuery="handleQuery":paramsPlusTemp.sync="paramsPlusTemp":column="scope.column":customArrList="dict.type.sys_file_type"field-name="type"filter-type="checkbox"></filter-header></template><template v-slot="scope"><dict-tag :options="dict.type.sys_file_type" :value="scope.row.fileType"/></template></el-table-column><el-table-column prop="fileSize" label="文件大小(mb)"><template slot="header" slot-scope="scope"><filter-header@handleQuery="handleQuery":paramsPlusTemp.sync="paramsPlusTemp":column="scope.column"field-name="type"filter-type="number"></filter-header></template><template slot-scope="scope">{{ scope.row.fileSize | transformByte }}</template></el-table-column><el-table-column prop="nickName" label="上傳用戶" :show-overflow-tooltip="true"><template slot="header" slot-scope="scope"><filter-header@handleQuery="handleQuery":paramsPlusTemp.sync="paramsPlusTemp":column="scope.column"field-name="type"filter-type="text"></filter-header></template></el-table-column><el-table-column prop="createTime" label="上傳時間"><template slot="header" slot-scope="scope"><filter-header@handleQuery="handleQuery":paramsPlusTemp.sync="paramsPlusTemp":column="scope.column"field-name="type"filter-type="date"></filter-header></template></el-table-column><el-table-column prop="enable" width="80" label="啟用"><template slot="header" slot-scope="scope"><filter-header@handleQuery="handleQuery":paramsPlusTemp.sync="paramsPlusTemp":column="scope.column":customArrList="dict.type.sys_file_status"field-name="type"filter-type="checkbox"></filter-header></template><template slot-scope="scope"><el-switch v-model="scope.row.enable" active-color="#13ce66" inactive-color="#ccc"@change="changeEnable(scope.row)"></el-switch></template></el-table-column><el-table-column fixed="right" label="操作" width="200" align="center"><template slot-scope="scope"><el-buttonsize="mini"type="text"@click="lookonline(scope.row.url)"slot="reference"><i class="el-icon-view"></i>預覽</el-button><el-buttonsize="mini"type="text"@click="download(scope.row)"slot="reference"><i class="el-icon-download"></i>下載</el-button><el-popconfirmconfirm-button-text='確定'cancel-button-text='我再想想'icon="el-icon-info"icon-color="red"title="您確定刪除嗎?"@confirm="del(scope.row)"><el-button style="margin: 0 10px" size="mini"type="text"slot="reference"><i class="el-icon-delete"></i>刪除</el-button></el-popconfirm></template></el-table-column></el-table><div style="padding: 10px 0"><el-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="pagequery.pageNum":page-sizes="[2, 5, 10, 20]":page-size="pagequery.pageSize"layout="total, sizes, prev, pager, next, jumper":total="total"></el-pagination></div><FileUpload :fileTableVisible="fileTableVisible" @uploadFileList="uploadFileList"@changeFileDialogVisible="changeFileDialogVisible"></FileUpload></div>
</template><script>
import FileUpload from "@/components/FileUpload";
import {getFilesPage, delFilesByIds, delFileById, updateFile} from '@/api/system/file'
import axios from "axios";
import * as base64Encode from "js-base64";
import {getDefaultHeaderFilter, uploadDefaultHeaderFilter} from "@/api/system/headerFilter";
import {copyText} from "@/utils";export default {name: "File",components: {FileUpload},dicts: ['sys_file_type','sys_file_status'],data() {return {// 查詢參數queryParams: {pageNum: 1,pageSize: 10,databaseTable: 'sys_file',},// 篩選和排序條件paramsPlusTemp: [],dateRange: '',// 遮罩層loading: true,fileTypes: [{label: '圖片', value: 'image'}, {label: '文本', value: 'txt'}, {label: '視頻',value: 'video'}, {label: '音頻', value: 'radio'}, {label: 'Excel', value: 'excel'}, {label: 'Word',value: 'word'}, {label: 'pdf', value: 'pdf'}, {label: 'PPT', value: 'ppt'}, {label: '其他', value: 'other'}],pagequery: {  //分頁查詢條件pageNum: 1,pageSize: 5,},fileTableVisible: false,uploadHeaders: localStorage.getItem("token"),tableData: [],multipleSelection: [],total: 0,headers: localStorage.getItem('token'),}},created() {getDefaultHeaderFilter().then(res => {if (res.data) {localStorage.setItem("defaultHeader", JSON.stringify(res.data))this.paramsPlusTemp = res.data[this.$route.name]}this.getList();})},methods: {copyText,/** 刷新按鈕操作 */resetQuery() {this.resetForm("queryForm");this.handleQuery();},/** 重置更新所有表頭篩選組件 */resetFilter() {this.$bus.$emit('resetFilter')this.paramsPlusTemp = []this.queryParams.paramsPlus = nulluploadDefaultHeaderFilter(this.$route.name, null).then(res => {localStorage.removeItem('defaultHeader')})this.getList()},getList() {this.loading = true;this.queryParams.paramsPlus = this.paramsPlusTemp && this.paramsPlusTemp.length === 0 ? null : JSON.stringify(this.paramsPlusTemp)getFilesPage(this.queryParams).then((res) => {//console.log("resp:", res);this.total = res.totalthis.tableData = res.rowsthis.loading = false;});},showUploadDialog() {//如果有文件沒有上傳成功就保留這個文件,這樣下次打開彈框還有記錄this.fileTableVisible = true},changeFileDialogVisible(value) {this.fileTableVisible = value},uploadFileList() {this.getList()},changeEnable(row) {updateFile(row).then(res => {if (res.code === 200) {this.$message.success("操作成功")}})},del(file) {delFileById(file).then(res => {if (res.code === 200) {this.$message.success("刪除成功")this.getList()}})},handleSelectionChange(val) {this.multipleSelection = val},delBatch() {if (this.multipleSelection.length === 0) {this.$message.warning("請選擇刪除的文件")return}delFilesByIds(this.multipleSelection).then(res => {if (res.code === 200) {this.$message.success("批量刪除成功")this.getList()}})},reset() {this.dateRange = ''this.pagequery = {pageNum: 1,pageSize: 5,}this.getList()},handleSizeChange(pageSize) {this.pagequery.pageSize = pageSizethis.getList()},handleCurrentChange(pageNum) {this.pagequery.pageNum = pageNumthis.getList()},// 下載文件download(row) {axios.get(row.url,{responseType: 'blob'}).then((res) => {console.log('文件下載成功');const blob = new Blob([res.data]);const fileName = row.fileName;//對于<a>標簽,只有 Firefox 和 Chrome(內核) 支持 download 屬性//IE10以上支持blob,但是依然不支持downloadif ('download' in document.createElement('a')) {//支持a標簽download的瀏覽器const link = document.createElement('a');//創建a標簽link.download = fileName;//a標簽添加屬性link.style.display = 'none';link.href = URL.createObjectURL(blob);document.body.appendChild(link);link.click();//執行下載URL.revokeObjectURL(link.href); //釋放urldocument.body.removeChild(link);//釋放標簽} else {navigator.msSaveBlob(blob, fileName);}}).catch((res) => {console.log('文件下載失敗');});},lookonline(url) {console.log(url)window.open('http://127.0.0.1:8012/onlinePreview?url=' + encodeURIComponent(base64Encode.encode(url)));},/** 搜索按鈕操作 */handleQuery() {this.queryParams.pageNum = 1;this.getList();uploadDefaultHeaderFilter(this.$route.name, this.queryParams.paramsPlus).then(res => {if (res.data) {localStorage.setItem('defaultHeader', JSON.stringify(res.data))this.paramsPlusTemp = res.data[this.$route.name]}})this.getList();},//獲取時間區間方法dateFormat(picker) {this.pagequery.startTime = picker[0]this.pagequery.endTime = picker[1]},},filters: {transformByte(size) {if (!size) {return '0B'}const unitSize = 1024// if (size < unitSize) {//   return size + ' B'// }// // KB// if (size < Math.pow(unitSize, 2)) {//   return (size / unitSize).toFixed(2) + ' K';// }// MB// if (size < Math.pow(unitSize, 3)) {return (size / Math.pow(unitSize, 2)).toFixed(2) + ' MB'// }// // GB// if (size < Math.pow(unitSize, 4)) {//   return (size / Math.pow(unitSize, 3)).toFixed(2) + ' GB';// }// // TB// return (size / Math.pow(unitSize, 4)).toFixed(2) + ' TB';},transformType(filename) {return filename.substr(filename.lastIndexOf('.') + 1)}}
}
</script><style scoped></style>

五、注意點

本片文章的大概交互流程是,前端當前頁面的表頭篩選組件(子組件),將數據傳遞到當前組件中(當前頁面父組件),并且請求了后端,持久化了表頭篩選數據,發送列表請求。后臺根據參數修改原sql。然后下次再查詢當前頁面或刷新時,回先從redis緩存中獲取全部的表頭篩選數據,獲取成功后放入瀏覽器緩存,進而每個頁面就能獲取到對應的表頭篩選數據進行數據渲染。

小結

文章貼的代碼有點多了,大家可以去我的gitee上下載下來運行。項目的功能我測試優化了很多次,如果代碼有何異常或者不完整歡迎在評論區留言。如果這篇文章有幸幫助到你,希望讀者大大們可以給作者點個贊呀😶?🌫?😶?🌫?😶?🌫?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/718656.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/718656.shtml
英文地址,請注明出處:http://en.pswp.cn/news/718656.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Grpc項目集成到java方式調用實踐

背景&#xff1a;由于項目要對接到grcp 的框架&#xff0c;然后需要對接老外的東西&#xff0c;還有簽名和證書剛開始沒有接觸其實有點懵逼。 gRPC 是由 Google 開發的高性能、開源的遠程過程調用&#xff08;RPC&#xff09;框架。它建立在 HTTP/2 協議之上&#xff0c;使用 …

D7805 正電壓穩壓電路應用——體積小,成本低,性能好

D7805 構成的 5V 穩壓電源為輸出電壓5V&#xff0c;輸出電流 1000mA 的穩壓電源它由濾波電容 C1,C3,防止自激電容 C2、C3 和一只固定三端穩壓器&#xff08;7805&#xff09;后級加 LC 濾波極為簡潔方便地搭成&#xff0c;輸入直流電壓范圍為 7~35V&#xff0c;此直流電壓經過D…

yolov8-更換卷積模塊-ContextGuidedBlock_Down

源碼解讀 class ContextGuidedBlock_Down(nn.Module):"""the size of feature map divided 2, (H,W,C)---->(H/2, W/2, 2C)"""def __init__(self, nIn, dilation_rate2, reduction16):"""args:nIn: the channel of input fea…

Hack The Box-Bizness

目錄 信息收集 nmap dirsearch WEB Get shell 提權 get user flag get root flag 信息收集 nmap 端口掃描┌──(root?ru)-[~/kali/hackthebox] └─# nmap -p- 10.10.11.252 --min-rate 10000 -oA port Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-03-04 1…

實測VLLM的加速效果

為了測試vllm的并行加速效果&#xff0c;采用同樣的5個提問&#xff0c;編寫兩個不同的python腳本&#xff0c;分別是compare_vllm.py和compare_chatglm3.py&#xff0c;其中compare_vllm.py采用vllm加速。 服務器參數&#xff1a; 操作系統ubuntu 22.04CPUi7 14700k內存dd5 …

hive中常見參數優化總結

1.with as 的cte優化&#xff0c;一般開發中習慣使用with as方便閱讀&#xff0c;但如果子查詢結果在下游被多次引用&#xff0c;可以使用一定的參數優化手段減少表掃描次數 默認set hive.optimize.cte.materialize.threshold-1;不自動物化到內存&#xff0c;一般可以設置為 se…

力扣 第 387 場周賽 解題報告 | 珂學家 | 離散化樹狀數組 + 模擬場

前言 整體評價 手速場模擬場&#xff0c;思路和解法都蠻直接的。 所以搞點活 如果T2&#xff0c;如果不固定左上角&#xff0c;批量查詢某個點為左上角&#xff0c;求滿足總和 ≤ k \le k ≤k的子矩陣個數 如果T2&#xff0c;如果不固定左上角&#xff0c;求總和 ≤ k \le k…

Spring的Bean的生命周期 | 有圖有案例

Spring的Bean的生命周期 Spring的Bean的生命周期整體過程實例化初始化服務銷毀循環依賴問題 完整生命周期演示 Spring的Bean的生命周期 Spring Bean的生命周期&#xff1a;從Bean的實例化之后&#xff0c;通過反射創建出對象之后&#xff0c;到Bean稱為一個完整的對象&#xf…

EXPLAIN:mysql 執行計劃分析詳解

目錄 EXPLAIN命令 查看執行計劃 分析執行計劃 優化查詢 EXPLAIN中的 type 列類型 在MySQL中&#xff0c;你可以使用EXPLAIN命令來生成查詢的執行計劃。EXPLAIN命令可以顯示MySQL如何使用鍵來處理SELECT和DELETE語句&#xff0c;以及INSERT或UPDATE語句的WHERE子句。這對于…

SRS Stack提供的鑒權、私人直播間、多平臺轉播、錄制等高級功能的具體使用方法是什么?

SRS Stack提供的鑒權、私人直播間、多平臺轉播、錄制等高級功能的具體使用方法是什么&#xff1f; 鑒權功能&#xff1a;SRS Stack支持通過系統配置中的OpenAPI獲取Bearer鑒權&#xff0c;并可以嘗試HTTP API。用戶可以通過點擊網頁上的按鈕請求HTTP API&#xff0c;或者使用cu…

快上車:什么是人工智能?人工智能和普通程序的區別

什么是人工智能&#xff1f; 雖然AI歷史很悠久&#xff0c;上個世紀50年代就有各種概念&#xff0c;但是發展很慢。第一次對人類的沖擊就是1997年IBM深藍擊敗國際象棋世界冠軍&#xff0c;引起了人們的廣泛關注&#xff0c;之后又銷聲匿跡。突然間2016人工智能alphaGO戰勝了圍…

具身智能計算系統,機器人時代的 Android | 新程序員

【導讀】具身智能作為一種新興的研究視角和方法論&#xff0c;正在刷新我們對智能本質及其發展的理解&#xff1a;傳統的 AI 模型往往將智能視為一種獨立于實體存在的抽象能力&#xff0c;而具身智能則主張智能是實體與其環境持續互動的結果。 本文深度剖析了具身智能計算系統…

【CSS】初學了解Grid布局

目錄 什么是Grid布局如何開始使用Grid布局Grid容器的屬性Grid項目的屬性舉個例子 什么是Grid布局 Grid布局是一種二維的布局系統&#xff0c;它允許我們在水平和垂直方向上同時控制網格中的項目位置。通過將頁面劃分為行和列&#xff0c;我們可以輕松地創建出復雜的布局結構&a…

程序員如何選擇職業賽道?

一、自我評估與興趣探索 程序員選擇職業賽道時&#xff0c;可以考慮以下幾個關鍵因素&#xff1a; 1、興趣與熱情&#xff1a;首先要考慮自己的興趣和熱情&#xff0c;選擇符合個人喜好和激情的領域&#xff0c;能夠激勵自己持續學習和進步。 2、技術能力&am…

2.python72變筆記(自用未修改版)

以前寫的python筆記 1.二進制與字符編碼 #8bit&#xff08;位&#xff09;1byte&#xff08;字節&#xff09; #1024byte 1KB 千字節 #1024KB 1MB 兆字節 #1024MB 1TB 太字節 print(chr(0b100111001010000)) print(ord("陳")) #ord 十進制 #無論英語還是漢語在計算…

mysql5.7配置主從

原理&#xff1a; MySQL主從復制的工作原理如下:1. 主服務器產生Binlog日志當主服務器的數據庫發生數據修改操作時,如INSERT、UPDATE、DELETE語句執行,主服務器會記錄這些操作的日志信息到二進制日志文件中。2. 從服務器讀取Binlog日志 從服務器會向主服務器發送請求,主服務器把…

微信小程序開發學習筆記《18》uni-app框架-網絡請求與輪播圖

微信小程序開發學習筆記《18》uni-app框架-網絡請求 博主正在學習微信小程序開發&#xff0c;希望記錄自己學習過程同時與廣大網友共同學習討論。建議仔細閱讀uni-app對應官方文檔 一、下載網絡請求包 這個包是以前黑馬程序員老師寫的一個包&#xff0c;跟著課程學習&#x…

Open3D(C++) 指定點數的體素濾波

目錄 一、算法原理1、算法過程2、參考文獻二、代碼實現三、結果展示本文由CSDN點云俠原創,原文鏈接。如果你不是在點云俠的博客中看到該文章,那么此處便是不要臉的爬蟲與GPT。 一、算法原理 1、算法過程 對于數據量較大的點云,在后期進行配準時會影響計算效率。而體素格網…

vue3ts websocket通信

前端&#xff1a;vue3ts 后端&#xff1a;springboot npm安裝依賴 cnpm install sockjs-client stompjs 前端代碼 <template><div><el-input v-model"message" type"text" placeholder"發送" /><el-button-group><…

LCR 170. 交易逆序對的總數

解題思路&#xff1a; 歸并排序&#xff0c;在歸并的過程中不斷計算逆序對的個數 count mid -i 1&#xff1b;的來源見下圖&#xff0c;因為兩個數組都是單調遞增的&#xff0c;所以如果第一個數組的前一個元素大于第二個數組的對應元素&#xff0c;那么第一個數組的這一元素…