feat:增加docker配置
This commit is contained in:
5
Dockerfile
Normal file
5
Dockerfile
Normal file
@@ -0,0 +1,5 @@
|
||||
FROM nginx:1.27.0
|
||||
COPY dist/ /usr/share/nginx/html/
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
RUN echo 'Asia/Shanghai' > /etc/timezone
|
||||
18
docker-compose.yml
Normal file
18
docker-compose.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
name:
|
||||
sweet-hut
|
||||
|
||||
services:
|
||||
blog-ui:
|
||||
image: cxx/blog-ui:0.0.1
|
||||
container_name: blog-ui
|
||||
ports:
|
||||
- "82:80"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
networks:
|
||||
- sweet-hut
|
||||
restart: always
|
||||
|
||||
networks:
|
||||
sweet-hut:
|
||||
driver: bridge
|
||||
22
nginx.conf
Normal file
22
nginx.conf
Normal file
@@ -0,0 +1,22 @@
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
server_name _;
|
||||
|
||||
location /blog/ {
|
||||
alias /usr/share/nginx/html/;
|
||||
try_files $uri $uri/ /blog/index.html;
|
||||
}
|
||||
|
||||
location /blog-api/ {
|
||||
proxy_pass http://127.0.0.1:8082/;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc -b && vite build",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { cloudService } from './index'
|
||||
import { IBlog, IBlogCategory, IBlogComment, IBlogStats, IBlogVisit, INewBlog, IQueryBlog } from '@/types/blog'
|
||||
import { IBlog, IBlogCategory, IBlogComment, IBlogStats, IQueryBlog } from '@/types/blog'
|
||||
|
||||
import qs from 'qs'
|
||||
import { IPageRecord } from '@/types'
|
||||
|
||||
export const queryBlogApi = (currentPage: number, pageSize: number): Promise<IPageRecord<IBlog>> =>
|
||||
cloudService({
|
||||
url: '/blog-service/blog/page',
|
||||
url: '/blog-api/blog/page',
|
||||
method: 'get',
|
||||
params: { currentPage, pageSize }
|
||||
})
|
||||
|
||||
export const queryBlogByConditionApi = (query: IQueryBlog): Promise<IBlog[]> =>
|
||||
cloudService({
|
||||
url: '/blog-service/blog/condition',
|
||||
url: '/blog-api/blog/condition',
|
||||
method: 'get',
|
||||
params: query,
|
||||
paramsSerializer: (params) => {
|
||||
@@ -23,85 +23,37 @@ export const queryBlogByConditionApi = (query: IQueryBlog): Promise<IBlog[]> =>
|
||||
|
||||
export const queryBlogByIdApi = (id: number): Promise<IBlog> =>
|
||||
cloudService({
|
||||
url: `/blog-service/blog/content/${id}`,
|
||||
url: `/blog-api/blog/content/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryBlogCategoryApi = (): Promise<IBlogCategory[]> =>
|
||||
cloudService({
|
||||
url: '/blog-service/blog/category',
|
||||
url: '/blog-api/blog/category',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryBlogStatsApi = (): Promise<IBlogStats> =>
|
||||
cloudService({
|
||||
url: '/blog-service/blog/stats',
|
||||
url: '/blog-api/blog/stats',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryLatestBlogApi = (): Promise<IBlog[]> =>
|
||||
cloudService({
|
||||
url: '/blog-service/blog/latest',
|
||||
url: '/blog-api/blog/latest',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryBlogCommentApi = (blogId: number): Promise<IBlogComment[]> =>
|
||||
cloudService({
|
||||
url: `/blog-service/blog/comment/${blogId}`,
|
||||
url: `/blog-api/blog/comment/${blogId}`,
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const addBlogCommentApi = (blogComment: IBlogComment): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/blog-service/blog/comment',
|
||||
url: '/blog-api/blog/comment',
|
||||
method: 'put',
|
||||
data: blogComment
|
||||
})
|
||||
|
||||
export const queryAdminBlogApi = (currentPage: number,
|
||||
pageSize: number): Promise<IPageRecord<IBlog>> =>
|
||||
cloudService({
|
||||
url: '/admin-service/blog-manage/page',
|
||||
method: 'get',
|
||||
params: { currentPage, pageSize }
|
||||
})
|
||||
|
||||
export const queryAdminBlogByIdApi = (id: number): Promise<IBlog> =>
|
||||
cloudService({
|
||||
url: `/admin-service/blog-manage/content/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const queryAdminBlogCategoryApi = (): Promise<IBlogCategory[]> =>
|
||||
cloudService({
|
||||
url: '/admin-service/blog-manage/category',
|
||||
method: 'get'
|
||||
})
|
||||
|
||||
export const addBlogApi = (blog: INewBlog): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: '/admin-service/blog-manage',
|
||||
method: 'post',
|
||||
data: blog
|
||||
})
|
||||
|
||||
export const updateBlogApi = (id: number, blog: INewBlog): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/admin-service/blog-manage/${id}`,
|
||||
method: 'put',
|
||||
data: blog
|
||||
})
|
||||
|
||||
export const deleteBlogApi = (id: number): Promise<boolean> =>
|
||||
cloudService({
|
||||
url: `/admin-service/blog-manage/${id}`,
|
||||
method: 'DELETE'
|
||||
})
|
||||
|
||||
export const queryBlogVisitApi = (currentPage: number,
|
||||
pageSize: number): Promise<IPageRecord<IBlogVisit>> =>
|
||||
cloudService({
|
||||
url: '/admin-service/blog-manage/visit',
|
||||
method: 'get',
|
||||
params: { currentPage, pageSize }
|
||||
})
|
||||
|
||||
@@ -53,7 +53,7 @@ const changeDateEvent = async (value: Date) => {
|
||||
*/
|
||||
const viewBlogClick = async (index: number) => {
|
||||
const blogId = blogStore.blogList[index].id
|
||||
await router.push({ name: 'BlogDetail', params: { id: blogId } })
|
||||
await router.push({ name: 'DetailId', params: { id: blogId } })
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ onMounted(() => {
|
||||
* @param name 类别名称
|
||||
*/
|
||||
const viewBlogCategoryClick = async (name: string) => {
|
||||
await router.push({ name: 'BlogCategoryName', params: { name } })
|
||||
await router.push({ name: 'CategoryName', params: { name } })
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ onMounted(async () => {
|
||||
|
||||
const viewBlogClick = async (index: number) => {
|
||||
const blogId = blogStore.blogList[index].id
|
||||
await router.push({ name: 'BlogDetailId', params: { id: blogId } })
|
||||
await router.push({ name: 'DetailId', params: { id: blogId } })
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ onMounted(async () => {
|
||||
*/
|
||||
const readBlogClick = async (index: number) => {
|
||||
const blogId = blogStore.blogList[index].id
|
||||
await router.push({ name: 'BlogDetailId', params: { id: blogId } })
|
||||
await router.push({ name: 'DetailId', params: { id: blogId } })
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<el-menu router class="blog-menu-container">
|
||||
<el-menu-item index="/blog/overview">
|
||||
<el-menu-item index="/overview">
|
||||
<i class="fa fa-fw fa-home" />
|
||||
<span class="menu-title">首页</span>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item index="/blog/category">
|
||||
<el-menu-item index="/category">
|
||||
<i class="fa fa-fw fa-th" />
|
||||
<span class="menu-title">分类</span>
|
||||
<span class="value">{{ blogStore.blogStats.categoryCount }}</span>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item index="/blog/archive">
|
||||
<el-menu-item index="/archive">
|
||||
<i class="fa fa-fw fa-archive" />
|
||||
<span class="menu-title">归档</span>
|
||||
<span class="value">{{ blogStore.blogStats.blogCount }}</span>
|
||||
|
||||
@@ -61,14 +61,14 @@ const router = useRouter()
|
||||
* 点击查看博客归档按钮
|
||||
*/
|
||||
const viewBlogArchiveClick = () => {
|
||||
router.push('/blog/archive')
|
||||
router.push('/archive')
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击查看博客分类按钮
|
||||
*/
|
||||
const viewBlogCategoryClick = () => {
|
||||
router.push('/blog/category')
|
||||
router.push('/category')
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,6 +77,6 @@ const viewBlogCategoryClick = () => {
|
||||
*/
|
||||
const viewBlogClick = async (index: number) => {
|
||||
const blogId = blogStore.latestBlogList[index].id
|
||||
await router.push({ name: 'BlogDetail', params: { id: blogId } })
|
||||
await router.push({ name: 'DetailId', params: { id: blogId } })
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import BlogLayout from '@/layout/index.vue'
|
||||
import { getRoutersByModules } from 'vue3-common/utils/routerUtil'
|
||||
import { blogMeta } from '@/views/blog/meta'
|
||||
import { blogMeta } from '@/views/meta'
|
||||
|
||||
|
||||
const blogRoutes = getRoutersByModules(import.meta.glob('@/views/blog/**/*.vue'), BlogLayout, blogMeta)
|
||||
const blogRoutes = getRoutersByModules(import.meta.glob('@/views/**/*.vue'), BlogLayout, blogMeta)
|
||||
|
||||
export default blogRoutes
|
||||
|
||||
@@ -3,7 +3,7 @@ import { RouteRecordRaw } from 'vue-router'
|
||||
const constantRoutes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/',
|
||||
redirect: '/blog/overview'
|
||||
redirect: { path: '/overview' }
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
|
||||
import { setupRouteGuard } from 'vue3-common/utils/permissionUtil'
|
||||
|
||||
// 使用 import.meta.glob 自动导入所有 src/router 目录下的 .ts 文件
|
||||
const routeModules = import.meta.glob('./*.ts', { eager: true })
|
||||
@@ -10,11 +9,9 @@ const routes: RouteRecordRaw[] = Object.values(routeModules)
|
||||
.flat() // 扁平化数组,确保所有路由项都在一个数组中
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
history: createWebHashHistory('/blog/'),
|
||||
scrollBehavior: () => ({ top: 0 }),
|
||||
routes
|
||||
})
|
||||
|
||||
setupRouteGuard(router)
|
||||
|
||||
export default router
|
||||
|
||||
@@ -4,12 +4,11 @@ import {
|
||||
IBlogLatest, IBlogNestedComment, IBlogStats, INewBlog, IQueryBlog
|
||||
} from '@/types/blog'
|
||||
import {
|
||||
addBlogApi, addBlogCommentApi, deleteBlogApi, queryAdminBlogApi, queryAdminBlogByIdApi, queryAdminBlogCategoryApi,
|
||||
addBlogCommentApi,
|
||||
queryBlogApi, queryBlogByConditionApi, queryBlogByIdApi,
|
||||
queryBlogCategoryApi, queryBlogCommentApi, queryBlogStatsApi, queryLatestBlogApi, updateBlogApi
|
||||
queryBlogCategoryApi, queryBlogCommentApi, queryBlogStatsApi, queryLatestBlogApi
|
||||
} from '@/apis/blog.ts'
|
||||
import { IHandleApi } from 'vue3-common/types'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ImagePathEnum } from '@/types'
|
||||
import { flattenToTwoLevel } from '@/utils/blog/blogUtil.ts'
|
||||
|
||||
@@ -73,18 +72,6 @@ export const useBlogStore = defineStore('blog', {
|
||||
this.blogList = result.records
|
||||
this.pageInfo.totalSize = result.total
|
||||
},
|
||||
async queryMobileBlog() {
|
||||
const { currentPage, pageSize } = this.pageInfo
|
||||
const result = await queryBlogApi(currentPage, pageSize)
|
||||
this.blogList.push(...result.records)
|
||||
this.pageInfo.totalSize = result.total
|
||||
},
|
||||
async queryAdminBlog() {
|
||||
const { currentPage, pageSize } = this.adminPageInfo
|
||||
const result = await queryAdminBlogApi(currentPage, pageSize)
|
||||
this.blogList = result.records
|
||||
this.pageInfo.totalSize = result.total
|
||||
},
|
||||
async queryBlogByCondition(query: IQueryBlog) {
|
||||
this.blogList = await queryBlogByConditionApi(query)
|
||||
},
|
||||
@@ -93,9 +80,6 @@ export const useBlogStore = defineStore('blog', {
|
||||
await this.queryBlogComment(this.currentBlogId)
|
||||
this.blogNestedCommentList = flattenToTwoLevel(this.blogCommentList)
|
||||
},
|
||||
async queryAdminBlogById(id: number) {
|
||||
this.currentBlog = await queryAdminBlogByIdApi(id)
|
||||
},
|
||||
async queryBlogComment(blogId: number) {
|
||||
this.blogCommentList = await queryBlogCommentApi(blogId)
|
||||
},
|
||||
@@ -106,50 +90,12 @@ export const useBlogStore = defineStore('blog', {
|
||||
async queryBlogCategory() {
|
||||
this.blogCategoryList = await queryBlogCategoryApi()
|
||||
},
|
||||
async queryAdminBlogCategory() {
|
||||
this.blogCategoryList = await queryAdminBlogCategoryApi()
|
||||
},
|
||||
async queryBlogStats() {
|
||||
this.blogStats = await queryBlogStatsApi()
|
||||
},
|
||||
async queryLatestBlog() {
|
||||
this.latestBlogList = await queryLatestBlogApi()
|
||||
},
|
||||
async handleBlogApi(id?: number) {
|
||||
switch (this.blogApiType) {
|
||||
case 'ADD':
|
||||
await addBlogApi(this.newBlog)
|
||||
ElMessage.success('新增博客成功')
|
||||
break
|
||||
case 'UPDATE':
|
||||
await updateBlogApi(this.newBlog.id as number, this.newBlog)
|
||||
ElMessage.success('更新博客成功')
|
||||
break
|
||||
case 'DELETE':
|
||||
await deleteBlogApi(id as number)
|
||||
ElMessage.success('删除博客成功')
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
await this.refreshInfo()
|
||||
},
|
||||
async refreshInfo() {
|
||||
this.pageInfo.currentPage = 1
|
||||
await this.queryBlog()
|
||||
await this.queryBlogStats()
|
||||
await this.queryLatestBlog()
|
||||
},
|
||||
getEmptyBlog(): INewBlog {
|
||||
return {
|
||||
id: 0,
|
||||
category: '',
|
||||
content: '',
|
||||
isGreat: false,
|
||||
title: '',
|
||||
topValue: 0
|
||||
}
|
||||
},
|
||||
getEmptyBlogComment(): IBlogComment {
|
||||
return {
|
||||
blogId: 0,
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
<template>
|
||||
<div class="login-view">
|
||||
<div class="login-container">
|
||||
<div class="login-title">
|
||||
<span class="title">
|
||||
{{ loginInfo.title }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<common-login v-if="authStore.loginType === 'common'"
|
||||
class="animate__animated animate__bounceIn"/>
|
||||
<phone-login v-if="authStore.loginType === 'phone'"
|
||||
class="animate__animated animate__bounceIn"/>
|
||||
<email-login v-if="authStore.loginType === 'email'"
|
||||
class="animate__animated animate__bounceIn"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import CommonLogin from '@/components/Home/Login/CommonLogin.vue'
|
||||
import PhoneLogin from '@/components/Home/Login/PhoneLogin.vue'
|
||||
import EmailLogin from '@/components/Home/Login/EmailLogin.vue'
|
||||
import { useAuthStore } from '@/store/auth'
|
||||
import { onMounted, onUnmounted, reactive } from 'vue'
|
||||
|
||||
const authStore = useAuthStore()
|
||||
|
||||
const loginInfo = reactive({
|
||||
title: 'Sweet Hut'
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
authStore.isVerified = false
|
||||
// authStore.resetLoginForm()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
authStore.stopCountdown()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$form-item-width: 300px;
|
||||
$login-height: 500px;
|
||||
|
||||
.login-view {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
|
||||
.login-container {
|
||||
// height: $login-height;
|
||||
padding: 30px;
|
||||
border-radius: 15px;
|
||||
box-shadow: 2px 2px 5px #D3D3D3, 4px 4px 10px #A9A9A9;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1vh;
|
||||
|
||||
.login-title {
|
||||
margin-bottom: 20px;
|
||||
.title {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.common-login {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 1vh;
|
||||
|
||||
.login-form {
|
||||
.el-form-item {
|
||||
width: $form-item-width;
|
||||
}
|
||||
|
||||
.login-option {
|
||||
.el-form-item__content {
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login-type {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.login-others-type {
|
||||
margin-top: 5vh;
|
||||
width: 100%;
|
||||
|
||||
.el-divider {
|
||||
.el-divider__text {
|
||||
color: #A9A9A9;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
.type-list {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
|
||||
i {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
i:hover {
|
||||
cursor: pointer;
|
||||
filter: brightness(1.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login-register {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
span {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.phone-login, .email-login {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1vh;
|
||||
|
||||
.login-form {
|
||||
.el-form-item {
|
||||
width: $form-item-width;
|
||||
}
|
||||
|
||||
.code-item {
|
||||
.el-form-item__content {
|
||||
flex-wrap: nowrap;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,8 +1,5 @@
|
||||
import { IRouteMetaConfig } from 'vue3-common/types'
|
||||
|
||||
export const blogMeta: IRouteMetaConfig = {
|
||||
'/blog': {
|
||||
path: '/blog',
|
||||
redirect: '/blog/overview'
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,7 +30,7 @@ export default defineConfig({
|
||||
}
|
||||
}
|
||||
},
|
||||
base: './',
|
||||
base: '/blog/',
|
||||
resolve: {
|
||||
// 配置路径别名
|
||||
alias: {
|
||||
@@ -41,10 +41,10 @@ export default defineConfig({
|
||||
port: 5174,
|
||||
// 服务器代理 服务器没有部署Nginx的情况下使用
|
||||
proxy: {
|
||||
'/blog-service': {
|
||||
'/blog-api': {
|
||||
target: `http://${API_HOST}:8082`,
|
||||
changeOrigin: true,
|
||||
rewrite: (item) => item.replace(/^\/blog-service/, '')
|
||||
rewrite: (item) => item.replace(/^\/blog-api/, '')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user