谷粒商城官网_尚硅谷谷粒商城电商项目(谷粒金刚PRO手柄)
谷粒商城_01_環境搭建
谷粒商城_02_Nacos、網關
谷粒商城_03_前端基礎
商品服務-分類管理
查出所有分類以及子分類
后端編寫
1、定義接口查詢所有數據:gulimall-product的com.liu.gulimall.product.controller.CategoryController添加如下方法
/** * 商品三級分類 * * @author liujianyu * @email 380404812@qq.com * @date 2021-12-09 19:15:00 */
@RestController
@RequestMapping("product/category")
public class CategoryController {
@Autowired
private CategoryService categoryService;
/** * 查出所有分類以及子分類,以樹形結構組裝起來 */
@RequestMapping("/list/tree")
public R list(){
List<CategoryEntity> entities = categoryService.listWithTree();
return R.ok().put("data", entities);
}
}
2、在service層中創建方法 listWithTree
/** * 商品三級分類 * * @author liujianyu * @email 380404812@qq.com * @date 2021-12-09 18:29:39 */
public interface CategoryService extends IService<CategoryEntity> {
PageUtils queryPage(Map<String, Object> params);
/** * 將數據以樹形分類,分出三級 * @return */
List<CategoryEntity> listWithTree();
}
3、在service層的Impl中實現方法
- 最重要的是商品實體中需要多一個字段,children,為了放此分類的子分類
- 先把所有商品查出來然后根據數據庫字段父id查出,沒有父id的一級商品,然后在遞歸找子分類
- 主要理解流式編程:filter、map、sorted、collect
- 一級分類有二級,二級有三級,所以是一個遞歸的方式
@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {
// @Autowired
// private CategoryDao categoryDao;
// ServiceImpl<CategoryDao, CategoryEntity>已經幫我們注入了dao,就不用自己注入了
@Override
public List<CategoryEntity> listWithTree() {
// 1 查出所有分類
List<CategoryEntity> entities = baseMapper.selectList(null);
// 2 組裝成父子的樹形結構
List<CategoryEntity> level1Menus = entities.stream().filter((categoryEntity) ->{
// 過濾
// long類型的比較不要直接使用==,要用到longValue()來比較
return categoryEntity.getParentCid().longValue() == 0;} // 過濾只要父id等于0的數據,也就是一級分類
).map((categoryEntity)->{
// 為過濾后的一級分類的每一個數據設置他的子分類
categoryEntity.setChildren(getChildrens(categoryEntity,entities));
return categoryEntity;}
).sorted((categoryEntity1,categoryEntity2)->{
// 升序排序根據字段sort來讓sort小的的排前面 由于categoryEntity1可能已經為空null了,所以先判斷
return (categoryEntity1.getSort() == null? 0: categoryEntity1.getSort())
-
(categoryEntity2.getSort() == null?0:categoryEntity2.getSort());
}).collect(Collectors.toList()); // 將過濾的數據收集成數組
return level1Menus;
}
// 遞歸查找所有菜單的子菜單,把當前分類,和總分類傳進來
private List<CategoryEntity> getChildrens(CategoryEntity root, List<CategoryEntity> all) {
List<CategoryEntity> children = all.stream().filter(categoryEntity -> {
// 過濾取出父id等于當前分類的數據
return categoryEntity.getParentCid().longValue() == root.getCatId().longValue();
}).map(categoryEntity -> {
// 每一個子分類還有可能有子分類
// 1 找到子菜單
categoryEntity.setChildren(getChildrens(categoryEntity, all));
return categoryEntity;
}).sorted((menu1, menu2) -> {
// 2 菜單的排序 由于menu可能已經為空null了,所以先判斷
return (menu1.getSort() == null?0:menu1.getSort()) - (menu2.getSort() == null?0:menu2.getSort());
}).collect(Collectors.toList());
return children;
}
}
前端展示
1、創建商品系統的目錄,以及內容轉發的路由
數據庫同步數據
2、根據人人開源策略,根據路由product/category 來請求product-category,比如sys-role具體的視圖在renren-fast-vue/views/modules/sys/role.vue 所以要自定義我們的product/category視圖的話,就是創建mudules/product/category.vue,根據策略創建product文件,在文件下創建category.vue組件,這樣請求路由就會跳轉到這個組件中,
3、編寫category.vue組件
- 可以模仿人人開源的組件方式,包括里面怎么轉發,怎么數據交互等。
- 采用Element UI來開發,采用樹形控件來管理三級數據
<template>
<el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick" ></el-tree>
</template>
<script> export default {
data() {
return {
data: [], defaultProps: {
children: "children", label: "label", }, }; }, methods: {
handleNodeClick(data) {
console.log(data); }, getMenus(data) {
// 自定義方法 this.$http({
// htpp請求 url: this.$http.adornUrl("/product/category/list/tree"), // 請求后端的接口 method: "get", }).then((data) => {
// 成功了之后的操作 console.log("請求數據," + data); }); }, }, created() {
// 加載組件的時候就調用改方法 this.getMenus(); }, }; </script>
<style lang="scss" scoped> </style>
4、我們的數據肯定是從后端取出來,所以要請求gulimall-product服務后端的接口,但是現在請求的是:人人開源的接口,所以修改前端配置:renren-fast-vue\static\config\index.js中修改,但是我們gulimall-product服務可能在很多服務器上,所以每次都要修改端口很麻煩,直接交給網關來做,讓網關跟我們去請求服務器
由于我們想要訪問的是:http://localhost:10000/product/category/list/tree這個請求,而且這里面的10000端口也存在多服務問題,所以采用網關來轉發請求。http://localhost:88/product/category/list/tree
服務注冊
-
我們登錄有驗證碼,這個是renrne-fast服務的數據,所以先注冊renrne-fast服務
-
通過網關把請求轉發給后端renren-fast服務,所以先讓網關發現服務,也就是注冊服務到注冊中心去
1、在renren-fast中導入的依賴【如果依賴無法徹底刪除,復制全文,刪除原來的,重新創建pom文件】
2、在配置文件中配置,服務名稱和注冊中心地址
3、注冊到注冊中心中,加入注解:@EnableDiscoveryClient
4、啟動nacos,發現服務
配置網關
- 驗證碼前端請求:http://localhost:88/api/captcha.jpg 我們需要的是:http://localhost:8080/renren-fast/captcha.jpg
- 配置網關
spring:
cloud:
gateway:
# 路由規則
routes:
- id: admin_route
uri: lb://renren-fast # 路由給renren-fast,lb代表負載均衡
predicates: # 什么情況下路由給它
- Path=/api/** # 默認前端項目都帶上api前綴,但是這樣還是請求的:http://localhost:88/api/..我們想要請求 http://localhost:8080/renren-fast/..,所以加上過濾器
# 所以在前端index.js中改為 window.SITE_CONFIG['baseUrl'] = 'http://localhost:88/api';
filters: # 過濾器,
- RewritePath=/api/(?<segment>.*),/renren-fast/$\{
segment}
- 啟動renren-fast、gulimall-gateway、nacos,發現驗證出現
503問題
- 檢查服務是否配置到注冊中心,并且保證在同一命名空間
- 檢查配置是否正確,路徑,服務名等
- 在gateway中更換alibaba依賴版本為2.2.0;
- 200,沒有圖片:將renren-fast的跨域配置中的
allowedOrigins("*")改為allowedOriginPatterns("*")
- 當驗證碼成功后登錄遇到跨域問題
跨域
已攔截跨源請求:同源策略禁止讀取位于 http://localhost:88/api/sys/login 的遠程資源。(原因:CORS 頭缺少 ‘Access-Control-Allow-Origin’)。
這是一種跨域問題。訪問的域名和端口和原來的請求不同,請求就會被限制
跨域:指的是瀏覽器不能執行其他網站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對js施加的安全限制。(ajax可以)
同源策略:是指協議,域名,端囗都要相同,其中有一個不同都會產生跨域;
跨域流程
- 瀏覽器先發送OPTIONS,請求服務器能否跨域,服務器需要配置允許跨域,然后瀏覽器在發送真實請求
解決跨域
- 我們現在學習常用,自己后端編寫配置
- 在網關中定義
GulimallCorsConfiguration類,該類用來做過濾,允許所有的請求跨域。【注意】需要把renren-fast的跨域注解掉,因為先走我們網關跨域再走renrne-fast就重復了,然后就成功解決跨域
/** * @author ljy * @version 1.0.0 * @Description TODO * @createTime 2021年12月12日 22:46:00 */
@Configuration // gateway
public class GulimallCorsConfiguration {
@Bean // 添加過濾器
public CorsWebFilter corsWebFilter(){
// 基于url跨域,選擇reactive包下的
UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
// 跨域配置信息
CorsConfiguration corsConfiguration = new CorsConfiguration();
// 允許跨域的頭
corsConfiguration.addAllowedHeader("*");
// 允許跨域的請求方式
corsConfiguration.addAllowedMethod("*");
// 允許跨域的請求來源
// corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedOriginPattern("*");
// 是否允許攜帶cookie跨域
corsConfiguration.setAllowCredentials(true);
// 任意url都要進行跨域配置
source.registerCorsConfiguration("/**",corsConfiguration);
return new CorsWebFilter(source);
}
}
服務注冊
- 在顯示商品系統/分類信息的時候,出現了404異常,請求的http://localhost:88/api/product/category/list/tree不存在
這是因為網關上所做的路徑映射不正確,映射后的路徑為http://localhost:8080/renren-fast/product/category/list/tree
但是只有通過http://localhost:10000/product/category/list/tree路徑才能夠正常訪問,所以會報404異常。 - 所以我們注冊gulimall-product到服務中心,重新再配置網關
1、編寫配置文件,加上配置中心地址和服務名稱
2、添加注解@EnableDiscoveryClient
3、添加spring-cloud-starter-alibaba-nacos-discovery服務發現依賴
配置網關
- 在網關配置中添加gulimall-product服務的路由配置,并且要寫在renren-fast的前面, 路由的順序有影響,把更具體的路由請求放前面
- id: product_route
uri: lb://gulimall-product
predicates:
- Path=/api/product/**
filters:
- RewritePath=/api/(?<segment>.*),/$\{
segment}
再訪問http://localhost:88/api/product/category/list/tree,數據正常出現,數據正常顯示,就應該編寫頁面了
<template>
<!-- :dataA="data" 表示dataA跟我們組件中的data進行綁定-->
<el-tree :data="menus" :props="defaultProps" >
</el-tree>
</template>
<script> export default {
data() {
return {
menus: [], // 請求后端返回的數據 defaultProps: {
children: "children", // 表示children顯示data的children屬性 label: "name", // label指的是顯示數據中的哪個屬性這里就顯示data中的name屬性,這些label、children都可以在官方文檔 中查看的 }, }; }, methods: {
getMenus(data) {
// 自定義方法 this.$http({
// htpp請求 url: this.$http.adornUrl("/product/category/list/tree"), // 請求后端的接口 method: "get", // }).then((data) => { 由于我們的data是一個對象,我們只需要拿到其中的data屬性的數據,所以要把data對象解構出來 }).then(({
data }) => {
// 成功了之后的操作 // console.log("請求數據," + data); +號不能顯示出數據 // console.log("請求數據," , data); ,才可以顯示出數據 console.log("請求數據,", data.data); // 解構data對象取出data屬性 this.menus = data.data; // 將后端取出的數據給到組件中的menus屬性 }); } }, created() {
// 加載組件的時候就調用改方法 this.getMenus(); }, }; </script>
<style lang="scss" scoped> </style>
刪除數據
后端接口
- com.liu.gulimall.product.controller.CategoryController
/** * 刪除 * @RequestBody 獲取到請求體里面的內容,必須發送Post請求 * springMVC會自動將請求體的數據(json),轉為對應的對象(Long[]) */
@RequestMapping("/delete")
public R delete(@RequestBody Long[] catIds){
// categoryService.removeByIds(Arrays.asList(catIds));
// 刪除之前需要判斷待刪除的菜單那是否被別的地方所引用。
categoryService.removeMenuByIds(Arrays.asList(catIds));
return R.ok();
}
- com/liu/gulimall/product/service/impl/CategoryServiceImpl.java
@Override
public void removeMenuByIds(List<Long> asList) {
// TODO 先檢查當前的菜單是否被別的地方所引用
// TODO表示代辦事項,以后可以直接在最下方查看代辦
// 開發期間多用邏輯刪除:使用字段來標識
baseMapper.deleteBatchIds(asList);
}
邏輯刪除
- 多數時候,我們并不希望刪除數據,而是標記它被刪除了,這就是邏輯刪除; 邏輯刪除是mybatis-plus 的內容,會在項目中配置一些內容,告訴此項目執行delete語句時并不刪除,只是標志位 可以設置show_status為0,標記它已經被刪除。
- 官網:https://mp.baomidou.com/ 中有提到邏輯刪除的用法
1、配置mybatis-plus
# MapperScan
# sql映射文件位置
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
global-config:
db-config:
id-type: auto
logic-delete-value: 1 # 表示邏輯已刪除
logic-not-delete-value: 0
2、添加注解@TableLogic
/** * 是否顯示[0-不顯示,1顯示],由于我們數據庫和mybatis-plus規則相反,所以我們自己定義邏輯刪除,1表示未刪除 */
@TableLogic(value = "1",delval = "0")
private Integer showStatus;
測試
http://localhost:88/api/product/category/delete
- 可以查看sql信息,我們需要配置日志
logging:
level:
com.liu.gulimall: debug
==> Preparing: UPDATE pms_category SET show_status=0 WHERE cat_id IN ( ? ) AND show_status=1
==> Parameters: 1000(Long)
<== Updates: 1
前端請求
- 直接采用Element UI跟我們提供的一些組件,然后結合renrne-vue中的一些請求方式即可
刪除數據
- 只有沒有子分類的才允許有刪除的功能
- 在刪除上綁定事件,彈出提示框,確定刪除才會給后端發請求走數據庫并且是邏輯刪除
- 刪除完后需要彈出成功消息,刷新新頁面,并且展開剛才被刪除的父分類
新增分類
- 只要有子分類的才允許有此功能
- 綁定事件,彈出彈框,在彈框中內嵌表格,給屬性置為默認值,確定添加,給后端發請求
- 彈出消息,刷新頁面,展開次分類
修改分類
- 自定義一個按鈕,每一數據都有此功能
- 綁定事件,和新增共用一個彈框,只需判斷彈框的類型,并且需要將此分類的數據先從后端請求(每次都拿數據庫,避免高并發)回顯到彈框的內嵌表格中,只回顯需要修改的屬性,并且只將修改的屬性請求到后端
- 彈出提示,刷新頁面,展開父分類
拖拽效果
-
避免誤操作,是否開啟拖拽需要設置一個按鈕switch標簽來確定
-
可以直接拖動每一分類來改變每一分類的順序,以及其父和子分類,并且需要判斷是否可以拖拽到此分類
-
官網:拖拽完成觸發方法,不同拖拽,會有不同的父id,確定拖拽的新順序,將所有改動的分類都放到一個數組里面
-
由于不能反復請求后端,設置批量保存按鈕,觸發事件請求后端,將數組傳給后端
-
彈出提示,刷新頁面,展開所有的父分類,并將數組置空
批量刪除
- 獲取被選中的元素,獲取元素的id
- 彈出警告框,確定刪除,請求后端,將元素id數組傳入
- 刷新菜單
<template>
<div>
<el-switch v-model="draggable" active-text="開啟拖拽" inactive-text="關閉拖拽" >
</el-switch>
<el-button @click="batchSave()" v-if="draggable">批量保存</el-button>
<el-button type="danger" @click="batchDelete">批量刪除</el-button>
<!-- :dataA="data" 表示dataA跟我們組件中的data進行綁定-->
<!-- :expand-on-click-node表示禁止網上冒泡,官網都有解釋,直接在官網ctrl+f搜索即可 -->
<!--el-tree中的 @node-click="handleNodeClick" 刪除沒什么用-->
<!-- show-checkbox表示該標簽是否可以被選中 -->
<!-- node-key表示每個節點的唯一標識,catId是我們各個data中唯一的屬性,也就是數據庫中的主鍵 -->
<!-- :default-expanded-keys表示動態綁定需要展開的節點id,因為當我們刪除的時候,不想讓父節點折疊起來,所以定義讓刪除節點的父節點都展開 -->
<!-- :draggable="draggable"是否可以拖動-->
<!-- :allow-drop="allowDrop"是否允許拖動比如層級關系等等。有三個情況,分別表示放置在目標節點前、插入至目標節點和放置在目標節點后, -->
<!-- @node-drop拖拽成功觸發的方法-->
<!-- ref="menuTree" 方便指定是哪個組件,主要是批量刪除的時候用到 -->
<el-tree node-key="catId" show-checkbox :data="menus" :props="defaultProps" :expand-on-click-node="false" :default-expanded-keys="expandedKey" :draggable="draggable" :allow-drop="allowDrop" @node-drop="handleDrop()" ref="menuTree" >
<!-- 官網找的span slot-scope插槽機制,每一個元素后面都會格外加上是這個span-->
<!-- node代表當前的節點也即是對象,node.label就是當前節點的name,data就是此節點的數據 -->
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{
{ node.label }}</span>
<span>
<!-- @click點擊就會跳轉到我們的方法-->
<!-- 由于只要一級二級才有append操作,所以加上v-if="node.level<=2",node的level<=2表示為一二級-->
<el-button v-if="node.level <= 2" type="text" size="mini" @click="() => append(data)" >
Append
</el-button>
<!-- 自己定義修改按鈕,每一個菜單都要顯示 -->
<el-button type="text" size="mini" @click="edit(data)">
Edit
</el-button>
<!--childNodes是node的子節點數組屬性, v-if="node.childNodes==0"表示沒有子節點才有delete按鈕 -->
<el-button v-if="node.childNodes == 0" type="text" size="mini" @click="() => remove(node, data)" >
Delete
</el-button>
</span>
</span>
</el-tree>
<!-- :visible.sync 為true顯示該彈框 -->
<!-- close-on-click-modal 是否點擊彈框外邊就會讓彈框消失 -->
<el-dialog :title="title" :visible.sync="dialogVisible" width="30%" :close-on-click-modal="false" >
<!-- 彈框嵌套 官網 model表單綁定對象 category我們自己的分類對象-->
<el-form :model="category">
<el-form-item label="分類名">
<el-input v-model="category.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="圖標">
<el-input v-model="category.icon" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="計量單位">
<el-input v-model="category.productUnit" autocomplete="off" ></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<!-- 取消就把他設為false即可 -->
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="submitData()">確 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script> export default {
data() {
return {
pCid: [], // 是否可以拖動 draggable: false, updateNodes: [], // 最大的層級 maxLevel: 0, // 彈框的標題 title: "", // 彈框的類型,因為修改和添加復用一個彈框 dialogType: "", // 添加的分類對象 category: {
// 里面的屬性都是根據后端數據庫中來定義的 name: "", parentCid: 0, catLevel: 0, showStatus: 1, sort: 0, catId: null, icon: "", productUnit: "", }, // 表單對象 // 是否彈框,默認為false dialogVisible: false, // 需要展開的id expandedKey: [], // 分類對象 menus: [], defaultProps: {
children: "children", // 表示children顯示data的children屬性 label: "name", // label指的是顯示數據中的哪個屬性這里就顯示data中的name屬性,這些label、children都可以在官方文檔中查看的 }, }; }, methods: {
// 批量刪除 batchDelete() {
let catIds = []; // 拿到組件menuTree let checkedNodes = this.$refs.menuTree.getCheckedNodes(); console.log("被選中的元素", checkedNodes); for (let i = 0; i < checkedNodes.length; i++) {
catIds.push(checkedNodes[i].catId); } this.$confirm(`是否批量刪除【${
catIds}】菜單?`, "提示", {
confirmButtonText: "確定", // 點擊確定就調用then cancelButtonText: "取消", type: "warning", }) .then(() => {
this.$http({
url: this.$http.adornUrl("/product/category/delete"), method: "post", data: this.$http.adornData(catIds, false), }) .then(({
data }) => {
this.$message({
type: "success", message: "菜單批量刪除成功!", }); // 刷新出新的菜單 this.getMenus(); }) .catch(() => {
}); }) .catch(() => {
}); }, // 批量修改 batchSave() {
this.$http({
url: this.$http.adornUrl("/product/category/update/sort"), method: "post", data: this.$http.adornData(this.updateNodes, false), }) .then(({
data }) => {
this.$message({
type: "success", message: "菜單順序修改成功!", }); // 刷新出新的菜單 this.getMenus(); // 設置需要默認展開的菜單 this.expandedKey = this.pCid; this.updateNodes = []; this.maxLevel = 0; // this.pCid = 0; }) .catch(() => {
}); }, // 拖拽完成觸發方法,draggingNode當前拖拽的節點,拖拽到哪個節點dropNode,dropType類型:前面,后面,里面 handleDrop(draggingNode, dropNode, dropType, ev) {
console.log("handleDrop: ", draggingNode, dropNode, dropType); //1 當前節點最新的父節點 let pCid = 0; let siblings = null; // 不同拖拽,會有不同的父id if (dropType == "before" || dropType == "after") {
pCid = dropNode.parent.data.catId == undefined ? 0 : dropNode.parent.data.catId; siblings = dropNode.parent.childNodes; } else {
pCid = dropNode.data.catId; siblings = dropNode.childNodes; } this.pCid.push(pCid); //2 當前拖拽節點的最新順序 for (let i = 0; i < siblings.length; i++) {
if (siblings[i].data.catId == draggingNode.data.catId) {
// 如果遍歷的是當前正在拖拽的節點 let catLevel = draggingNode.level; if (siblings[i].level != draggingNode.level) {
// 當前節點的層級發生變化 catLevel = siblings[i].level; // 修改他子節點的層級 this.updateChildNodeLevlel(siblings[i]); } this.updateNodes.push({
catId: siblings[i].data.catId, sort: i, parentCid: pCid, catLevel: catLevel, }); } else {
this.updateNodes.push({
catId: siblings[i].data.catId, sort: i }); } } //3 當前拖拽節點的最新層級 console.log("updateNodes", this.updateNodes); }, updateChildNodeLevlel(node) {
if (node.childNodes.length > 0) {
for (let i = 0; i < node.childNodes.length; i++) {
var cNode = node.childNodes[i].data; this.updateNodes.push({
catId: cNode.catId, catLevel: node.childNodes[i].level, }); this.updateChildNodeLevlel(node.childNodes[i]); } } }, // 判斷是否可以拖動 allowDrop(draggingNode, dropNode, type) {
//1 被拖動的當前節點以及所在的父節點總層數不能大于3 //1 被拖動的當前節點總層數 // draggingNode當前正在拖動的節點 // dropNode 拖到哪個節點,也就是draggingNode和dropNode同級 console.log("allowDrop:", draggingNode, dropNode, type); // 返回總層數 var level = this.countNodeLevel(draggingNode); // 當前正在拖動的節點+父節點所在的深度不大于3即可 // draggingNode.level表示層級一級標題為1,三級標題為3 // 當前深度 let deep = Math.abs(this.maxLevel - draggingNode.level) + 1; console.log("this.maxLevel", this.maxLevel); console.log("深度:", deep); // this.maxLevel // innner表示拖到里面 if (type == "innner") {
// console.log( // `this.maxLevel: ${this.maxLevel}; draggingNode.data.catLevel:${draggingNode.data.catLevel};dropNode.level: ${dropNode.level}` // ); return deep + dropNode.level <= 3; } else {
return deep + dropNode.parent.level <= 3; } }, countNodeLevel(node) {
// 找到所有子節點,求出最大深度 // 如果當前節點不為null,并且有子節點 if (node.childNodes != null && node.childNodes.length > 0) {
for (let i = 0; i < node.childNodes.length; i++) {
// 找到最大的深度 if (node.childNodes[i].level > this.maxLevel) {
this.maxLevel = node.childNodes[i].level; } this.countNodeLevel(node.childNodes); } } }, // 獲取所有的菜單 getMenus(data) {
// 自定義方法 this.$http({
// htpp請求 url: this.$http.adornUrl("/product/category/list/tree"), // 請求后端的接口 method: "get", // }).then((data) => { 由于我們的data是一個對象,我們只需要拿到其中的data屬性的數據,所以要把data對象解構出來 }).then(({
data }) => {
// 成功了之后的操作 // console.log("請求數據," + data); +號不能顯示出數據 // console.log("請求數據," , data); ,才可以顯示出數據 console.log("請求數據,", data.data); // 解構data對象取出data屬性 this.menus = data.data; // 將后端取出的數據給到組件中的menus屬性 }); }, // 添加分類方法 addCategory() {
console.log("提交的三級分類數據", this.category); // 提交對象到后端,給后端發請求 this.$http({
url: this.$http.adornUrl("/product/category/save"), method: "post", data: this.$http.adornData(this.category, false), }).then(({
data }) => {
// 提交成功 this.$message({
message: "保存成功", type: "success", }); // 保存完后,關閉彈框 this.dialogVisible = false; // 刷新出新的菜單 this.getMenus(); // 展開添加菜單的父菜單 this.expandedKey = [this.category.parentCid]; }); }, // 修改分類數據 editCategory() {
// 只往后端發需要更新的數據,沒有發送的數據為null后端則不會更新 // 從category取出數據,解構對象! var {
catId, name, icon, productUnit } = this.category; this.$http({
url: this.$http.adornUrl("/product/category/update"), method: "post", // 這些數據都是對應的后端實體字段 data: this.$http.adornData({
catId, name, icon, productUnit }, false), }) .then(({
data }) => {
this.$message({
type: "success", message: "菜單修改成功!", }); // 關閉對話框 this.dialogVisible = false; // 刷新出新的菜單 this.getMenus(); // 設置需要默認展開的菜單 this.expandedKey = [this.category.parentCid]; }) .catch(() => {
}); }, submitData() {
if (this.dialogType == "add") {
this.addCategory(); } if (this.dialogType == "edit") {
this.editCategory(); } }, append(data) {
console.log("append----", data); // 打開彈框 this.dialogVisible = true; this.dialogType = "add"; // 將彈框類型變為添加 this.title = "添加分類"; // 取出當前節點的一些屬性賦給要填加的節點 this.category.parentCid = data.catId; // 父id this.category.catLevel = data.catLevel * 1 + 1; // 層級 // 由于我們修改過后的category回顯時設置了屬性,所以我們添加的時候要清空這些屬性,讓他等于默認值 this.category.catId = null; // 為null,表示后端添加的時候不加上id,自增 this.category.name = null; this.category.icon = ""; this.category.productUnit = ""; this.category.sort = 0; this.category.showStatus = 1; // this.dialogVisible = true; }, edit(data) {
console.log("要修改的數據", data); // 將彈框類型變為修改 this.dialogType = "edit"; this.title = "修改分類"; // 打開彈框 this.dialogVisible = true; // 修改框內顯示要修改的name this.category.name = data.name; // 發送請求獲取節點最新的數據,因為有并發 this.$http({
url: this.$http.adornUrl(`/product/category/info/${
data.catId}`), method: "get", }).then(({
data }) => {
// 請求成功 這個data是從服務器拿過來的data console.log("要回顯得數據", data); // 因為服務器返回的data是數據對象,里面還有一個data才是分類對象,所以data.data.name this.category.name = data.data.name; this.category.catId = data.data.catId; this.category.icon = data.data.icon; this.category.productUnit = data.data.productUnit; //由于修改完后要展開父菜單,所以把父id也回顯 this.category.parentCid = data.data.parentCid; // this.dialogVisible = true; }); }, remove(node, data) {
// 定義我們要刪除的id數組,data.catId數據的id,也就是數據庫中的id var ids = [data.catId]; // 在刪除之前顯示一個彈框,官網 this.$confirm(`此操作將永久刪除【${
data.name}】文件, 是否繼續?`, "提示", {
confirmButtonText: "確定", cancelButtonText: "取消", type: "warning", }) .then(() => {
// 確定刪除才會真正請求刪除業務 // 模仿renrne-vue的Post請求寫法即可 this.$http({
// adornUrl是renrne-vue定義的工具類:renren-fast-vue\src\utils\httpRequest.js url: this.$http.adornUrl("/product/category/delete"), // 請求的地址 method: "post", // 發送Post請求 data: this.$http.adornData(ids, false), }).then((data) => {
// 刪除成功,發送一個消息提示 this.$message({
message: "恭喜你,刪除成功", type: "success", }); // 刪除成功后,要刷新頁面 this.getMenus(); // 重新請求方法,就會獲取到最新的menus,然而el-tree又和menus是雙向綁定的,所以會實時切換 // 刷新后我們想要展開剛才被刪除的節點的父結點 // node當前節點,中有個parent屬性里面放的是父節點的內容,父節點中的data就是父節點的數據對象,然后再拿到父節點的id即可 this.expandedKey = [node.parent.data.catId]; }); }) .catch(() => {
console.log("取消刪除"); }); console.log(node, data); // 打印當前結點和當前數據 }, }, created() {
// 加載組件的時候就調用改方法 this.getMenus(); }, }; </script>
<style lang="scss" scoped> </style>
- 設置全局代碼片段,將我們常用的代碼片段提出來
- 文件–首選項–用戶片段–即可添加
- 比如下面,下次直接寫httpget+回車,就會快捷生成http-get請求里面的片段
"http-get請求": {
"prefix": "httpget",
"body": [
"this.\\$http({",
"url: this.\\$http.adornUrl(''),",
"method: 'get',",
"params: this.\\$http.adornParams({})",
"}).then(({ data }) => {",
"})"
],
"description": "httpGet請求"
},
"http-post請求": {
"prefix": "httppost",
"body": [
"this.\\$http({",
"url: this.\\$http.adornUrl(''),",
"method: 'post',",
"data: this.\\$http.adornData(data, false)",
"}).then(({ data }) => { });"
],
"description": "httpPOST請求"
}
- 修改的時候只提交我們需要修改的數據
總結
以上是生活随笔為你收集整理的谷粒商城官网_尚硅谷谷粒商城电商项目(谷粒金刚PRO手柄)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android Camera 拍照的两个
- 下一篇: IDEA 打不开怎么办 ?「建议收藏」(