城市灾害应急管理集成系统

系统介绍

城市灾害应急管理集成系统——系统介绍-CSDN博客

构建流程

前端项目构建流程-CSDN博客

  • 需求分析:理解项目需求和业务目标,
  • 技术选型与架构设计:确定技术栈和项目结构。
  • UI/UX 设计:设计用户体验和视觉界面,
  • 开发阶段:基于设计稿实现功能,编写代码并集成 API。
  • 测试阶段:进行功能、性能和兼容性测试,
  • 优化与打包:优化项目性能,打包静态资源。
  • 部署与上线:将项目发布到生产环境。
  • 后续维护与迭代:根据反馈进行改进并推出新功能。

项目说明

【一网打尽】前端Vue和React项目的构建-CSDN博客

Vue CLI、create-vue(Vite) 、create-react-app

  • Vue2版本:技术栈Vue2+Vue Router+Vuex+axios+Element-UI/Ant-design+BPMN +Echarts +Cesium+Three等

https://gitee.com/gisjinger/ubmanage

  • Vue3版本:Vue3+Vue Router+Pinia+axios+Element Plus+BPMN+ Echarts

城市灾害应急管理集成系统 Vue3: 城市灾害应急管理集成系统(Vue3+Node版本)

项目结构

├── build                      // 构建相关  
├── bin                        // 执行脚本
├── public                     // 公共文件
│   ├── favicon.ico            // favicon图标
|   ├── static                 // 静态资源
│   └── index.html             // html模板
│   └── robots.txt             // 反爬虫
├── src                        // 源代码
│   ├── api                    // 所有请求
│   ├── assets                 // 主题 字体等静态资源
│   ├── components             // 全局公用组件
│   ├── directive              // 全局指令
│   ├── layout                 // 布局
│   ├── plugins                // 通用方法
│   ├── router                 // 路由
│   ├── store                  // 全局 store管理
│   ├── utils                  // 全局公用方法
│   ├── views                  // view
│   ├── App.vue                // 入口页面
│   ├── main.js                // 入口 加载组件 初始化等
│   ├── permission.js          // 权限管理
│   └── settings.js            // 系统配置
├── .editorconfig              // 编码格式
├── .env.development           // 开发环境配置
├── .env.production            // 生产环境配置
├── .env.staging               // 测试环境配置
├── .eslintignore              // 忽略语法检查
├── .eslintrc.js               // eslint 配置项
├── .gitignore                 // git 忽略项
├── babel.config.js            // babel.config.js
├── package.json               // package.json
└── vue.config.js              // vue.config.js

配置文件设置 

  • package.json     项目描述信息和依赖库信息
  • vue.config.js      核心配置文件,配置webpack(dev-server代理、loader、plugin、优化等)
  • babel.config.js   转换为浏览器能识别模块
  • .eslintrc.js/.eslintignore                 语法检查
  • .env.development/.env.production 环境变量

协作开发

GIT&SVN:

IDEA项目提交至SVN&GIT仓库_intellij idea svn-CSDN博客

Git绑定Gitee或Github以及Git面试常见题-CSDN博客

从使用者角度解读项目

若依系统前端项目解读——从使用过程解读_若依 登录后 没有保存token-CSDN博客

axios请求封装

封装了拦截器、拦截器、统一的错误处理、统一做了超时处理、baseURL设置

import axios from 'axios'
import { Notification, MessageBox, Message, Loading } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { tansParams, blobValidate } from "@/utils/ruoyi";
import cache from '@/plugins/cache'
import { saveAs } from 'file-saver'
import qs from 'qs'

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

// axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 对应国际化资源文件后缀
axios.defaults.headers['Content-Language'] = 'zh_CN'
// 创建axios实例
const service = axios.create({
  // axios中请求配置有baseURL选项,表示请求URL公共部分
  baseURL: process.env.VUE_APP_BASE_API,
  // // 超时,设置不超时功能,有一定不合理
  // timeout: Number.MAX_SAFE_INTEGER
})

// request拦截器
service.interceptors.request.use(config => {
  // 是否需要设置 token
  const isToken = (config.headers || {}).isToken === false
    //不要随便改代码,会有bug
   // //此处以下为重点
    //1.headers中的content-type 默认的大多数情况是 (application/json),就是json序列化的格式
      config.headers['Content-Type'] ='application/json'
  //2.为了判断是否为formdata格式,增加了一个变量为type,post請求且數據以JSON鍵值對,默认是这个
    //如果type存在,而且是form的话,则代表是UrlSearchParams(application/x-www-form-urlencoded)的格式
        if (config.type && config.type === 'url-form') {
        config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
          //!!!不是所有浏览器都支持UrlSearchParams,可以用qs库编码数据
          if (config.data) {
            config.data = qs.stringify(config.data)
          }
        }

    //3.FormData ('multipart/form-data'), axios会帮忙处理
    //Axios 会将传入数据序列化,因此使用 Axios 提供的 API 可以无需手动处理 FormData


  // 是否需要防止数据重复提交
  const isRepeatSubmit = (config.headers || {}).repeatSubmit === false

  if (getToken() && !isToken) {
    config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
  }
  // get请求映射params参数
  if (config.method === 'get' && config.params) {
    let url = config.url + '?' + tansParams(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 = 1000;                         // 间隔时间(ms),小于此时间视为重复提交
      if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
        const message = '数据正在处理,请勿重复提交';
        console.warn(`[${s_url}]: ` + message)
        return Promise.reject(new Error(message))
      } else {
        cache.session.setJSON('sessionObj', requestObj)
      }
    }
  }
  return config
}, error => {
    console.log(error)
    Promise.reject(error)
})

// 响应拦截器
service.interceptors.response.use(res => {
    // 未设置状态码则默认成功状态
    const code = res.data.code || 200;
    // 获取错误信息
    const msg = errorCode[code] || res.data.msg || errorCode['default']
    // 二进制数据则直接返回
    if (res.request.responseType ===  'blob' || res.request.responseType ===  'arraybuffer') {
      return res.data
    }
    if (code === 401) {
      if (!isRelogin.show) {
        isRelogin.show = true;
        MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
          isRelogin.show = false;
          store.dispatch('LogOut').then(() => {
            location.href = process.env.VUE_APP_CONTEXT_PATH + "index";
          })
      }).catch(() => {
        isRelogin.show = false;
      });
    }
      return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
    }
    // else if (code === 500) {
    //   Message({ message: msg, type: 'error' })//redis错误,待解决
    //   return Promise.reject(new Error(msg))
    // }
    else if (code === 601) {
      Message({ message: msg, type: 'warning' })
      return Promise.reject('error')
    } else if (code !== 200) {
      Notification.error({ title: msg })
      return Promise.reject('error')
    } else {
      return res.data
    }
  },
  error => {
    console.log('err' + error)
    let { message } = error;
    if (message == "Network Error") {
      message = "后端接口连接异常";
    } else if (message.includes("timeout")) {
      message = "系统接口请求超时";
    } else if (message.includes("Request failed with status code")) {
      message = "系统接口" + message.substr(message.length - 3) + "异常";
    }
    Message({ message: message, type: 'error', duration: 5 * 1000 })
    return Promise.reject(error)
  }
)



// 通用下载方法
export function download(url, params, filename, config) {
  downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
  return service.post(url, params, {
    transformRequest: [(params) => { return tansParams(params) }],
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    responseType: 'blob',
    ...config
  }).then(async (data) => {
    const isBlob = blobValidate(data);
    if (isBlob) {
      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']
      Message.error(errMsg);
    }
    downloadLoadingInstance.close();
  }).catch((r) => {
    console.error(r)
    Message.error('下载文件出现错误,请联系管理员!')
    downloadLoadingInstance.close();
  })
}

export default service

[设计模式]发布订阅者模式解耦业务和UI(以Axios拦截器处理响应状态为例)

路由设置

Vue Router进阶详解-CSDN博客

静态路由

// router/index.js  
 
import Vue from 'vue'  
import Router from 'vue-router'  
  
Vue.use(Router)  
  
// 静态路由  
const constantRoutes = [  
  {  
    path: '/login',  
    component: () => import('@/views/login/index'),  
    hidden: true  
  },  
  {  
    path: '/404',  
    component: () => import('@/views/404'),  
    hidden: true  
  }  
]  
  
// 异步路由(示例)  
const asyncRoutes = [  
  {  
    path: '/user',  
    component: () => import('@/views/user/index'),  
    meta: { title: '用户管理', roles: ['admin', 'editor'] }  
  },  
  // 更多路由...  
]  
  
const createRouter = () => new Router({  
  // mode: 'history', // 需要后端支持  
  scrollBehavior: () => ({ y: 0 }),  
  routes: constantRoutes  
})  
  
const router = createRouter()  
  
// 动态添加路由  
function addAsyncRoutes(routes) {  
  routes.forEach(route => {  
    router.addRoute(route)  
  })  
}  
  
export {  
  router,  
  addAsyncRoutes,  
  asyncRoutes  
}

动态路由

前端登录鉴权——以若依Ruoyi前后端分离项目为例解读_若依鉴权-CSDN博客

状态管理

Vuex

VueX详解_组合式vuex-CSDN博客

Pinia

Vue的状态管理——Vuex3&4&Pinia_vue3 状态管理vuex-CSDN博客

Vue3状态管理——Pinia_vue3中pinia-CSDN博客

Redux

Redux与Redux-thunk详解_redux thunk-CSDN博客

Redux详解_redux的使用-CSDN博客

组件化设计

全局/局部注册

// 全局组件挂载
Vue.component('DictTag', DictTag)
Vue.component('Pagination', Pagination)
Vue.component('RightToolbar', RightToolbar)
Vue.component('Editor', Editor)
Vue.component('FileUpload', FileUpload)
Vue.component('ImageUpload', ImageUpload)
Vue.component('ImagePreview', ImagePreview)

组件通信

Vue

React

封装指令

权限指令

Vue自定义指令详解——以若依框架中封装指令为例分析-CSDN博客

防抖

聚焦

字典

对象($tab/$modal/$auth/$cache)

项目基础功能

页面主题(暗/明)

Vue中动态样式绑定+CSS变量实现切换明暗主题功能——从入门到进阶-CSDN博客

语言设置(zh/en)

Vue3+Element Plus项目国际化——中英文切换实战,亲测有效!-CSDN博客

布局设置(导航条)

前端Vue3项目响应式布局实战——基于Flex布局和媒体查询的响应式布局设计-CSDN博客

若依系统前端项目解读——从使用过程解读_若依开发平台的前端详细介绍-CSDN博客

主题颜色、布局、大小等(vuex+cookie、screenfull库),具体待撰写

Ant-Design-Vue快速上手指南+排坑_ant-design-vue css-CSDN博客

项目亮点功能

 登录鉴权功能实现

若依框架登录鉴权详解(动态路由)_若依鉴权-CSDN博客

前端登录鉴权——以若依Ruoyi前后端分离项目为例解读_若依鉴权-CSDN博客

文件上传与下载

Ruoyi若依框架下载流程详细解读(SpringBoot-Vue)-CSDN博客

【前后端】大文件切片上传_filechunkservice-CSDN博客

表单构建器(Form Builder ⭐)

[前端项目Overview]表单构建器vue-form-generator-CSDN博客

工作流设计器BPMN.js(⭐⭐)

BPMNJS设计器开发核心功能分析-CSDN博客

BPMN.JS及其常见API[算得上很全啦]_bpmn-js库中updatemoddleproperties和updateproperties方法-CSDN博客

BPMN.JS中文教程学习_bpmnjs中文文档-CSDN博客

可视化(亮点⭐⭐)

二三维可视化:Echarts图表/Three/Cesium,部分计算机图形学 

性能优化

Vue3知识弥补漏洞——性能优化篇-CSDN博客

首页性能提升

服务端渲染(SSR)

单元测试与集成测试 Jest

其他

代理转发

开发

部署

后端接口撰写

SpringBoot后端

Python Flask

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GISer_Jinger

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值