一、搭建項目
1.后端gitee鏈接:
啟動項目時記得修改mysql和redis的相關信息;創建項目相關數據庫,并導入初始化的SQL腳本
dkd-parent: 帝可得后臺管理系統 (gitee.com)
2.前端gitee鏈接:
啟動項目時記得安裝依賴:npm install
dkd-vue: 帝可得前端 (gitee.com)
二、 點位管理
2.1 需求說明:
2.2 相關數據庫設計
區域表:主鍵id、區域名稱、備注說明(BaseEntity里有該字段,無需多余創建)
合作商表:主鍵id、合作商名稱、聯系人、聯系電話、分成比例·、賬號、密碼
點位表:主鍵id、點位名稱、詳細地址、商圈類型、區域外鍵、合作商外鍵
使用大模型進行數據庫的生成:
你是一位軟件工程師,幫我生成MySQL的表結構,需求如下:
1.區域表:表名tb_region,字段有id、區域名稱;
2.合作商表:表名tb_partner,字段有id、合作商名稱、聯系人、聯系電話、分成比例(int)、賬號、密碼;
3.點位表:表名tb_node 字段id、點位名稱、詳細地址、商圈類型(int);
其他要求:
1.每張表中的都有創建的時間create_time、修改時間date_time、創建人create_by、修改人update_by、備注remark這些字段;
2.每張表的主鍵都是自增的;
3.區域與點位是一對多的關系,合作商與點位是一對多的關系,請用字段表示出來,并建立外鍵的約束;
4.請為每個字段都添加上comment;
5.幫我給生成的表中插入一些北京城市相關的區域、點位、合作商的測試數據
將所生成的數據導入數據庫中
對于點位管理數據的? 關系字段:region_id、partner_id; 數據字典:business_type
2.3 點位管理相關代碼生成
2.3.1 理論部分
2.3.2 實操部分
(1)添加點位管理菜單欄
?(2)添加商圈類型的字典類型
分別添加字典類型的字鍵和對應字鍵值;結果顯示:
?(3)代碼生成(分別生成3張表的信息)
-
配置區域表:
基本信息修改:將在前綴tb刪除:
字段信息根據需求進行修改:
生成信息:根據項目中的模塊名,修改其生成模塊名和生成包路徑,最后設置上傳菜單
-
配置合作商表:
基本信息:
字段信息:
生成信息:根據項目中的模塊名,修改其生成模塊名和生成包路徑,最后設置上傳菜單
-
配置點位表:
基本信息:
字段信息:(記得商圈類型選擇商圈類型的字典類型)
生成信息:
(4)生成代碼并導入文件中,注意后端的代碼是導入manage模塊中
2.4 區域管理的改造(自主添加)
需求分析:
在該頁面無法查看到每個區域的點位數
需要對區域管理的列表顯示進行改造,使其能夠顯示各列表的點位數
2.4.1 添加RegionVo類(在Region的基礎上顯示點位數量nodeCount)
@Data
public class RegionVo extends Region {//區域點位數量private Integer nodeCount;}
?2.4.2?開啟駝峰命名轉換字段
記得在domain resources的mybatis-config.xml中打開駝峰命名轉換字段,這樣Mapper.xml中所寫的字段會通過駝峰命名的方式裝換類中的字段
2.4.3 修改后端代碼:
修改順序 Mapper => Service => Controller
Mapper:
/*** * @param region* @return 區域管理集合和每個區域的點位數量*/public List<RegionVo> selectRegionVoList(Region region);
Mapper.xml:
<select id="selectRegionVoList" resultType="com.dkd.manage.domain.vo.RegionVo">select r.*,count(n.id) as node_count from tb_region r left join tb_node n on r.id = n.region_id<where><if test="regionName != null and regionName != ''"> and region_name like concat('%', #{regionName}, '%')</if></where>group by r.id</select>
ServiceImpl:
@Overridepublic List<RegionVo> selectRegionVoList(Region region) {return regionMapper.selectRegionVoList(region);}
因為是將區域管理的列表多顯示每個區域的點位數,只需要在Controller層中修改顯示區域管理的對應的方法即可:
Controller:
/*** 查詢區域管理列表*/@PreAuthorize("@ss.hasPermi('manage:region:list')")@GetMapping("/list")public TableDataInfo list(Region region){startPage();List<RegionVo> voList = regionService.selectRegionVoList(region);return getDataTable(voList);}
2.4.4 修改前端代碼:
原有的代碼:
修改后的代碼:(在原有的代碼上添加點位數)?
?2.5 合作商管理的改造
合作商生成的界面:
2.5.1 修改前端代碼:
(1)加大搜索合作商名稱的標簽長度,使其在一條線上,并刪除多余的搜索框代碼
修改后的效果:
(2) 將合作商ID的label修改為序號,設置type為index和width,移動column的顯示順序
(3)在password的這個column,添加type = "password"這樣明文就可以變成密文
修改前:
修改的代碼:
修改后:
?
(4)在修改合作商時,設置不需要顯示賬號和密碼
添加 v-if="form.id == null" 即可;因為修改是包含id的所以隱藏賬號和密碼,而新增不包含id的,所以顯示添加賬號和密碼信息
(5)想在修改表單中顯示創建的時間
顯示效果:
(5)添加查看詳細的操作
添加操作的查看詳情的一行
編寫查看合作商詳情的函數
編寫查詢合作商詳細的對話框
點擊后的顯示效果:
?(6)給合作商的列表添加點位數(跟剛剛進行區域管理的改造差不多)
顯示效果:
(7)添加重置密碼的操作,初始的密碼值為:123456
因為在后端代碼中添加了一個重置密碼的請求,所以要修改對應api中js的代碼
對應的partner.js:
// 重置合作商管理密碼
export function resetPartnerPwd(id) {return request({url: '/manage/partner/resetPwd/' + id,method: 'put'})
}
view/partner/index.vue:?
重置密碼仿寫刪除操作的函數?
(8)給操作欄設置寬度,使其在一行上
?顯示效果:
2.5.2 修改后端代碼:
(1)設置密碼以密文的方式保存
通過觀察可以發覺password為明文
?修改其添加的代碼,使添加合作商的密碼都顯示為密文
?(2)添加重置密碼對應的后端代碼:
@PreAuthorize("@ss.hasPermi('manage:partner:edit')")@Log(title = "合作商管理", businessType = BusinessType.UPDATE)@PutMapping("/resetPwd/{id}")public AjaxResult reset(@PathVariable("id") Long id){Partner partner = new Partner();partner.setId(id);partner.setPassword(SecurityUtils.encryptPassword("123456"));return toAjax(partnerService.updatePartner(partner));}
2.6 點位管理的改造:
2.6.1點位管理的基本改造
(1)改造需求
修改前的頁面:
要求改造后的界面顯示: 將關聯的區域ID調整為所在區域 以及 將關聯的合作商ID調整為合作商
開始改造?
(2)對點位管理的中所屬區域部分進行修改
改造 將通過node中的區域Id 替換 獲取listRegion中的區域名
同時 將所屬區域為輸入框 替換為 下拉框的方式
在node/index.js 中引入獲取 listRegion的列表
在script部分添加
/* 查詢所有條件的對象 */
const loadAllParams = reactive({pageNum:1,pageSize:10000
})/* 查詢區域列表 */
const regionList = ref([])
function getListRegion(){listRegion(loadAllParams).then(response=>{regionList.value = response.rows})
}getListRegion()
?這時,通過刷新頁面可以查看getListRegion()獲取的信息
這樣方便核對response所返回的列表值
修改搜索框中的 通過輸入區域Id獲取對應信息?=> 通過下拉框的方式選擇對應區域信息
(注釋部分的代碼是修改前的代碼)
<el-form-item label="關聯的區域" prop="regionId"><!-- <el-inputv-model="queryParams.regionId"placeholder="請輸入關聯的區域ID"clearable@keyup.enter="handleQuery"/> --><el-select v-model="queryParams.regionId" placeholder="請選擇區域" clearable style="width: 100%"><el-optionv-for="item in regionList":key="item.id":label="item.regionName":value="item.id"/></el-select></el-form-item>
修改新增中的區域的輸入框為下拉框?
(注釋部分的代碼是修改前的代碼)
<el-form-item label="所屬區域" prop="regionId"><!-- <el-input v-model="form.regionId" placeholder="請輸入關聯的區域ID" /> --><el-select v-model="form.regionId" placeholder="請選擇關聯的區域"><el-optionv-for="item in regionList":key="item.id":label="item.regionName":value="item.id"/></el-select></el-form-item>
(3)對點位管理的中合作商部分進行修改
基本上與對點位管理的中所屬區域部分進行修改差不多;
對于復用率高的代碼,我們可以進行封裝,我們將在api下創建page.js
/* 查詢所有條件的對象 */
export const loadAllParams = reactive({pageNum: 1,pageSize: 10000,
});
如果使用的直接進行導入即可:
import {loadAllParams} from '@/api/page'
最終改造后的效果:
(4) 使用...替換詳細地址中內容過長的部分,當鼠標移動到上方會顯示完整的詳細地址
只需要在詳細地址這行上加上 show-over-tooltip屬性即可
2.6.2 點位管理中的設備相關改造
我們希望能夠看到每個點位的設備數,在查看詳情中顯示當前點位下的所有設備列表
還沒有創建設備的數據庫表,要根據分析先創建設備的數據庫表
關聯查詢:對于設備數量的統計,需要執行關聯查詢,在mapper層封裝
關聯實體:對于區域和合作商的數據,采用Mybatis提供的嵌套查詢功能
(1)創建Vo實體類
@Data
public class NodeVo extends Node {private Integer vmCount;private Region region;private Partner partner;
}
(2)mapper:
public List<NodeVo> selectNodeVoList(Node node);
(3)Mapper.xml:
<resultMap id="NodeVoResult" type="NodeVo"><result property="id" column="id" /><result property="nodeName" column="node_name" /><result property="address" column="address" /><result property="businessAreaType" column="business_area_type" /><result property="regionId" column="region_id" /><result property="partnerId" column="partner_id" /><result property="createTime" column="create_time" /><result property="updateTime" column="update_time" /><result property="createBy" column="create_by" /><result property="updateBy" column="update_by" /><result property="remark" column="remark" /><result property="vmCount" column="vm_count" /><association property="region" column="region_id" javaType="Region" select="com.dkd.manage.mapper.RegionMapper.selectRegionById"/><association property="partner" column="partner_id" javaType="Partner" select="com.dkd.manage.mapper.PartnerMapper.selectPartnerById"/></resultMap> <select id="selectNodeVoList" resultMap="NodeVoResult">SELECTn.*,COUNT(vm.id) AS vm_countFROMtb_node nLEFT JOINtb_vending_machine vm ON n.id = vm.node_id<where><if test="nodeName != null and nodeName != ''"> and n.node_name like concat('%', #{nodeName}, '%')</if><if test="regionId != null "> and n.region_id = #{regionId}</if><if test="partnerId != null "> and n.partner_id = #{partnerId}</if></where>GROUP BYn.id;</select>
(4)ServiceImpl:
@Overridepublic List<NodeVo> selectNodeVoList(Node node) {return nodeMapper.selectNodeVoList(node);}
?(5)Controller:
/*** 查詢點位管理列表*/@PreAuthorize("@ss.hasPermi('manage:node:list')")@GetMapping("/list")public TableDataInfo list(Node node){startPage();List<NodeVo> voList = nodeService.selectNodeVoList(node);return getDataTable(voList);}
修改前端的代碼部分:
最終展示效果:
?2.7 區域管理 通過 查看詳細信息 查看 區域信息 和 點位列表
引入listNode,目的是獲取相關的點位列表
import {listNode} from '@/api/manage/node'
?編寫相關函數?
const nodeList = ref([]);
const regionInfoOpen = ref(false);
/* 查看詳情操作按鈕*/
function getRegionInfo(row){//查看區域信息reset();const _id = row.idgetRegion(_id).then(response => {form.value = response.data;});//查看點位列表loadAllParams.id = row.idlistNode(loadAllParams).then(response => {nodeList.value = response.rows;})regionInfoOpen.value = true
}
添加修改后的對話框
效果顯示:
?
2.8 數據的完整性
?在區域表中進行刪除,會導致將區域表下的點位數一并刪除(ON DELETE CASCADE)
所以為了保證數據的完整性,我們在刪除區域之前如果該區域還有點位數則無法刪除。
級聯操作:
- 當主表中的行被刪除或更新時,可以設置外鍵約束來自動執行級聯操作。
- ON DELETE CASCADE:當主表的行被刪除時,所有依賴于該主鍵的外鍵行也將被刪除。
- ON UPDATE CASCADE:當主表的主鍵值被更新時,所有依賴于該主鍵的外鍵值也會相應更新。
- NO ACTION?或?RESTRICT:如果刪除或更新主鍵值會導致外鍵違反約束,則操作將被阻止。
將ON DELETE CASCADE 和 ON UPDATE CASCADE 都改為 ON ACTION
在GlobalException中添加處理異常信息的返回?
三、人員管理
需要員工區將設備投放到各個區域
3.1 數據庫設計
3.2 使用代碼生成器生成代碼
(1)創建人員管理的菜單?
(2)添加員工狀態的字典(1:啟動,0:禁用)?
?導入員工表和角色表
編輯tb_emp中的生成信息?
?
?編輯tb_role 中的生成信息?
最后是生成代碼并導入項目中
3.3 人員列表改造
對所顯示的主鍵修改label為序號,同時添加type = "index",width = "50"
將下圖的區域id和角色id的輸入框都修改為下拉框
角色的下拉框的數據通過獲取角色列表來確定,區域框也是如此(獲取列表需要考慮分頁的情況,所以需要獲取 loadAllParams)
import {listRole} from "@/api/manage/role";
import {listRegion} from "@/api/manage/region";
import {loadAllParams} from "@/api/page"
?將獲取到的區域列表存儲到regionList,角色列表存儲到roleList
const roleList = ref([]);
function getRoleList(){listRole(loadAllParams).then(response=>{roleList.value = response.rows;})
}const regionList = ref([]);
function getRegionList(){listRegion(loadAllParams).then(response=>{regionList.value = response.rows;})
}getRegionList()
getRoleList()
將輸入框修改為下拉框的代碼所示
注意:item的屬性命名,要根據F12中所獲取的屬性字段名相一致
<el-form-item label="所屬區域" prop="regionId"><!-- <el-input v-model="form.regionId" placeholder="請輸入所屬區域Id" /> --><el-select v-model="form.regionId" placeholder="請選擇區域" ><el-optionv-for="item in regionList":key="item.id":label="item.regionName":value="item.id"></el-option></el-select></el-form-item><el-form-item label="角色" prop="roleId"><!-- <el-input v-model="form.roleId" placeholder="請輸入角色id" /> --><el-select v-model="form.roleId" placeholder="請選擇角色"><el-optionv-for="item in roleList":key="item.roleId":label="item.roleName":value="item.roleId"></el-option></el-select></el-form-item>
修改后端代碼的添加和修改員工的代碼
?
添加啟動或禁用
<el-form-item label="是否啟用" prop="status"><el-radio-group v-model="form.status"><el-radio :label="0">禁用</el-radio><el-radio :label="1">啟用</el-radio></el-radio-group></el-form-item>
?
改造后的效果:
?
3.4 列表改造實現同步存儲
當修改區域名稱時,在人員信息所對應的區域名稱沒有同步發生改變
在emp的mapper中添加updateByRegionId方法
@Update("update tb_emp set region_name = #{regionName} where region_id = #{regionId}")public int updateByRegionId(@Param("regionName") String regionName, @Param("regionId") Long regionId);
這樣只需要在修改region的名稱時進行調用empMapper.updateByRegionId方法實現數據一致
加上@Transcational保證原子性
@Transactional(rollbackFor = Exception.class)@Overridepublic int insertRegion(Region region){region.setCreateTime(DateUtils.getNowDate());int result = regionMapper.insertRegion(region);empMapper.updateByRegionId(region.getRegionName(), region.getId());return result;}
四、阿里云OSS存儲文件
(1)設置 AK 和 SK
-
AK(Access Key):訪問密鑰是公開的標識符,它唯一地標識了用戶賬戶。它可以被認為是一個用戶名,用于在請求時識別調用者。
-
SK(Secret Key):密鑰是私密的,不應該公開分享或泄露。它類似于密碼,用于驗證發送請求的用戶是否是訪問密鑰的合法持有者。在發送API請求時,SK通常用于生成簽名,以確保請求的完整性和真實性。
以管理員的身份打開CMD命令行
配置系統變量:
set OSS_ACCESS_KEY_ID = 您的AK
set OSS_ACCESS_KEY_SECRET = 您的SK
(2)執行下面命令使其更改生效
setx OSS_ACCESS_KEY_ID = "%OSS_ACCESS_KEY_ID%"
set OSS_ACCESS_KEY_SECRET = "%OSS_ACCESS_KEY_SECRET%"
(3)執行下面命令,驗證變量是否生效
echo "%OSS_ACCESS_KEY_ID%"
echo "%OSS_ACCESS_KEY_SECRET%"
(4)引入阿里云OSS的依賴并參考示例使用
五、X-File-Storage
優勢:
????????X-File-Storage的設計目標之一就是為了簡化不同存儲平臺之間的遷移和集成工作。通過使用X-File-Storage,您可以在其統一的抽象層上操作文件,而不必直接與每個特定存儲平臺的API打交道。
????????這意味著,一旦您熟悉了X-File-Storage的API和使用方式,當您需要切換或添加新的存儲平臺時,您只需進行一些配置上的更改,而不需要重寫大量代碼來適應新的存儲平臺。X-File-Storage已經為您處理了與各種存儲平臺交互的復雜性。
使用步驟:
- X-File-Storage只需要導入自身的依賴和所使用云存儲平臺的依賴;
- 填寫根據X-File-Storage所提供的appllication.yml中的信息;
- 最后通過X-File-Storage提供的代碼方式實現文件上傳;