目錄
一、產品模塊(products表)
1.1、添加產品(/adminapi/product/add)
1.2、產品列表(/adminapi/product/list)
1.3、編輯產品(/adminapi/product/update)
1.4、首頁產品聯動
二、前臺模塊
2.1、路由配置
2.3、新聞搜索
2.4、新聞選項卡
2.5、新聞詳情
2.6、產品與服務
三、總結
前言:
前端項目git地址:Enterprise Product Management System: 企業產品管理系統:web端展示、后臺進行添加信息,前端用的vue3+vuex。
后端項目git地址:Enterprise Product Management System Backend: 企業產品管理系統:后端項目,用的node +mysql
查看git記錄:"第一版"是只有后臺管理+admin/web分離的接口,"第二版"是將前臺頁面和后臺管理系統放在一起了,根據自己需要進行下載與切換。目前是"第二版"。
一、產品模塊(products表)
1.1、添加產品(/adminapi/product/add)
后端先創建一個products表
-- 創建products表
CREATE TABLE IF NOT EXISTS products (id INT AUTO_INCREMENT PRIMARY KEY,-- 1、傳統自增int主鍵title VARCHAR(50) NOT NULL UNIQUE,introduction TEXT,detail TEXT,cover VARCHAR(255),userId INT DEFAULT 1,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,edit_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 2、UUID作為主鍵
-- id CHAR(36) PRIMARY KEY DEFAULT (UUID())
-- 缺點:不連續,索引性能低于自增int
-- 3、時間戳作為主鍵
-- 4、帶前綴的自增編號(如 NEWS0001、PROD0001)
-- 每個表直接會重復?-- 插入測試產品數據
INSERT INTO products (title, introduction, detail, cover,userId) VALUES
('標題1','簡要描述1','詳細描述1','/avatar/admin.jpg', 1),
('標題2','簡要描述1','詳細描述2','/avatar/editor.jpg', 2)
1.2、產品列表(/adminapi/product/list)
1.3、編輯產品(/adminapi/product/update)
前三個接口幾乎可以照搬vue3+node.js+mysql寫接口(一)_node.js mysql vue-CSDN博客,除了字段不一樣。
1.4、首頁產品聯動
當添加產品成功后,首頁就會產生相應的輪播圖
<el-carousel:interval="4000"type="card"height="400px"v-if="loopList.length > 0"><el-carousel-item v-for="item in loopList" :key="item.id"><div:style="{backgroundImage: `url(http://localhost:3000${item.cover})`,backgroundSize: 'cover',height: '400px',}"><h3>{{ item.title }}</h3></div></el-carousel-item>
</el-carousel>
<style lang="scss" scoped>
.el-carousel__item h3 {color: white;opacity: 0.75;line-height: 200px;margin: 0;text-align: center;
}
.el-carousel__item:nth-child(2n) {background-color: #99a9bf;
}
.el-carousel__item:nth-child(2n + 1) {background-color: #d3dce6;
}
</style>
二、前臺模塊
這里介紹的是單獨開發一個項目,而不是和后臺管理放在一起的。
2.1、路由配置
import { createRouter, createWebHashHistory } from "vue-router";
import Home from "../views/Home.vue";
import News from "../views/News.vue";
import NewsDetails from "../views/NewsDetails";
import Product from "../views/Product.vue";
const routes = [{path: "/",name: "home",component: Home,},{path: "/news",name: "news",component: News,},{path: "/news-detail/:id",name: "NewsDetails",component: NewsDetails,},{path: "/product",name: "product",component: Product,},
];
const router = createRouter({history: createWebHashHistory(),routes,
});
export default router;
2.2、NavBar組件
<template><div class="navbar"><el-menu:default-active="route.fullPath"class="el-menu-demo"mode="horizontal"router><el-menu-item index="/">首頁</el-menu-item><el-menu-item index="/news">新聞中心</el-menu-item><el-menu-item index="/product">產品與服務</el-menu-item><el-menu-item index="" @click="handleClick">登錄</el-menu-item></el-menu><div class="right">企業門戶管理系統</div></div>
</template>
<script setup>
import { useRoute } from "vue-router";
const route = useRoute();
const handleClick = () => {window.location = "http://localhost:8081/";
};
</script>
<style lang="scss" scoped>
.navbar {position: sticky;top: 0px;z-index: 999;
}
.right {position: fixed;top: 0;right: 20px;width: 160px;height: 59px;line-height: 59px;text-align: center;
}
</style>
2.3、新聞搜索
<div class="search-center"><el-popovertitle="檢索結果"placement="bottom"width="50%":visible="popVisible"><template #reference><el-inputv-model="searhText"placeholder="請輸入新聞關鍵字":prefix-icon="Search"type="search"size="large"@input="popVisible = true"@blur="popVisible = false"/></template><div v-if="newsListFilter.length"><divv-for="(data, index) in newsListFilter":key="data.id"class="search-item"@click="handleClick(data.id)">{{ index + 1 }} . {{ data.title }}</div></div><div v-else><el-empty description="暫無新聞" :image-size="50" /></div></el-popover></div>
// 根據搜索內容過濾
const newsListFilter = computed(() => {return newsList.value.filter((item) => {return item.title.includes(searhText.value);});
});
2.4、新聞選項卡
<el-tabs v-model="whichTab" style="margin: 20px"><el-tab-panev-for="item in options":key="item.value":label="item.label":name="item.value"><el-row :gutter="20"><el-col :span="18"><divv-for="data in tabnews[item.value]":key="data.id"style="padding: 10px"><el-card:body-style="{ padding: '0px' }"shadow="hover"@click="handleClick(data.id)"><divclass="tab-image":style="{backgroundImage: `url(http://localhost:3000${data.cover})`,}"></div><div style="padding: 14px; float: left"><span>{{ data.title }}</span><div class="edit-time"><span>{{ formatTime.getTime(data.edit_time) }}</span></div></div></el-card></div></el-col><el-col :span="6"><el-timeline style="padding-top: 16px"><el-timeline-itemv-for="data in tabnews[item.value]":key="data.id":timestamp="formatTime.getTime(data.edit_time)">{{ data.title }}</el-timeline-item></el-timeline></el-col></el-row></el-tab-pane></el-tabs>
借助lodash組裝數組,將其分為三類(后臺創建時的三類選項)
import _ from "lodash";//npm i lodash
// 組裝選項卡數據
// groupBy用法:https://www.lodashjs.com/docs/lodash.groupBy
const tabnews = computed(() =>_.groupBy(newsList.value, (item) => item.category)
);
2.5、新聞詳情
點擊右側新聞,此時左側內容更新:這里相當于自己跳轉到自己,onMounted只會觸發一次,需要監聽路由變化的話,需要使用watchEffect
const stop = watchEffect(async () => {if (!route.params.id) return;const res = await axios.get(`/adminapi/news/list/${route.params.id}`);const res1 = await axios.get(`/adminapi/news/topList?limit=4`); //可以用vuex存儲主頁的;也可以由后端返回最新的前四個數據currentNews.value = res.data[0];topNews.value = res1.data;
});
// 頁面銷毀時取消監聽
onBeforeUnmount(() => {stop();
});
const router = useRouter();
// 跳轉詳情
// 注意:這里相當于自己跳轉到自己,onMounted只會觸發一次,需要監聽路由變化的話,需要使用watchEffect
const handleClick = (id) => {router.push(`/news-detail/${id}`);
};
2.6、產品與服務
其實就是將后端的數據返回,前端根據指定樣式渲染即可
三、總結
后端:
post請求參數:用body接收;
get請求參數:接收URL路徑中的參數用params接收、查詢字符串參數用query接收
前端:
1、model屬性:讓表單的驗證功能正常工作,再結合rules+prop
2、如果表單form是ref或者reactive對象,直接賦值,會改變原始數據tableData,需要深拷貝
3、文件上傳時,前端拿到的是file文件【二進制】格式,傳給后端時一般用FormData形式,此時需要改變消息頭:multipart/form-data
4、當一個頁面自己跳轉到自己,onMounted只會觸發一次,需要監聽路由變化的話,需要使用watchEffect,在頁面銷毀時取消監聽。