Vue3 实现页面简单的CRUD

请求拦截器

bash 复制代码
import axios from 'axios';
import { ElNotification, ElMessageBox, ElMessage, ElLoading } from 'element-plus';
import { saveAs } from 'file-saver';
import store from '@/store';
import { getToken } from '@/utils/token';
import errorCode from '@/utils/errorCode';
import { isBlobData } from '@/utils/common';
import { encodeURIParams } from '@/utils/strUtil';
import cache from '@/plugins/cache';

let downloadLoadingInstance;
// 是否显示重新登录
export const isReLogin = { show: false };

axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';
// 创建axios实例
const service = axios.create({
    // axios中请求配置有baseURL选项,表示请求URL公共部分
    baseURL: import.meta.env.VITE_APP_BASE_API,
    // 超时
    timeout: 30000,
});

// request拦截器
service.interceptors.request.use(
    (config) => {
        // 是否需要设置 token
        const isToken = (config.headers || {}).isToken === false;
        // 是否需要防止数据重复提交
        const isRepeatSubmit = (config.headers || {}).repeatSubmit === false;
        if (getToken() && !isToken) {
            config.headers.AuthToken = `Bearer ${getToken()}`; // 让每个请求携带自定义token 请根据实际情况自行修改
        }
        // get请求映射params参数
        if (config.method === 'get' && config.params) {
            let url = `${config.url}?${encodeURIParams(config.params)}`;
            url = url.slice(0, -1);
            config.params = {};
            config.url = url;
        }
        if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
            const requestObj = {
                url: config.url,
                data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
                time: new Date().getTime(),
            };
            const sessionObj = cache.session.getJSON('sessionObj');
            if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
                cache.session.setJSON('sessionObj', requestObj);
            } else {
                const s_url = sessionObj.url; // 请求地址
                const s_data = sessionObj.data; // 请求数据
                const s_time = sessionObj.time; // 请求时间
                const interval = 10; // 间隔时间(ms),小于此时间视为重复提交
                if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
                    const message = 'The request is in processing, please do not repeat the same request.';
                    console.warn(`[${s_url}]: ${message}`);
                    return Promise.reject(new Error(message));
                }
                cache.session.setJSON('sessionObj', requestObj);
            }
        }
        return config;
    },
    (error) => {
        console.log(error);
        Promise.reject(error);
    },
);

// 响应拦截器
service.interceptors.response.use(
    (res) => {
        // 二进制数据则直接返回
        if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
            return res.data;
        } else {
            if (res.data.state === 'S') {
                return Promise.resolve(res.data.payload);
            } else {
               //{"state":"F","errorCode":5001,"error":"User is not exists!"}
                // 未设置状态码则默认成功状态
                const code = res.data.errorCode;
                // 获取错误信息
                const msg = res.data.error;
                if (code == 4004 || code == 4005 || code == 4006 || code == 4007) {
                    if (!isReLogin.show) {
                        isReLogin.show = true;
                        ElMessageBox.confirm('Login state has been expired, Please re-login!', 'System Info', {
                            confirmButtonText: 'Re-Login',
                            cancelButtonText: 'Cancel',
                            type: 'warning',
                        })
                            .then(() => {
                                isReLogin.show = false;
                                store.dispatch('LogOut').then(() => {
                                    location.href = import.meta.env.BASE_URL;
                                });
                            })
                            .catch(() => {
                                isReLogin.show = false;
                            });
                    }
                    return Promise.reject('Please re-login!');
                } else {
                    ElNotification.error({
                        title: msg,
                    });
                    return Promise.reject('error');
                }
            }
        }
        return Promise.resolve(res.data.payload);
    },
    (error) => {
        console.log(`err${error}`);
        let { message } = error;
        ElMessage({
            message,
            type: 'error',
            duration: 5 * 1000,
        });
        return Promise.reject(error);
    },
);

// 通用下载方法
export function download(url, params, filename) {
    downloadLoadingInstance = ElLoading.service({ text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)' });
    return service
        .post(url, params, {
            transformRequest: [(params) => encodeURIParams(params)],
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            responseType: 'blob',
        })
        .then(async (data) => {
            const isLogin = await isBlobData(data);
            if (isLogin) {
                const blob = new Blob([data]);
                saveAs(blob, filename);
            } else {
                const resText = await data.text();
                const rspObj = JSON.parse(resText);
                const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode.default;
                ElMessage.error(errMsg);
            }
            downloadLoadingInstance.close();
        })
        .catch((r) => {
            console.error(r);
            ElMessage.error('下载文件出现错误,请联系管理员!');
            downloadLoadingInstance.close();
        });
}

export default service;

api

bash 复制代码
import request from '@/utils/request';

export function addAccountSettingsSubscribeType(data) {
    return request({
        url: '/dic/common/accountSettingsSubscribeType',
        method: 'post',
        data
    });
}
export function removeAccountSettingsSubscribeType(data) {
    return request({
        url: `/dic/common/accountSettingsSubscribeType/` + data,
        method: 'delete',
        data
    });
}
export function updateAccountSettingsSubscribeType(data) {
    return request({
        url: `/dic/common/accountSettingsSubscribeType/` + data.id,
        method: 'put',
        data,
    });
}
export function getAccountSettingsSubscribeType(data) {
    return request({
        url: `/dic/common/accountSettingsSubscribeType/` + data,
        method: 'get'
    });
}
export function getAccountSettingsSubscribeTypeList(data) {
    return request({
        url: '/dic/common/accountSettingsSubscribeType/findPage' + data,
        method: 'get',
        data
    });
}

功能管理

bash 复制代码
<template>
  <div>
    <div class="card-wrap" style="padding: 0 12px;">
      <el-form :model="queryParams" ref="queryRef" :inline="true" class="form-search-wrap">
        <el-form-item label="编码">
          <el-input v-model="queryParams.code" clearable style="width: 240px" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="Search" @click="getList()">搜索</el-button>
          <el-button icon="Refresh" @click="resetSearchForm">重置</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="card-wrap" style="padding-bottom: 100px;">
      <div class="operation-wrap">
        <el-button type="primary" @click="handleEdit(null, 1)">添加</el-button>
        <el-button type="danger">删除</el-button>
      </div>
      <el-table :data="tableData"
                v-loading="loading">
        <el-table-column prop="code" label="编码"></el-table-column>
        <el-table-column prop="value" label="值"></el-table-column>
        <el-table-column prop="i18n" label="国际化"></el-table-column>
        <el-table-column label="操作" align="center">
          <template #default="scope">
            <el-button type="primary" icon="Edit" @click="handleEdit(scope.row, 0)" circle />
            <el-button type="danger" icon="Delete" @click="remove(scope.row.id, 0)" circle />
          </template>
        </el-table-column>
      </el-table>
      <div class="pagination">
        <el-pagination
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
            :current-page="queryParams.page"
            :page-sizes="[10, 20, 50, 100]"
            :page-size="queryParams.size"
            layout="total, sizes, prev, pager, next, jumper"
            :total="queryParams.total">
        </el-pagination>
      </div>
    </div>
    <el-dialog :title="type?'添加':'修改'" v-model="dialogVisible" width="30%"  destroy-on-close @close='resetForm'>
      <el-form ref="addForm" :rules="rules" :model="addFormField" label-width="100px">
        <el-form-item label="编码" prop="code">
          <el-input v-model="addFormField.code" style="width:220px" ></el-input>
        </el-form-item>
        <el-form-item label="值" prop="value">
          <el-input v-model="addFormField.value" style="width:220px" ></el-input>
        </el-form-item>
        <el-form-item label="国际化" prop="i18n">
          <el-input v-model="addFormField.i18n" style="width:220px" ></el-input>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogVisible = false">取 消</el-button>
          <el-button type="primary" @click="add">确 定</el-button>
        </span>
      </template>
    </el-dialog>
    <el-dialog
        v-model="dialogVisible"
        title="Tips"
        width="30%"
        :before-close="remove"
    >
      <span>This is a message</span>
      <template #footer>
      <span class="dialog-footer">
        <el-button @click="dialogVisible = false">Cancel</el-button>
        <el-button type="primary" @click="dialogVisible = false">
          Confirm
        </el-button>
      </span>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import { reactive, toRefs, onMounted, ref } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import * as api from '@/api/dic/accountSettingsSubscribeType';
export default {
  name: "AccountSettingsSubscribeType",
  setup() {
    //vue3.x获取ref
    const addForm = ref();
    const dialogVisible = ref(false)
    //定义字段
    const state = reactive({
      dialogVisible: false,
      num: 1,
      loading: false,
      type: "添加",
      tableData: [],
      addFormField: {
        id: "",
        code: "",
        value: "",
        i18n: "",
      },
      queryParams: {
        code: undefined,
        page: 1,
        size: 10,
        total: 0,
      },
      rules: {
        code: [
          { required: "true", message: "code不能为空", trigger: ["change"] },
        ],
        value: [
          { required: "true", message: "value不能为空", trigger: ["change"] },
        ],
        i18n: [
          { required: "true", message: "i18n不能为空", trigger: ["change"] },
        ],
      },
    });
    const handleEdit = (row, type) => {
      if(row){
        state.addFormField = JSON.parse(JSON.stringify(row));
      }
      if (type) {
        state.type = true;
      } else{
        state.type = false;
      }
      state.dialogVisible = true;
    };
    const resetForm = () => {
      state.addFormField = {
        id: undefined,
        code: undefined,
        value: undefined,
        i18n: undefined,
      }
    };
    const resetSearchForm = () => {
      state.queryParams.code = undefined;
    };
    const remove = (id) => {
      ElMessageBox.confirm('Are you sure to remove this data?')
          .then(() => {
            api
                .removeAccountSettingsSubscribeType(id)
                .then((res) => {
                })
                .finally(() => {
                  state.loading = false;
                });
            ElMessage.success("删除成功");
            setTimeout(() => {
              getList();
            }, 300);
          })
          .catch(() => {
            // catch error
          })
    };
    const add = () => {
      addForm.value.validate((valid) => {
        if (valid) {
          let id = state.addFormField.id;
          if (id) {
            api
                .updateAccountSettingsSubscribeType(state.addFormField)
                .then((res) => {
                })
                .finally(() => {
                  state.loading = false;
                });
            ElMessage.success("修改成功");
          }else{
            api
                .addAccountSettingsSubscribeType(state.addFormField)
                .then((res) => {
                })
                .finally(() => {
                  state.loading = false;
                });
            ElMessage.success("添加成功");
          }
          resetForm();
          state.dialogVisible = false;
          setTimeout(() => {
            getList();
          }, 200);
        } else {
          return false;
        }
      });
    };
    const getList = () => {
      state.loading = true;
      let data = {};
      if(state.queryParams){
        data = JSON.stringify(state.queryParams).replace(/:/g, '=').replace(/,/g, '&').replace(/{/g, '?').replace(/}/g, '').replace(/"/g, '');
      }
      api
          .getAccountSettingsSubscribeTypeList(data)
          .then((res) => {
            state.tableData = res.items;
            state.queryParams.page = res.page;
            state.queryParams.size = res.size;
            state.queryParams.total = res.total;
          })
          .finally(() => {
            state.loading = false;
          });
    };
    const handleSizeChange = (val) => {
      state.queryParams.size = val;
      getList();
    };
    const handleCurrentChange = (val) => {
      state.queryParams.page = val;
      getList();
    };
    onMounted(() => {
      getList();
    });
    return {
      add,
      addForm,
      handleEdit,
      getList,
      remove,
      resetForm,
      handleSizeChange,
      handleCurrentChange,
      resetSearchForm,
      ...toRefs(state),
    };
  },
};
</script>
<style scoped >
.pagination {
  background: #fff;
  padding: 10px;
  display: flex;
  justify-content: flex-end;
  box-sizing: border-box;
}
.card-wrap{
  padding: 15px 20px 20px 20px;
  border-radius: 4px;
  border: 1px solid #e6ebf5;
  background-color: #fff;
  overflow: hidden;
  color: #303133;
  -webkit-transition: .3s;
  transition: .3s;
  box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
  margin: 10px;
}
.operation-wrap{
  margin: 0 0 16px 0;
}
.form-search-wrap{
  margin: 10px 0 0 12px;
}
</style>

今天水一篇,祝各位大佬 1024程序员节快乐~

相关推荐
学习ing小白9 小时前
JavaWeb - 5 - 前端工程化
前端·elementui·vue
一只小阿乐9 小时前
前端web端项目运行的时候没有ip访问地址
vue.js·vue·vue3·web端
hello_fracong12 小时前
3.Vue2结合element-ui实现国际化多语言i18n
vue
码力码力我爱你17 小时前
QT + WebAssembly + Vue环境搭建
vue.js·vue·wasm·webassembly·emscripten
尸僵打怪兽1 天前
后台数据管理系统 - 项目架构设计-Vue3+axios+Element-plus(0916)
vue.js·vue
是梦终空1 天前
JAVA毕业设计176—基于Java+Springboot+vue3的交通旅游订票管理系统(源代码+数据库)
java·spring boot·vue·毕业设计·课程设计·源代码·交通订票
天下无贼!2 天前
2024年最新版Vue3学习笔记
前端·vue.js·笔记·学习·vue
这个需求建议不做2 天前
vue3打包配置 vite、router、nginx配置
前端·nginx·vue
QGC二次开发2 天前
Vue3 : Pinia的性质与作用
前端·javascript·vue.js·typescript·前端框架·vue
罗_三金2 天前
前端框架对比和选择?
javascript·前端框架·vue·react·angular