南川区 网站集约化建设方案,网站建设最快多长时间,大气网站首页,建设网站一般要多少钱数据库设计与前端框架
学习目标#xff1a;
理解多租户的数据库设计方案
熟练使用PowerDesigner构建数据库模型理解前端工程的基本架构和执行流程
完成前端工程企业模块开发
多租户SaaS平台的数据库方案
多租户是什么
多租户技术#xff08;Multi-TenancyTechnology
理解多租户的数据库设计方案
熟练使用PowerDesigner构建数据库模型理解前端工程的基本架构和执行流程
完成前端工程企业模块开发
多租户SaaS平台的数据库方案
多租户是什么
多租户技术Multi-TenancyTechnology又称多重租赁技术是一种软件架构技术是实现如何在多用户环境下
此处的多用户一般是面向企业用户共用相同的系统或程序组件并且可确保各用户间数据的隔离性。简单讲 在一台服务器上运行单个应用实例它为多个租户客户提供服务。从定义中我们可以理解多租户是一种架 构目的是为了让多用户环境下使用同一套程序且保证用户间数据隔离。那么重点就很浅显易懂了多租户的重 点就是同一套程序下实现多用户数据的隔离
需求分析
传统软件模式指将软件产品进行买卖是一种单纯的买卖关系客户通过买断的方式获取软件的使用权软件的 源码属于客户所有因此传统软件是部署到企业内部不同的企业各自部署一套自己的软件系统
Saas模式指服务提供商提供的一种软件服务应用统一部署到服务提供商的服务器上客户可以根据自己的实际 需求按需付费。用户购买基于WEB的软件而不是将软件安装在自己的电脑上用户也无需对软件进行定期的维护 与管理 在SaaS平台里需要使用共用的数据中心以单一系统架构与服务提供多数客户端相同甚至可定制化的服务并且仍可 以保障客户的数据正常使用。由此带来了新的挑战就是如何对应用数据进行设计以支持多租户而这种设计的 思路是要在数据的共享、安全隔离和性能间取得平衡。
多租户的数据库方案分析
目前基于多租户的数据库设计方案通常有如下三种
独立数据库共享数据库、独立 Schema共享数据库、共享数据表
独立数据库
独立数据库每个租户一个数据库。
优点为不同的租户提供独立的数据库有助于简化数据模型的扩展设计满足不同租户的独特需求如果 出现故障恢复数据比较简单。
缺点 增多了数据库的安装数量随之带来维护成本和购置成本的增加
这种方案与传统的一个客户、一套数据、一套部署类似差别只在于软件统一部署在运营商那里。由此可见此方案用户数据隔离级别最高安全性最好但是成本较高
共享数据库、独立 Schema
1 什么是Schema
oracle数据库在oracle中一个数据库可以具有多个用户那么一个用户一般对应一个Schema表都是建立在Schema中的,可以简单的理解在oracle中一个用户一套数据库表 骚戴理解其实oracle的Schema就相当于mysql中的database
mysql数据库mysql数据中的schema比较特殊并不是数据库的下一级而是等同于数据库。比如执行create schema test 和执行create database test效果是一模一样的 共享数据库、独立 Schema即多个或所有的租户使用同一个数据库服务如常见的ORACLE或MYSQL数据库 但是每个租户一个Schema。
优点 为安全性要求较高的租户提供了一定程度的逻辑数据隔离并不是完全隔离每个数据库可支持更多的租户数量。
缺点 如果出现故障数据恢复比较困难因为恢复数据库将牵涉到其他租户的数据 如果需要跨租户统计数据存在一定困难。
这种方案是方案一的变种。只需要安装一份数据库服务通过不同的Schema对不同租户的数据进行隔离。由于数据库服务是共享的所以成本相对低廉。
骚戴理解共享数据库、独立 Schema方案其实就是假如我在服务器上安装了一个mysql服务端然后每一个用户就给他创建一个数据库database这样多个用户就只需要创建多个database数据库即可不需要像独立数据库方案一样每一个用户我就要去搭建一个mysql服务端。共享数据库、共享数据表方案就是我就一个数据库一套数据库表大家都用这个至于怎么区分到底哪条记录是哪个用户的加个用户标识的字段就可以了
共享数据库、共享数据表
共享数据库、共享数据表即租户共享同一个Database同一套数据库表所有租户的数据都存放在一个数据库的同一套表中。在表中增加租户ID等租户标志字段表明该记录是属于哪个租户的。
优点所有租户使用同一套数据库所以成本低廉。
缺点隔离级别最低安全性最低需要在设计开发时加大对安全的开发量数据备份和恢复最困难。
这种方案和基于传统应用的数据库设计并没有任何区别但是由于所有租户使用相同的数据库表所以需要做好对 每个租户数据的隔离安全性处理这就增加了系统设计和数据管理方面的复杂程度。 SAAS-HRM数据库设计
在SAAS-HRM平台中分为了试用版和正式版。处于教学的目的试用版采用共享数据库、共享数据表的方式设 计。正式版采用基于mysql的共享数据库、独立 Schema设计。
数据库设计与建模
数据库设计的三范式
三范式
第一范式1NF确保每一列的原子性做到每列不可拆分
第二范式2NF在第一范式的基础上非主字段必须依赖于主字段一个表只做一件事
第三范式3NF在第二范式的基础上消除传递依赖
反三范式反三范式是基于第三范式所调整的没有冗余的数据库未必是最好的数据库有时为了提高运行效率就必须降低范式标准适当保留冗余数据。
骚戴理解第二范式其实就是假如有一个学生表除了学生基本信息的一些字段如果你还有课程成绩相关的字段在这个表就不符合第二范式把课程成绩相关字段拆出来分作一个成绩表那就符合第二范式。继续上面的例子现在已经分成了学生表和成绩表学生表里有个字段是成绩表的id那么我每次查询学生的所有信息包括成绩我都要去查询学生表然后根据成绩id去成绩表再查一次这样就要查询两次所以就有了反三范式的出现反三范式就是加冗余字段也就是把成绩信息又加到学生表里这样只要查询学生表就可以查询出学生的所有信息当然这是跟第二范式冲突的所以叫“反”三范式。至于这个三范式其实就是假如有个表里面有单价和数量两个字段那么就可以根据单价和数量去计算出总价所以就可以不需要总价这个字段这也叫传递依赖
数据库建模
了解了数据的设计思想那对于数据库表的表设计应该怎么做呢答案是数据库建模
数据库建模在设计数据库时对现实世界进行分析、抽象、并从中找出内在联系进而确定数据库的结构。它主 要包括两部分内容确定最基本的数据结构对约束建模。
建模工具
对于数据模型的建模最有名的要数PowerDesignerPowerDesigner是在中国软件公司中非常有名的其易用性、功能、对流行技术框架的支持、以及它的模型库的管理理念都深受设计师们喜欢。他的优势在于不用在使 用create table等语句创建表结构数据库设计人员只关注如何进行数据建模即可将来的数据库语句可以自动生成
使用pd建模
选择新建数据库模型 打开PowerDesigner文件-建立新模型-model types选择类型-Physical Data Model(物理模型) 控制面板 创建数据库表
点即面板按钮中的创建数据库按钮创建数据库模型 切换columns标签可以对表中的所有字段进行配置
如果基于传统的数据库设计中存在外键则可以使用面版中的Reference配置多个表之间的关联关系效果如下图 导出sql
菜单-数据库database-生成数据库表结构Generate Database
前端框架
脚手架工程
此项目采用目前比较流行的前后端分离的方式进行开发。前端是在传智播客研究院开源的前端框架黑马Admin商用后台模板的基础上进行的开发。
官网上提供了非常基础的脚手架如果我们使用官网的脚手架需要自己写很多代码比如登陆界面、主界面菜单样式 等内容。 课程已经提供了功能完整的脚手架我们可以拿过来在此基础上开发这样可以极大节省我们开发的时间。
技术栈
vue 2.5elementUI 2.2.2 vuexaxiosvue-router vue-i18n
前端环境
node 8.npm 5.
启动与安装
官网上提供了非常基础的脚手架如果我们使用官网的脚手架需要自己写很多代码比如登陆界面、主界面菜单样式 等内容。 课程已经提供了功能完整的脚手架我们可以拿过来在此基础上开发这样可以极大节省我们开发的时间。
解压提供的资源包在命令提示符进入该目录输入命令
cnpm install
通过淘宝镜像下载安装所有的依赖几分钟后下载完成如果没有安装淘宝镜像请使用npm install
关闭语法检查
打开 将useEslint的值改为false。
config/index.js
useEslint: false,
此配置作用: 是否开启语法检查语法检查是通过ESLint 来实现的。我们现在科普一下,什么是ESLint : ESLint 是一个语法规则和代码风格的检查工具可以用来保证写出语法正确、风格统一的代码。如果我们开启了 Eslint , 也就意味着要接受它非常苛刻的语法检查包括空格不能少些或多些必须单引不能双引语句后不可以写分号等等这些规则其实是可以设置的。我们作为前端的初学者最好先关闭这种校验否则会浪费 很多精力在语法的规范性上。如果以后做真正的企业级开发建议开启
输入命令
npm run dev
工程结构
整个前端工程的工程目录结构如下
├── assets | 资源
├── build | webpack编译配置
├── config | 全局变量
├── src | 源码
│ ├── api | 数据请求
│ ├── assets | 资源
│ ├── components | 组件
│ ├── mixins | mixins
│ ├── filters | vue filter
│ ├── icons | 图标
│ ├── lang | 多语言
│ ├── router | 路由
│ ├── store | 数据
│ ├── styles | 样式
│ ├── utils | 工具函数库
│ ├── module-dashboard | 框架程序
│ │ ├── assets
│ │ ├── components
│ │ ├── pages
│ │ ├── router
│ │ └── store
│ ├── module-example | 示例程序
│ │ ├── assets
│ │ ├── components
│ │ ├── pages
│ │ ├── router
│ │ └── store
│ ├── App.vue | app
│ ├── main.js | 主引导
│ └── errorLog.js | vue全局错误捕捉
├── dist | 编译发布目录
├── README.md
├── index.html | 页面模板
├── package.json | npn包配置
├── static
└── test | 测试├── e2e└── unit 执行流程分析 路由和菜单
路由和菜单是组织起一个后台应用的关键骨架。本项目侧边栏和路由是绑定在一起的所以你只有在/router/index.js 下面配置对应的路由侧边栏就能动态的生成了。大大减轻了手动编辑侧边栏的工作量。
当然这样就需要在配置路由的时候遵循很多的约定这里的路由分为两种 constantRouterMap 和 asyncRouterMap 。
constantRouterMap 代通用页面。asyncRouterMap 代表那些业务中通过 addRouters 动态添加的页面。 骚戴理解路由分为两种公共路由和模块路由公共路由就是下面的第二个红框画出来的通常就是登录、注册、404页面这些公共模块的路由定义下面module-saas-clients就是一个模块所有模块通常都是以module开头的那么模块下面的router路由自然就是模块路由 其实每一个模块就是下面的左侧栏例如这个模块对应的就是SAAS企业这个左侧栏 前端数据交互 一个完整的前端 UI 交互到服务端处理流程是这样的
UI 组件交互操作调用统一管理的 api service 请求函数使用封装的 request.js 发送请求获取服务端返回更新 data
从上面的流程可以看出为了方便管理维护统一的请求处理都放在 src/api 文件夹中并且一般按照 model纬度进行拆分文件
api/frame.jsmenus.jsusers.jspermissions.js...
其中 src/utils/request.js 是基于 axios 的封装便于统一处理 POSTGET 等请求参数请求头以及错误提示信息等。具体可以参看 request.js。 它封装了全局 request拦截器 、 respone拦截器 、 统一的错误处理 、 统一做了超时baseURL设置等
骚戴理解这里我一开始不理解为什么明明用的是demo却可以找到module-demo这个模块 上面的这个main.js里面定义了模块的名称所以你的路径里用的是demo也可以找到module-demo这个模块
企业管理
需求分析
在通用页面配置企业管理模块完成企业的基本操作
搭建环境
新增模块
手动创建
方式一在src目录下创建文件夹命名规则module-模块名称
在文件夹下按照指定的结构配置assetscomponentspagesrouterstore等文件
使用命令自动创建
安装命令行工具
npm install -g itheima-cli
执行命令
itheima moduleAdd saas-clients
saas-clients 是新模块的名字
自动创建这些目录和文件
│ ├── module-saas-clients | saas-clients模块主目录
│ │ ├── assets | 资源
│ │ ├── components | 组件
│ │ ├── pages | 页面
│ │ │ └── index.vue | 示例
│ │ ├── router | 路由
│ │ │ └── index.js | 示例
│ │ └── store | 数据
│ │ └── app.js | 示例
每个模块所有的素材、页面、组件、路由、数据都是独立的方便大型项目管理 在实际项目中会有很多子业务项目它们之间的关系是平行的、低耦合、互不依赖。
构造模拟数据
在/src/mock中添加模拟数据company.js
import Mock from mockjs
import { param2Obj } from /utils
const List []
const count 100
for (let i 0; i 3; i) {let data {id: 1i,name: 企业i,managerId: string,version: 试用版v1.0,renewalDate: 2018-01-01,expirationDate: 2019-01-01,companyArea: string,companyAddress: string,businessLicenseId: string,legalRepresentative: string,companyPhone: 13800138000,mailbox: string,companySize: string,industry: string,remarks: string,auditState: string,state: 1,balance: string,createTime: string}List.push(data)
}
export default {list: () {return {code: 10000,success: true,message: 查询成功,data:List}},sassDetail:() {return {code: 10000,success: true,message: 查询成功,data:{id: 10001,name: 测试企业,managerId: string,version: 试用版v1.0,renewalDate: 2018-01-01,expirationDate: 2019-01-01,companyArea: string,companyAddress: string,businessLicenseId: string,legalRepresentative: string,companyPhone: 13800138000,mailbox: string,companySize: string,industry: string,remarks: string,auditState: string,state: 1,balance: string,createTime: string}}}
}
配置模拟API接口拦截规则
在/src/mock/index.js中配置模拟数据接口拦截规则
import Mock from mockjs
import TableAPI from ./table
import ProfileAPI from ./profile
import LoginAPI from ./login
import CompanyAPI from ./company
Mock.setup({//timeout: 1000
})
//如果发送请求的api路径匹配拦截
//第一个参数匹配的请求api路径第二个参数匹配请求的方式第三个参数相应数据如何替换
Mock.mock(/\/table\/list\.*/, get, TableAPI.list)
//获取用户信息
Mock.mock(/\/frame\/profile/, post, ProfileAPI.profile)
Mock.mock(/\/frame\/login/, post, LoginAPI.login)
//配置模拟数据接口
// /company/12
Mock.mock(/\/company\//, get, CompanyAPI.sassDetail)//根据id查询
Mock.mock(/\/company/, get, CompanyAPI.list) //访问企业列表
注册模块
编辑src/main.js
...
/*
* 注册 - 业务模块
*/
import dashboard from /module-dashboard/ // 面板
import saasClients from /module-saas-clients/ //刚新添加的 企业管理
Vue.use(dashboard, store)
Vue.use(saasClients, store)
...
配置路由菜单
打开刚才自动创建的/src/module-saas-clients/router/index.js
import Layout from /module-dashboard/pages/layout
const _import require(/router/import_ process.env.NODE_ENV)
export default [{path: /saas-clients,component: Layout,redirect: noredirect,name: saas-clients,meta: {title: SaaS企业管理,icon: international},root: true, children: [{path: index,name: saas-clients-index,component: _import(saas-clients/pages/index),meta: {title: SaaS企业, icon: international, noCache: true}}]}
]
骚戴理解 path: /saas-clients是父路径 component: _import(saas-clients/pages/index)可不是子路径 path: index才是子路径我一开始以为 component: _import(saas-clients/pages/index)是子路径其实 component: _import(saas-clients/pages/index) 只是说从根据这个路径去找Vue视图页面
编写业务页面
创建/src/module-saas-clients/pages/index.vue
templatediv classdashboard-containersaas企业管理/div
/template
script
export default {name: saasClintList,components: {},data() {return {}},computed: {},created() {}
}
/script
注意文件名 驼峰格式 首字小写
页面请放在目录 /src/module-saas-clients/pages/
组件请放在目录 /src/module-saas-clients/components/
页面路由请修改 /src/module-saas-clients/router/index.js
企业操作
创建api
在api/base目录下创建企业数据交互的APIsaasClient.js
import {createAPI, createFormAPI} from /utils/request
export const list data createAPI(/company, get, data)
export const detail data createAPI(/company/${data.id}, get, data)
骚戴理解/company/${data.id}这里注意带参数的写法然后注意是梵引号不是单引号
企业列表
在src\module-saas-clients\pages\index.vue里面引用上面的API
templatediv classdashboard-containerdiv classapp-containerel-card shadownever!--elementui的table组件data数据模型--el-table :datadataList border stylewidth: 100%!--el-table-column : 构造表格中的每一列 prop 数组中每个元素对象的属性名--el-table-column typeindex label序号 width50/el-table-columnel-table-column propname label企业名称 /el-table-columnel-table-column propversion label版本 /el-table-columnel-table-column propcompanyphone label联系电话 /el-table-columnel-table-column propexpirationDate label截至时间 /el-table-columnel-table-column propstate label状态 !--scope:传递当前行的所有数据 --template slot-scopescope!--开关组件active-value激活的数据值active-color激活的颜色inactive-value未激活inactive-color未激活的颜色--el-switchv-modelscope.row.stateinactive-value0 active-value1disabledactive-color#13ce66inactive-color#ff4949/el-switch/template/el-table-columnel-table-column fixedright label操作 width150template slot-scopescoperouter-link :to/saas-clients/details/scope.row.id查看/router-link/template/el-table-column/el-table/el-card/div/div
/templatescript
import {list} from /api/base/saasClient
export default {name: saas-clients-index,data () {return {dataList:[]}},methods: {getList() {//调用API发起请求//res响应数据list().then(res {this.dataList res.data.data})}},// 创建完毕状态created() {this.getList()}
}
/scriptstyle relstylesheet/scss langscss scoped
.alert {margin: 10px 0px 0px 0px;
}
.pagination {margin-top: 10px;text-align: right;
}
/style骚戴理解import {list} from /api/base/saasClient通过这句引用API在getList方法里面去用list()这里也并没有直接发请求给后端而是演示了一下mock怎样模拟数据在src\mock\company.js填写模拟数据然后注册到mock里面进行拦截在src\mock\index.js这里面注册模拟的mockAPI然后设置拦截路径拦截对应的请求然后返回模拟数据 骚戴理解
/\/company\// 表示一个正则表达式匹配包含 /company/ 后面跟着一个或多个字符的字符串比如:
/company/apple/company/google/maps/company/microsoft/windows/excel
但是不匹配以下字符串
/company//company/companyapple
而 /\/company/ 则表示一个正则表达式匹配所有以 /company 开头的字符串包括:
/company/company/apple/company/google/maps/company/microsoft/windows/excel
它也会匹配包含 /company 例如 /companyapple 因为该正则表达式只匹配 字符串开始部分的 /company。
import Mock from mockjs
import { param2Obj } from /utilsconst List []
const count 100for (let i 0; i 3; i) {let data {id: 1i,name: 企业i,managerId: string,version: 试用版v1.0,renewalDate: 2018-01-01,expirationDate: 2019-01-01,companyArea: string,companyAddress: string,businessLicenseId: string,legalRepresentative: string,companyPhone: 13800138000,mailbox: string,companySize: string,industry: string,remarks: string,auditState: string,state: 1,balance: string,createTime: string}List.push(data)
}export default {list: () {return {code: 10000,success: true,message: 查询成功,data:List}},sassDetail:() {return {code: 10000,success: true,message: 查询成功,data:{id: 10001,name: 测试企业,managerId: string,version: 试用版v1.0,renewalDate: 2018-01-01,expirationDate: 2019-01-01,companyArea: string,companyAddress: string,businessLicenseId: string,legalRepresentative: string,companyPhone: 13800138000,mailbox: string,companySize: string,industry: string,remarks: string,auditState: string,state: 1,balance: string,createTime: string}}}
}骚戴理解 这里两个前端的点通过以下的语句来实现序号排列数据注意这个序号不是数据库里的id
el-table-column fixed typeindex label序号 width50/el-table-column
通过下面的代码块来实现按钮 disabled直接设置按钮可不可设置 el-table-column fixed propstate label状态 width150!--scope:传递当前行的所有数据 --template slot-scopescope!--开关组件active-value激活的数据值active-color激活的颜色inactive-value未激活inactive-color未激活的颜色--el-switchv-modelscope.row.stateinactive-value0 active-value1disabledactive-color#13ce66inactive-color#ff4949/el-switch/template/el-table-column
骚戴理解这里我抽出来主要是要学会通过Vue的方式去发请求注意是单引号去拼接请求的url路径
template slot-scopescoperouter-link :to/saas-clients/details/scope.row.id查看/router-link
/template
企业详情
1配置路由
在 /src/module-saas-clients/router/index.js 添加新的子路由配置 {path: details/:id,name: saas-clients-details,component: _import(saas-clients/pages/sass-details),meta: {title: SaaS企业详情, icon: international, noCache: false}}
2定义公共组件在/src/module-saas-clients/components/下创建公共的组件页面enterprise-info.vue
templatediv classboxInfo!-- 表单内容 --div classformInfodivdiv classboxMainel-form refform :modelformData label-width215px labelpositionrightel-form-item classformInfo label公司名称el-input v-modelformData.name classinputW disabled/el-input/el-form-itemel-form-item classformInfo label公司地区el-input v-modelformData.companyArea classinputW disabled/elinput/el-form-itemel-form-item classformInfo label公司地址el-input v-modelformData.companyAddress classinputW disabled
/el-input/el-form-itemel-form-item classformInfo label审核状态el-input v-modelformData.auditState classinputW disabled/elinput/el-form-itemel-form-item classformInfo label营业执照span v-foritem in fileList :keyitem.id classfileImgimg :srcitem.url/span/el-form-itemel-form-item classformInfo label法人代表el-input v-modelformData.legalRepresentative classinputW
disabled/el-input/el-form-itemel-form-item classformInfo label公司电话el-input v-modelformData.companyPhone classinputW disabled/elinput/el-form-itemel-form-item classformInfo label邮箱el-input v-modelformData.mailbox classinputW disabled/elinput/el-form-itemel-form-item classformInfo label公司规模el-input v-modelformData.companySize classinputW disabled/elinput/el-form-itemel-form-item classformInfo label所属行业el-input v-modelformData.industry classinputW disabled/elinput/el-form-itemel-form-item classformInfo label备注el-input typetextarea v-modelformData.remarks classinputW
/el-input/el-form-item/el-formdiv slotfooter classdialog-footerel-button typeprimary clickhandleSub(1)审核/el-buttonel-button clickhandleSub(2)拒绝/el-button/div/div/div/div/div
/template
script
import { auditDetail } from /api/base/sassClients
import { imgDownload } from /api/base/baseApi
var _this null
export default {name: userInfo,components: {},props: [formData],data() {return {fileList: []}},methods: {// 业务方法// 界面交互handleSub(state) {auditDetail({id: this.formData.id,remarks: this.formData.remarks,state: state}).then(() {if (state 1) {this.$message.success(恭喜你审核成功)}if (state 2) {this.$message.success(已拒绝审核)}this.$emit(getObjInfo, this.formData)})},// 图片 blob 流转化为可用 srcimgHandle(obj) {return window.URL.createObjectURL(obj)},// 图片下载fillDownload(fid) {}},// 挂载结束mounted: function() {},// 创建完毕状态created: function() {_this this},// 组件更新updated: function() {// this.imgDownInfo()if (this.formData.businessLicense ! null) {this.fillDownload(this.formData.businessLicense)}}
}
/script
style relstylesheet/scss langscss
/style
style relstylesheet/scss langscss scoped
.fileImg{img{width:20%;}
}
/style
3完成详情展示在在/src/module-saas-clients/pages/下创建企业详情视图details.vue
templatediv classdashboard-containerdiv classapp-containerel-card shadowneverel-tabs v-modelactiveNameel-tab-pane label企业信息 namefirst!--form表单model 双向绑定的数据对象--el-form refform :modelformData label-width200pxel-form-item label企业名称 el-input v-modelformData.name stylewidth:250px disabled
/el-input/el-form-itemel-form-item label公司地址el-input v-modelformData.companyAddress stylewidth:250px
disabled/el-input/el-form-itemel-form-item label公司电话el-input v-modelformData.companyPhone stylewidth:250px
disabled/el-input/el-form-itemel-form-item label邮箱el-input v-modelformData.mailbox stylewidth:250px
disabled/el-input/el-form-itemel-form-item label备注el-input v-modelformData.remark stylewidth:250px /elinput/el-form-itemel-form-itemel-button typeprimary审核/el-buttonel-button拒绝/el-button/el-form-item/el-form/el-tab-paneel-tab-pane label账户信息 namesecond账户信息/el-tab-paneel-tab-pane label交易记录 namethird交易记录/el-tab-pane/el-tabs/el-card/div/div
/template
script
import {detail} from /api/base/saasClient
export default {name: saas-clients-detail,data () {return {activeName: first,formData:{}}},methods: {detail(id) {detail({id:id}).then(res {this.formData res.data.dataconsole.log(id)console.log(this.formData)})}},// 创建完毕状态created() {var id this.$route.params.idthis.detail(id);}
}
/script
style relstylesheet/scss langscss scoped
.alert {margin: 10px 0px 0px 0px;
}
.pagination {margin-top: 10px;text-align: right;
}
/style
骚戴理解: activeName: first是默认加载first这个tab如下所示 this.$route.params.id表示获取当前页面url路由参数中为id的值并将其赋值给变量“id”。
具体来说假设url为example.com/page/123那么在vue.js应用程序中如果当前页面的路由配置为{ path: /page/:id, component: mycomponent }则this.$route.params.id的值将为123。因此以上代码将把123赋值给变量“id”。
接口对接
1启动企业微服务服务
2在 config/dev.env.js 中配置请求地址
use strict
const merge require(webpack-merge)
const prodEnv require(./prod.env)
module.exports merge(prodEnv, {NODE_ENV: development,BASE_API: http://localhost:9001/
})
骚戴理解如果要前后端联调的话就需要把src\mock\index.js路径下的mock给禁用掉然后修改上面的BASE_API: http://localhost:9001/为后端端口的地址这样请求才会走后端