?數(shù)據(jù)庫設(shè)計與前端框架
學(xué)習(xí)目標(biāo):
理解多租戶的數(shù)據(jù)庫設(shè)計方案
熟練使用PowerDesigner構(gòu)建數(shù)據(jù)庫模型理解前端工程的基本架構(gòu)和執(zhí)行流程
完成前端工程企業(yè)模塊開發(fā)
多租戶SaaS平臺的數(shù)據(jù)庫方案
多租戶是什么
多租戶技術(shù)(Multi-TenancyTechnology)又稱多重租賃技術(shù):是一種軟件架構(gòu)技術(shù),是實現(xiàn)如何在多用戶環(huán)境下
(此處的多用戶一般是面向企業(yè)用戶)共用相同的系統(tǒng)或程序組件,并且可確保各用戶間數(shù)據(jù)的隔離性。簡單講: 在一臺服務(wù)器上運行單個應(yīng)用實例,它為多個租戶(客戶)提供服務(wù)。從定義中我們可以理解:多租戶是一種架 構(gòu),目的是為了讓多用戶環(huán)境下使用同一套程序,且保證用戶間數(shù)據(jù)隔離。那么重點就很淺顯易懂了,多租戶的重 點就是同一套程序下實現(xiàn)多用戶數(shù)據(jù)的隔離
需求分析
傳統(tǒng)軟件模式,指將軟件產(chǎn)品進行買賣,是一種單純的買賣關(guān)系,客戶通過買斷的方式獲取軟件的使用權(quán),軟件的 源碼屬于客戶所有,因此傳統(tǒng)軟件是部署到企業(yè)內(nèi)部,不同的企業(yè)各自部署一套自己的軟件系統(tǒng)
Saas模式,指服務(wù)提供商提供的一種軟件服務(wù),應(yīng)用統(tǒng)一部署到服務(wù)提供商的服務(wù)器上,客戶可以根據(jù)自己的實際 需求按需付費。用戶購買基于WEB的軟件,而不是將軟件安裝在自己的電腦上,用戶也無需對軟件進行定期的維護 與管理
在SaaS平臺里需要使用共用的數(shù)據(jù)中心以單一系統(tǒng)架構(gòu)與服務(wù)提供多數(shù)客戶端相同甚至可定制化的服務(wù),并且仍可 以保障客戶的數(shù)據(jù)正常使用。由此帶來了新的挑戰(zhàn),就是如何對應(yīng)用數(shù)據(jù)進行設(shè)計,以支持多租戶,而這種設(shè)計的 思路,是要在數(shù)據(jù)的共享、安全隔離和性能間取得平衡。
多租戶的數(shù)據(jù)庫方案分析
目前基于多租戶的數(shù)據(jù)庫設(shè)計方案通常有如下三種:
- 獨立數(shù)據(jù)庫
- 共享數(shù)據(jù)庫、獨立 Schema
- 共享數(shù)據(jù)庫、共享數(shù)據(jù)表
獨立數(shù)據(jù)庫
獨立數(shù)據(jù)庫:每個租戶一個數(shù)據(jù)庫。
優(yōu)點:為不同的租戶提供獨立的數(shù)據(jù)庫,有助于簡化數(shù)據(jù)模型的擴展設(shè)計,滿足不同租戶的獨特需求;如果 出現(xiàn)故障,恢復(fù)數(shù)據(jù)比較簡單。
缺點: 增多了數(shù)據(jù)庫的安裝數(shù)量,隨之帶來維護成本和購置成本的增加
這種方案與傳統(tǒng)的一個客戶、一套數(shù)據(jù)、一套部署類似,差別只在于軟件統(tǒng)一部署在運營商那里。由此可見此方案用戶數(shù)據(jù)隔離級別最高,安全性最好,但是成本較高
共享數(shù)據(jù)庫、獨立 Schema
(1) 什么是Schema
oracle數(shù)據(jù)庫:在oracle中一個數(shù)據(jù)庫可以具有多個用戶,那么一個用戶一般對應(yīng)一個Schema,表都是建立在Schema中的,(可以簡單的理解:在oracle中一個用戶一套數(shù)據(jù)庫表)
騷戴理解:其實oracle的Schema就相當(dāng)于mysql中的database
mysql數(shù)據(jù)庫:mysql數(shù)據(jù)中的schema比較特殊,并不是數(shù)據(jù)庫的下一級,而是等同于數(shù)據(jù)庫。比如執(zhí)行create schema test 和執(zhí)行create database test效果是一模一樣的
共享數(shù)據(jù)庫、獨立 Schema:即多個或所有的租戶使用同一個數(shù)據(jù)庫服務(wù)(如常見的ORACLE或MYSQL數(shù)據(jù)庫), 但是每個租戶一個Schema。
優(yōu)點: 為安全性要求較高的租戶提供了一定程度的邏輯數(shù)據(jù)隔離,并不是完全隔離;每個數(shù)據(jù)庫可支持更多的租戶數(shù)量。
缺點: 如果出現(xiàn)故障,數(shù)據(jù)恢復(fù)比較困難,因為恢復(fù)數(shù)據(jù)庫將牽涉到其他租戶的數(shù)據(jù); 如果需要跨租戶統(tǒng)計數(shù)據(jù),存在一定困難。
這種方案是方案一的變種。只需要安裝一份數(shù)據(jù)庫服務(wù),通過不同的Schema對不同租戶的數(shù)據(jù)進行隔離。由于數(shù)據(jù)庫服務(wù)是共享的,所以成本相對低廉。
騷戴理解:共享數(shù)據(jù)庫、獨立 Schema方案其實就是假如我在服務(wù)器上安裝了一個mysql服務(wù)端,然后每一個用戶就給他創(chuàng)建一個數(shù)據(jù)庫database,這樣多個用戶就只需要創(chuàng)建多個database數(shù)據(jù)庫即可,不需要像獨立數(shù)據(jù)庫方案一樣每一個用戶我就要去搭建一個mysql服務(wù)端。共享數(shù)據(jù)庫、共享數(shù)據(jù)表方案就是我就一個數(shù)據(jù)庫,一套數(shù)據(jù)庫表,大家都用這個,至于怎么區(qū)分到底哪條記錄是哪個用戶的?加個用戶標(biāo)識的字段就可以了!
共享數(shù)據(jù)庫、共享數(shù)據(jù)表
共享數(shù)據(jù)庫、共享數(shù)據(jù)表:即租戶共享同一個Database,同一套數(shù)據(jù)庫表(所有租戶的數(shù)據(jù)都存放在一個數(shù)據(jù)庫的同一套表中)。在表中增加租戶ID等租戶標(biāo)志字段,表明該記錄是屬于哪個租戶的。
優(yōu)點:所有租戶使用同一套數(shù)據(jù)庫,所以成本低廉。
缺點:隔離級別最低,安全性最低,需要在設(shè)計開發(fā)時加大對安全的開發(fā)量,數(shù)據(jù)備份和恢復(fù)最困難。
這種方案和基于傳統(tǒng)應(yīng)用的數(shù)據(jù)庫設(shè)計并沒有任何區(qū)別,但是由于所有租戶使用相同的數(shù)據(jù)庫表,所以需要做好對 每個租戶數(shù)據(jù)的隔離安全性處理,這就增加了系統(tǒng)設(shè)計和數(shù)據(jù)管理方面的復(fù)雜程度。
SAAS-HRM數(shù)據(jù)庫設(shè)計
在SAAS-HRM平臺中,分為了試用版和正式版。處于教學(xué)的目的,試用版采用共享數(shù)據(jù)庫、共享數(shù)據(jù)表的方式設(shè) 計。正式版采用基于mysql的共享數(shù)據(jù)庫、獨立 Schema設(shè)計。
數(shù)據(jù)庫設(shè)計與建模
數(shù)據(jù)庫設(shè)計的三范式
三范式
第一范式(1NF):確保每一列的原子性(做到每列不可拆分)
第二范式(2NF):在第一范式的基礎(chǔ)上,非主字段必須依賴于主字段(一個表只做一件事)
第三范式(3NF):在第二范式的基礎(chǔ)上,消除傳遞依賴
反三范式:反三范式是基于第三范式所調(diào)整的,沒有冗余的數(shù)據(jù)庫未必是最好的數(shù)據(jù)庫,有時為了提高運行效率,就必須降低范式標(biāo)準(zhǔn),適當(dāng)保留冗余數(shù)據(jù)。
騷戴理解:第二范式其實就是假如有一個學(xué)生表,除了學(xué)生基本信息的一些字段,如果你還有課程成績相關(guān)的字段在這個表就不符合第二范式,把課程成績相關(guān)字段拆出來分作一個成績表,那就符合第二范式。繼續(xù)上面的例子,現(xiàn)在已經(jīng)分成了學(xué)生表和成績表,學(xué)生表里有個字段是成績表的id,那么我每次查詢學(xué)生的所有信息(包括成績)我都要去查詢學(xué)生表然后根據(jù)成績id去成績表再查一次,這樣就要查詢兩次,所以就有了反三范式的出現(xiàn),反三范式就是加冗余字段,也就是把成績信息又加到學(xué)生表里,這樣只要查詢學(xué)生表就可以查詢出學(xué)生的所有信息,當(dāng)然這是跟第二范式?jīng)_突的,所以叫“反”三范式。至于這個三范式其實就是假如有個表,里面有單價和數(shù)量兩個字段,那么就可以根據(jù)單價和數(shù)量去計算出總價,所以就可以不需要總價這個字段,這也叫傳遞依賴
數(shù)據(jù)庫建模
了解了數(shù)據(jù)的設(shè)計思想,那對于數(shù)據(jù)庫表的表設(shè)計應(yīng)該怎么做呢?答案是數(shù)據(jù)庫建模
數(shù)據(jù)庫建模:在設(shè)計數(shù)據(jù)庫時,對現(xiàn)實世界進行分析、抽象、并從中找出內(nèi)在聯(lián)系,進而確定數(shù)據(jù)庫的結(jié)構(gòu)。它主 要包括兩部分內(nèi)容:確定最基本的數(shù)據(jù)結(jié)構(gòu);對約束建模。
建模工具
對于數(shù)據(jù)模型的建模,最有名的要數(shù)PowerDesigner,PowerDesigner是在中國軟件公司中非常有名的,其易用性、功能、對流行技術(shù)框架的支持、以及它的模型庫的管理理念,都深受設(shè)計師們喜歡。他的優(yōu)勢在于:不用在使 用create table等語句創(chuàng)建表結(jié)構(gòu),數(shù)據(jù)庫設(shè)計人員只關(guān)注如何進行數(shù)據(jù)建模即可,將來的數(shù)據(jù)庫語句,可以自動生成
使用pd建模
選擇新建數(shù)據(jù)庫模型 打開PowerDesigner,文件->建立新模型->model types(選擇類型)->Physical Data Model(物理模型)
控制面板
創(chuàng)建數(shù)據(jù)庫表
點即面板按鈕中的創(chuàng)建數(shù)據(jù)庫按鈕創(chuàng)建數(shù)據(jù)庫模型
切換columns標(biāo)簽,可以對表中的所有字段進行配置
如果基于傳統(tǒng)的數(shù)據(jù)庫設(shè)計中存在外鍵則可以使用面版中的Reference配置多個表之間的關(guān)聯(lián)關(guān)系,效果如下圖
導(dǎo)出sql
菜單->數(shù)據(jù)庫(database)->生成數(shù)據(jù)庫表結(jié)構(gòu)(Generate Database)
前端框架
腳手架工程
此項目采用目前比較流行的前后端分離的方式進行開發(fā)。前端是在傳智播客研究院開源的前端框架(黑馬Admin商用后臺模板)的基礎(chǔ)上進行的開發(fā)。
官網(wǎng)上提供了非?;A(chǔ)的腳手架,如果我們使用官網(wǎng)的腳手架需要自己寫很多代碼比如登陸界面、主界面菜單樣式 等內(nèi)容。 課程已經(jīng)提供了功能完整的腳手架,我們可以拿過來在此基礎(chǔ)上開發(fā),這樣可以極大節(jié)省我們開發(fā)的時間。
技術(shù)棧
- vue 2.5++
- elementUI 2.2.2 vuex
- axios
- vue-router vue-i18n
前端環(huán)境
- node 8.++
- npm 5.++
啟動與安裝
官網(wǎng)上提供了非?;A(chǔ)的腳手架,如果我們使用官網(wǎng)的腳手架需要自己寫很多代碼比如登陸界面、主界面菜單樣式 等內(nèi)容。 課程已經(jīng)提供了功能完整的腳手架,我們可以拿過來在此基礎(chǔ)上開發(fā),這樣可以極大節(jié)省我們開發(fā)的時間。
- 解壓提供的資源包
- 在命令提示符進入該目錄,輸入命令:
cnpm install
通過淘寶鏡像下載安裝所有的依賴,幾分鐘后下載完成如果沒有安裝淘寶鏡像,請使用npm install
- 關(guān)閉語法檢查
打開 將useEslint的值改為false。
config/index.js
useEslint: false,
此配置作用: 是否開啟語法檢查,語法檢查是通過ESLint 來實現(xiàn)的。我們現(xiàn)在科普一下,什么是ESLint : ESLint 是一個語法規(guī)則和代碼風(fēng)格的檢查工具,可以用來保證寫出語法正確、風(fēng)格統(tǒng)一的代碼。如果我們開啟了 Eslint , 也就意味著要接受它非??量痰恼Z法檢查,包括空格不能少些或多些,必須單引不能雙引,語句后不可以寫分號等等,這些規(guī)則其實是可以設(shè)置的。我們作為前端的初學(xué)者,最好先關(guān)閉這種校驗,否則會浪費 很多精力在語法的規(guī)范性上。如果以后做真正的企業(yè)級開發(fā),建議開啟
- 輸入命令:
npm run dev
工程結(jié)構(gòu)
整個前端工程的工程目錄結(jié)構(gòu)如下:
├── assets | 資源
├── build | webpack編譯配置
├── config | 全局變量
├── src | 源碼
│ ├── api | 數(shù)據(jù)請求
│ ├── assets | 資源
│ ├── components | 組件
│ ├── mixins | mixins
│ ├── filters | vue filter
│ ├── icons | 圖標(biāo)
│ ├── lang | 多語言
│ ├── router | 路由
│ ├── store | 數(shù)據(jù)
│ ├── styles | 樣式
│ ├── utils | 工具函數(shù)庫
│ ├── module-dashboard | 框架程序
│ │ ├── assets
│ │ ├── components
│ │ ├── pages
│ │ ├── router
│ │ └── store
│ ├── module-example | 示例程序
│ │ ├── assets
│ │ ├── components
│ │ ├── pages
│ │ ├── router
│ │ └── store
│ ├── App.vue | app
│ ├── main.js | 主引導(dǎo)
│ └── errorLog.js | vue全局錯誤捕捉
├── dist | 編譯發(fā)布目錄
├── README.md
├── index.html | 頁面模板
├── package.json | npn包配置
├── static
└── test | 測試
├── e2e
└── unit
執(zhí)行流程分析
路由和菜單
路由和菜單是組織起一個后臺應(yīng)用的關(guān)鍵骨架。本項目側(cè)邊欄和路由是綁定在一起的,所以你只有在@/router/index.js 下面配置對應(yīng)的路由,側(cè)邊欄就能動態(tài)的生成了。大大減輕了手動編輯側(cè)邊欄的工作量。
當(dāng)然這樣就需要在配置路由的時候遵循很多的約定這里的路由分為兩種, constantRouterMap 和 asyncRouterMap 。
- constantRouterMap 代通用頁面。
- asyncRouterMap 代表那些業(yè)務(wù)中通過 addRouters 動態(tài)添加的頁面。
騷戴理解:路由分為兩種,公共路由和模塊路由,公共路由就是下面的第二個紅框畫出來的,通常就是登錄、注冊、404頁面這些公共模塊的路由定義,下面module-saas-clients就是一個模塊,所有模塊通常都是以module開頭的,那么模塊下面的router路由自然就是模塊路由
其實每一個模塊就是下面的左側(cè)欄,例如這個模塊對應(yīng)的就是SAAS企業(yè)這個左側(cè)欄,
前端數(shù)據(jù)交互
一個完整的前端 UI 交互到服務(wù)端處理流程是這樣的:
- UI 組件交互操作;
- 調(diào)用統(tǒng)一管理的 api service 請求函數(shù);
- 使用封裝的 request.js 發(fā)送請求;
- 獲取服務(wù)端返回;
- 更新 data;
從上面的流程可以看出,為了方便管理維護,統(tǒng)一的請求處理都放在 src/api 文件夾中,并且一般按照 model緯度進行拆分文件
api/
frame.js
menus.js
users.js
permissions.js
...
其中, src/utils/request.js 是基于 axios 的封裝,便于統(tǒng)一處理 POST,GET 等請求參數(shù),請求頭,以及錯誤提示信息等。具體可以參看 request.js。 它封裝了全局 request攔截器 、 respone攔截器 、 統(tǒng)一的錯誤處理 、 統(tǒng)一做了超時,baseURL設(shè)置等
騷戴理解:這里我一開始不理解為什么明明用的是demo卻可以找到module-demo這個模塊?
上面的這個main.js里面定義了模塊的名稱,所以你的路徑里用的是demo也可以找到module-demo這個模塊
企業(yè)管理
需求分析
在通用頁面配置企業(yè)管理模塊,完成企業(yè)的基本操作
搭建環(huán)境
新增模塊
手動創(chuàng)建
方式一:在src目錄下創(chuàng)建文件夾,命名規(guī)則:module-模塊名稱()
在文件夾下按照指定的結(jié)構(gòu)配置assets,components,pages,router,store等文件
使用命令自動創(chuàng)建
安裝命令行工具
npm install -g itheima-cli
執(zhí)行命令
itheima moduleAdd saas-clients
`saas-clients` 是新模塊的名字
自動創(chuàng)建這些目錄和文件
│ ├── module-saas-clients | saas-clients模塊主目錄
│ │ ├── assets | 資源
│ │ ├── components | 組件
│ │ ├── pages | 頁面
│ │ │ └── index.vue | 示例
│ │ ├── router | 路由
│ │ │ └── index.js | 示例
│ │ └── store | 數(shù)據(jù)
│ │ └── app.js | 示例
每個模塊所有的素材、頁面、組件、路由、數(shù)據(jù),都是獨立的,方便大型項目管理, 在實際項目中會有很多子業(yè)務(wù)項目,它們之間的關(guān)系是平行的、低耦合、互不依賴。
構(gòu)造模擬數(shù)據(jù)
- 在/src/mock中添加模擬數(shù)據(jù)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: "1"+i,
name: "企業(yè)"+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: "測試企業(yè)",
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接口攔截規(guī)則
在/src/mock/index.js中配置模擬數(shù)據(jù)接口攔截規(guī)則
import Mock from 'mockjs'
import TableAPI from './table'
import ProfileAPI from './profile'
import LoginAPI from './login'
import CompanyAPI from './company'
Mock.setup({
//timeout: '1000'
})
//如果發(fā)送請求的api路徑匹配,攔截
//第一個參數(shù)匹配的請求api路徑,第二個參數(shù)匹配請求的方式,第三個參數(shù)相應(yīng)數(shù)據(jù)如何替換
Mock.mock(/\/table\/list\.*/, 'get', TableAPI.list)
//獲取用戶信息
Mock.mock(/\/frame\/profile/, 'post', ProfileAPI.profile)
Mock.mock(/\/frame\/login/, 'post', LoginAPI.login)
//配置模擬數(shù)據(jù)接口
// /company/12
Mock.mock(/\/company\/+/, 'get', CompanyAPI.sassDetail)//根據(jù)id查詢
Mock.mock(/\/company/, 'get', CompanyAPI.list) //訪問企業(yè)列表
注冊模塊
編輯src/main.js
...
/*
* 注冊 - 業(yè)務(wù)模塊
*/
import dashboard from '@/module-dashboard/' // 面板
import saasClients from '@/module-saas-clients/' //剛新添加的 企業(yè)管理
Vue.use(dashboard, store)
Vue.use(saasClients, store)
...
配置路由菜單
打開剛才自動創(chuàng)建的/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企業(yè)管理',
icon: 'international'
},
root: true,
children: [
{
path: 'index',
name: 'saas-clients-index',
component: _import('saas-clients/pages/index'),
meta: {title: 'SaaS企業(yè)', 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') 只是說從根據(jù)這個路徑去找Vue視圖頁面
編寫業(yè)務(wù)頁面
創(chuàng)建/src/module-saas-clients/pages/index.vue
<template>
<div class="dashboard-container">
saas企業(yè)管理
</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
企業(yè)操作
創(chuàng)建api
在api/base目錄下創(chuàng)建企業(yè)數(shù)據(jù)交互的API(saasClient.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}`這里注意帶參數(shù)的寫法,然后注意是梵引號不是單引號
企業(yè)列表
在src\module-saas-clients\pages\index.vue里面引用上面的API
<template>
<div class="dashboard-container">
<div class="app-container">
<el-card shadow="never">
<!--elementui的table組件
data:數(shù)據(jù)模型
-->
<el-table :data="dataList" border style="width: 100%">
<!--el-table-column : 構(gòu)造表格中的每一列
prop: 數(shù)組中每個元素對象的屬性名
-->
<el-table-column type="index" label="序號" width="50"></el-table-column>
<el-table-column prop="name" label="企業(yè)名稱" ></el-table-column>
<el-table-column prop="version" label="版本" ></el-table-column>
<el-table-column prop="companyphone" label="聯(lián)系電話" ></el-table-column>
<el-table-column prop="expirationDate" label="截至?xí)r間" ></el-table-column>
<el-table-column prop="state" label="狀態(tài)" >
<!--scope:傳遞當(dāng)前行的所有數(shù)據(jù) -->
<template slot-scope="scope">
<!--開關(guān)組件
active-value:激活的數(shù)據(jù)值
active-color:激活的顏色
inactive-value:未激活
inactive-color:未激活的顏色
-->
<el-switch
v-model="scope.row.state"
inactive-value="0"
active-value="1"
disabled
active-color="#13ce66"
inactive-color="#ff4949">
</el-switch>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="150">
<template slot-scope="scope">
<router-link :to="'/saas-clients/details/'+scope.row.id">查看</router-link>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</div>
</template>
<script>
import {list} from '@/api/base/saasClient'
export default {
name: 'saas-clients-index',
data () {
return {
dataList:[]
}
},
methods: {
getList() {
//調(diào)用API發(fā)起請求
//res=響應(yīng)數(shù)據(jù)
list().then(res => {
this.dataList = res.data.data
})
}
},
// 創(chuàng)建完畢狀態(tài)
created() {
this.getList()
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.alert {
margin: 10px 0px 0px 0px;
}
.pagination {
margin-top: 10px;
text-align: right;
}
</style>
騷戴理解:import {list} from '@/api/base/saasClient'通過這句引用API,在getList方法里面去用list(),這里也并沒有直接發(fā)請求給后端,而是演示了一下mock怎樣模擬數(shù)據(jù),在src\mock\company.js填寫模擬數(shù)據(jù),然后注冊到mock里面進行攔截,在src\mock\index.js這里面注冊模擬的mockAPI,然后設(shè)置攔截路徑,攔截對應(yīng)的請求然后返回模擬數(shù)據(jù)
騷戴理解:
/\/company\/+/ 表示一個正則表達(dá)式,匹配包含 /company/ 后面跟著一個或多個字符的字符串,比如:
- /company/apple
- /company/google/maps
- /company/microsoft/windows/excel
但是不匹配以下字符串:
- /company/
- /company
- /companyapple
而 /\/company/ 則表示一個正則表達(dá)式,匹配所有以 "/company" 開頭的字符串,包括:
- /company
- /company/apple
- /company/google/maps
- /company/microsoft/windows/excel
它也會匹配包含 /company 例如 /companyapple , 因為該正則表達(dá)式只匹配 字符串開始部分的 /company。
import Mock from 'mockjs'
import { param2Obj } from '@/utils'
const List = []
const count = 100
for (let i = 0; i < 3; i++) {
let data = {
id: "1"+i,
name: "企業(yè)"+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: "測試企業(yè)",
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"
}
}
}
}
騷戴理解: 這里兩個前端的點,通過以下的語句來實現(xiàn)序號排列數(shù)據(jù),注意這個序號不是數(shù)據(jù)庫里的id
<el-table-column fixed type="index" label="序號" width="50"></el-table-column>
通過下面的代碼塊來實現(xiàn)按鈕, disabled直接設(shè)置按鈕可不可設(shè)置
<el-table-column fixed prop="state" label="狀態(tài)" width="150">
<!--scope:傳遞當(dāng)前行的所有數(shù)據(jù) -->
<template slot-scope="scope">
<!--開關(guān)組件
active-value:激活的數(shù)據(jù)值
active-color:激活的顏色
inactive-value:未激活
inactive-color:未激活的顏色
-->
<el-switch
v-model="scope.row.state"
inactive-value="0"
active-value="1"
disabled
active-color="#13ce66"
inactive-color="#ff4949">
</el-switch>
</template>
</el-table-column>
騷戴理解:這里我抽出來主要是要學(xué)會通過Vue的方式去發(fā)請求,注意是單引號去拼接請求的url路徑
<template slot-scope="scope">
<router-link :to="'/saas-clients/details/'+scope.row.id">查看</router-link>
</template>
企業(yè)詳情
(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企業(yè)詳情', icon: 'international', noCache: false}
}
(2)定義公共組件在/src/module-saas-clients/components/下創(chuàng)建公共的組件頁面enterprise-info.vue
<template>
<div class="boxInfo">
<!-- 表單內(nèi)容 -->
<div class="formInfo">
<div>
<div class="boxMain">
<el-form ref="form" :model="formData" label-width="215px" labelposition="right">
<el-form-item class="formInfo" label="公司名稱:">
<el-input v-model="formData.name" class="inputW" disabled></el-input>
</el-form-item>
<el-form-item class="formInfo" label="公司地區(qū):">
<el-input v-model="formData.companyArea" class="inputW" disabled></elinput>
</el-form-item>
<el-form-item class="formInfo" label="公司地址:">
<el-input v-model="formData.companyAddress" class="inputW" disabled>
</el-input>
</el-form-item>
<el-form-item class="formInfo" label="審核狀態(tài):">
<el-input v-model="formData.auditState" class="inputW" disabled></elinput>
</el-form-item>
<el-form-item class="formInfo" label="營業(yè)執(zhí)照:">
<span v-for="item in fileList" :key='item.id' class="fileImg">
<img :src="item.url">
</span>
</el-form-item>
<el-form-item class="formInfo" label="法人代表:">
<el-input v-model="formData.legalRepresentative" class="inputW"
disabled></el-input>
</el-form-item>
<el-form-item class="formInfo" label="公司電話:">
<el-input v-model="formData.companyPhone" class="inputW" disabled></elinput>
</el-form-item>
<el-form-item class="formInfo" label="郵箱:">
<el-input v-model="formData.mailbox" class="inputW" disabled></elinput>
</el-form-item>
<el-form-item class="formInfo" label="公司規(guī)模:">
<el-input v-model="formData.companySize" class="inputW" disabled></elinput>
</el-form-item>
<el-form-item class="formInfo" label="所屬行業(yè):">
<el-input v-model="formData.industry" class="inputW" disabled></elinput>
</el-form-item>
<el-form-item class="formInfo" label="備注:">
<el-input type="textarea" v-model="formData.remarks" class="inputW">
</el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="handleSub('1')">審核</el-button>
<el-button @click="handleSub('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: {
// 業(yè)務(wù)方法
// 界面交互
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 流轉(zhuǎn)化為可用 src
imgHandle(obj) {
return window.URL.createObjectURL(obj)
},
// 圖片下載
fillDownload(fid) {
}
},
// 掛載結(jié)束
mounted: function() {},
// 創(chuàng)建完畢狀態(tài)
created: function() {
_this = this
},
// 組件更新
updated: function() {
// this.imgDownInfo()
if (
this.formData.businessLicense !== null
) {
this.fillDownload(this.formData.businessLicense)
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss">
</style>
<style rel="stylesheet/scss" lang="scss" scoped>
.fileImg{
img{
width:20%;
}
}
</style>
(3)完成詳情展示在在/src/module-saas-clients/pages/下創(chuàng)建企業(yè)詳情視圖details.vue
<template>
<div class="dashboard-container">
<div class="app-container">
<el-card shadow="never">
<el-tabs v-model="activeName">
<el-tab-pane label="企業(yè)信息" name="first">
<!--form表單
model : 雙向綁定的數(shù)據(jù)對象
-->
<el-form ref="form" :model="formData" label-width="200px">
<el-form-item label="企業(yè)名稱" >
<el-input v-model="formData.name" style="width:250px" disabled>
</el-input>
</el-form-item>
<el-form-item label="公司地址">
<el-input v-model="formData.companyAddress" style="width:250px"
disabled></el-input>
</el-form-item>
<el-form-item label="公司電話">
<el-input v-model="formData.companyPhone" style="width:250px"
disabled></el-input>
</el-form-item>
<el-form-item label="郵箱">
<el-input v-model="formData.mailbox" style="width:250px"
disabled></el-input>
</el-form-item>
<el-form-item label="備注">
<el-input v-model="formData.remark" style="width:250px" ></elinput>
</el-form-item>
<el-form-item>
<el-button type="primary">審核</el-button>
<el-button>拒絕</el-button>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="賬戶信息" name="second">賬戶信息</el-tab-pane>
<el-tab-pane label="交易記錄" name="third">交易記錄</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.data
console.log(id)
console.log(this.formData)
})
}
},
// 創(chuàng)建完畢狀態(tài)
created() {
var id = this.$route.params.id
this.detail(id);
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.alert {
margin: 10px 0px 0px 0px;
}
.pagination {
margin-top: 10px;
text-align: right;
}
</style>
騷戴理解: activeName: 'first'是默認(rèn)加載first這個tab,如下所示
this.$route.params.id表示獲取當(dāng)前頁面url路由參數(shù)中為"id"的值,并將其賦值給變量“id”。
具體來說,假設(shè)url為example.com/page/123,那么在vue.js應(yīng)用程序中,如果當(dāng)前頁面的路由配置為{ path: '/page/:id', component: mycomponent },則this.$route.params.id的值將為"123"。因此,以上代碼將把"123"賦值給變量“id”。
接口對接
(1)啟動企業(yè)微服務(wù)服務(wù)
(2)在 config/dev.env.js 中配置請求地址文章來源:http://www.zghlxwxcb.cn/news/detail-430214.html
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
BASE_API: '"http://localhost:9001/"'
})
騷戴理解:如果要前后端聯(lián)調(diào)的話就需要把src\mock\index.js路徑下的mock給禁用掉,然后修改上面的BASE_API: '"http://localhost:9001/"'為后端端口的地址,這樣請求才會走后端文章來源地址http://www.zghlxwxcb.cn/news/detail-430214.html
到了這里,關(guān)于數(shù)據(jù)庫設(shè)計與前端框架的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!