feat(back): 后台布局、书籍加载完成
This commit is contained in:
parent
fe388551db
commit
1a5453bb32
1
package-lock.json
generated
1
package-lock.json
generated
@ -11,6 +11,7 @@
|
|||||||
"@ant-design/icons-vue": "^7.0.1",
|
"@ant-design/icons-vue": "^7.0.1",
|
||||||
"ant-design-vue": "^4.2.6",
|
"ant-design-vue": "^4.2.6",
|
||||||
"axios": "^1.8.2",
|
"axios": "^1.8.2",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "^4.5.0",
|
"vue-router": "^4.5.0",
|
||||||
"vue3-slide-verify": "^1.1.6",
|
"vue3-slide-verify": "^1.1.6",
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
"@ant-design/icons-vue": "^7.0.1",
|
"@ant-design/icons-vue": "^7.0.1",
|
||||||
"ant-design-vue": "^4.2.6",
|
"ant-design-vue": "^4.2.6",
|
||||||
"axios": "^1.8.2",
|
"axios": "^1.8.2",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "^4.5.0",
|
"vue-router": "^4.5.0",
|
||||||
"vue3-slide-verify": "^1.1.6",
|
"vue3-slide-verify": "^1.1.6",
|
||||||
|
10
src/App.vue
10
src/App.vue
@ -1,9 +1,19 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
import zhCN from 'ant-design-vue/es/locale/zh_CN';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import 'dayjs/locale/zh-cn';
|
||||||
|
|
||||||
|
// 设置 dayjs 的语言为中文
|
||||||
|
dayjs.locale('zh-cn');
|
||||||
|
|
||||||
|
// 定义响应式数据
|
||||||
|
const locale = zhCN;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template style="width: 100%;height: 100%;margin: 0;padding: 0">
|
<template style="width: 100%;height: 100%;margin: 0;padding: 0">
|
||||||
|
<a-config-provider :locale="locale">
|
||||||
<router-view style="width: 100%;height: 100%"></router-view>
|
<router-view style="width: 100%;height: 100%"></router-view>
|
||||||
|
</a-config-provider>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
24
src/apis/apis_book.js
Normal file
24
src/apis/apis_book.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// apis_book.js
|
||||||
|
|
||||||
|
// 获取所有图书
|
||||||
|
import {get, post,put, deleteRequest} from "./api.js";
|
||||||
|
|
||||||
|
// 分页查询(查询参数通过URL传递)
|
||||||
|
export const getBooks = async (data) => {
|
||||||
|
return get(`/book/books`,data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 新增(POST)
|
||||||
|
export const addBook = async (bookData) => {
|
||||||
|
return post("/book/books", bookData);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 更新(PUT,注意路径拼接ID)
|
||||||
|
export const updateBook = async (bookId, bookData) => {
|
||||||
|
return put(`/book/books/${bookId}`, bookData); // 关键修正:拼接ID
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除(DELETE,注意路径拼接ID)
|
||||||
|
export const deleteBook = async (bookId) => {
|
||||||
|
return deleteRequest(`/book/books/${bookId}`); // 关键修正:拼接ID
|
||||||
|
};
|
71
src/components/back/layout/AsideVue.vue
Normal file
71
src/components/back/layout/AsideVue.vue
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<template>
|
||||||
|
<div style="width: 100%;height: 100%">
|
||||||
|
<a-menu
|
||||||
|
v-model:openKeys="openKeys"
|
||||||
|
v-model:selectedKeys="selectedKeys"
|
||||||
|
style="width: 100%;height: 100%"
|
||||||
|
mode="inline"
|
||||||
|
:theme="theme"
|
||||||
|
:items="items"
|
||||||
|
@click="handleMenuClick"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { h, ref } from 'vue';
|
||||||
|
import {
|
||||||
|
MailOutlined,
|
||||||
|
CalendarOutlined,
|
||||||
|
AppstoreOutlined,
|
||||||
|
SettingOutlined,
|
||||||
|
} from '@ant-design/icons-vue';
|
||||||
|
import {useRouter} from "vue-router";
|
||||||
|
const router = useRouter();
|
||||||
|
const theme = ref('light');
|
||||||
|
const selectedKeys = ref(['1']);
|
||||||
|
const openKeys = ref(['sub1']);
|
||||||
|
const items = ref([
|
||||||
|
{
|
||||||
|
key: '1',
|
||||||
|
icon: () => h(AppstoreOutlined),
|
||||||
|
label: '首页',
|
||||||
|
title: '首页',
|
||||||
|
path: '/back/index',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2',
|
||||||
|
icon: () => h(CalendarOutlined),
|
||||||
|
label: '书籍管理',
|
||||||
|
title: '书籍管理',
|
||||||
|
path: '/back/admin/book',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'sub1',
|
||||||
|
icon: () => h(SettingOutlined),
|
||||||
|
label: '系统管理',
|
||||||
|
title: '系统管理',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
key: '3',
|
||||||
|
label: '用户管理',
|
||||||
|
title: '用户管理',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '3',
|
||||||
|
icon: () => h(MailOutlined),
|
||||||
|
label: '消息',
|
||||||
|
title: '消息',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const changeTheme = checked => {
|
||||||
|
theme.value = checked ? 'dark' : 'light';
|
||||||
|
};
|
||||||
|
const handleMenuClick = ({ key }) => {
|
||||||
|
const item = items.value.find(item => item.key === key);
|
||||||
|
if (item && item.path) {
|
||||||
|
router.push(item.path);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
59
src/components/back/layout/HeaderVue.vue
Normal file
59
src/components/back/layout/HeaderVue.vue
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<template>
|
||||||
|
<a-row>
|
||||||
|
<a-col flex="100px">
|
||||||
|
<span style="font-size: 24px; font-weight: bold">Libroro</span>
|
||||||
|
</a-col>
|
||||||
|
<a-col flex="auto" style="text-align: right">
|
||||||
|
{{ userName }}
|
||||||
|
<a-button style="margin-left: 1em;" @click="handleLogout" danger type="primary">退出登录</a-button>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { useStore } from 'vuex';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import { computed, onMounted } from 'vue';
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
// 获取用户信息
|
||||||
|
const userInfo = computed(() => store.state.user.info);
|
||||||
|
|
||||||
|
// 初始化检查登录状态
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
// 调用初始化方法(根据你的 Vuex 模块结构调整 action 路径)
|
||||||
|
await store.dispatch('user/initialize');
|
||||||
|
|
||||||
|
// 检查用户信息是否存在
|
||||||
|
if (!userInfo.value) {
|
||||||
|
await router.push('/auth');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('初始化失败:', error);
|
||||||
|
await router.push('/auth');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 安全获取用户名的计算属性
|
||||||
|
const userName = computed(() => userInfo.value?.name || '');
|
||||||
|
|
||||||
|
// 退出登录处理函数
|
||||||
|
const handleLogout = async () => {
|
||||||
|
try {
|
||||||
|
await store.dispatch('user/logout');
|
||||||
|
await router.push('/auth');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('退出登录失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 可以在这里添加一些样式 */
|
||||||
|
a-button {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -4,6 +4,8 @@ import router from "./router/index.js";
|
|||||||
import Antd from 'ant-design-vue';
|
import Antd from 'ant-design-vue';
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import 'ant-design-vue/dist/reset.css';
|
import 'ant-design-vue/dist/reset.css';
|
||||||
|
import store from "@/store/index.js";
|
||||||
let app = createApp(App)
|
let app = createApp(App)
|
||||||
|
app.use(store)
|
||||||
app.use(router).use(Antd).mount('#app')
|
app.use(router).use(Antd).mount('#app')
|
||||||
|
|
||||||
|
@ -14,7 +14,13 @@ const isAdmin = computed(() => store.state.user.info?.isAdmin || false)
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await store.dispatch('user/initialize')
|
await store.dispatch('user/initialize')
|
||||||
})
|
})
|
||||||
|
// 跳转后台
|
||||||
|
const goToBackend = () => {
|
||||||
|
console.log("go to backend")
|
||||||
|
router.push({
|
||||||
|
path: '/back',
|
||||||
|
})
|
||||||
|
}
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
// 调用 Vuex action
|
// 调用 Vuex action
|
||||||
store.dispatch('user/logout')
|
store.dispatch('user/logout')
|
||||||
@ -98,7 +104,7 @@ const handleBorrow = (book) => {
|
|||||||
|
|
||||||
|
|
||||||
<p style="text-align: center;">
|
<p style="text-align: center;">
|
||||||
<span class="inline-btn"><a-button type="primary">进入后台</a-button></span>
|
<span class="inline-btn"><a-button @click="goToBackend()" type="primary">进入后台</a-button></span>
|
||||||
<span class="inline-btn"><a-button type="primary" danger @click="logout()">退出登录</a-button></span>
|
<span class="inline-btn"><a-button type="primary" danger @click="logout()">退出登录</a-button></span>
|
||||||
</p>
|
</p>
|
||||||
</a-card>
|
</a-card>
|
||||||
|
5
src/pages/back/BackIndex.vue
Normal file
5
src/pages/back/BackIndex.vue
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
</script>
|
0
src/pages/back/BackUser.vue
Normal file
0
src/pages/back/BackUser.vue
Normal file
333
src/pages/back/BookVueAdmin.vue
Normal file
333
src/pages/back/BookVueAdmin.vue
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
<template>
|
||||||
|
<div class="book-management">
|
||||||
|
<div style="width: 100%;height: 10%;text-align: left">
|
||||||
|
<a-button type="primary" @click="openAdd">
|
||||||
|
添加图书
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
<div style="height: 80%;">
|
||||||
|
<a-table
|
||||||
|
:data-source="dataSource"
|
||||||
|
:columns="columns"
|
||||||
|
:pagination="pagination"
|
||||||
|
:loading="loading"
|
||||||
|
:scroll="{ x: '100%' }"
|
||||||
|
@change="handleTableChange"
|
||||||
|
bordered
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'action'">
|
||||||
|
<a-button type="link" @click="openEdit(record)">编辑</a-button>
|
||||||
|
<a-popconfirm
|
||||||
|
title="确定要删除这本图书吗?"
|
||||||
|
@confirm="handleDelete(record.id)"
|
||||||
|
>
|
||||||
|
<a-button type="link" danger>删除</a-button>
|
||||||
|
</a-popconfirm>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
<a-modal
|
||||||
|
v-model:open="visible"
|
||||||
|
:title="isEdit ? '编辑图书' : '添加图书'"
|
||||||
|
@ok="handleSubmit"
|
||||||
|
:confirm-loading="confirmLoading"
|
||||||
|
>
|
||||||
|
<a-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="formState"
|
||||||
|
:rules="rules"
|
||||||
|
layout="vertical"
|
||||||
|
>
|
||||||
|
<a-form-item label="图书名称" name="name">
|
||||||
|
<a-input v-model:value="formState.name"/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="作者" name="author">
|
||||||
|
<a-input v-model:value="formState.author"/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="出版日期" name="publishDate">
|
||||||
|
<a-date-picker
|
||||||
|
v-model:value="formState.publishDate"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="简介" name="description">
|
||||||
|
<a-textarea v-model:value="formState.description"/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {reactive, ref, onMounted} from 'vue';
|
||||||
|
import {message} from 'ant-design-vue';
|
||||||
|
import {
|
||||||
|
getBooks,
|
||||||
|
addBook,
|
||||||
|
updateBook,
|
||||||
|
deleteBook
|
||||||
|
} from '@/apis/apis_book.js';
|
||||||
|
|
||||||
|
// 表格数据
|
||||||
|
const dataSource = ref([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
const pagination = reactive({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 表单相关
|
||||||
|
const visible = ref(false);
|
||||||
|
const isEdit = ref(false);
|
||||||
|
const confirmLoading = ref(false);
|
||||||
|
const formRef = ref();
|
||||||
|
const formState = reactive({
|
||||||
|
id: undefined,
|
||||||
|
name: '',
|
||||||
|
author: '',
|
||||||
|
publishDate: null,
|
||||||
|
description: '',
|
||||||
|
});
|
||||||
|
const columns = reactive([
|
||||||
|
{
|
||||||
|
title: '图书名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
sorter: (a, b) => a.name.localeCompare(b.name), // 支持按图书名称排序
|
||||||
|
ellipsis: true, // 超长文本省略显示
|
||||||
|
width: 200, // 设置列宽
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '作者',
|
||||||
|
dataIndex: 'author',
|
||||||
|
key: 'author',
|
||||||
|
sorter: (a, b) => a.author.localeCompare(b.author), // 支持按作者排序
|
||||||
|
ellipsis: true,
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '国际标准书号(ISBN)',
|
||||||
|
dataIndex: 'isbn',
|
||||||
|
key: 'isbn',
|
||||||
|
ellipsis: true,
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '内部图书编码',
|
||||||
|
dataIndex: 'code',
|
||||||
|
key: 'code',
|
||||||
|
ellipsis: true,
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '出版社',
|
||||||
|
dataIndex: 'publisher',
|
||||||
|
key: 'publisher',
|
||||||
|
sorter: (a, b) => a.publisher.localeCompare(b.publisher), // 支持按出版社排序
|
||||||
|
ellipsis: true,
|
||||||
|
width: 200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '出版日期',
|
||||||
|
dataIndex: 'publication_date',
|
||||||
|
key: 'publication_date',
|
||||||
|
sorter: (a, b) => new Date(a.publication_date) - new Date(b.publication_date), // 支持按出版日期排序
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '版次',
|
||||||
|
dataIndex: 'edition',
|
||||||
|
key: 'edition',
|
||||||
|
sorter: (a, b) => a.edition - b.edition, // 支持按版次排序
|
||||||
|
width: 80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '定价(元)',
|
||||||
|
dataIndex: 'price',
|
||||||
|
key: 'price',
|
||||||
|
sorter: (a, b) => a.price - b.price, // 支持按定价排序
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '分类',
|
||||||
|
dataIndex: 'category',
|
||||||
|
key: 'category',
|
||||||
|
sorter: (a, b) => a.category.localeCompare(b.category), // 支持按分类排序
|
||||||
|
filters: [
|
||||||
|
// 可以根据实际数据动态生成筛选选项
|
||||||
|
{text: 'I247.5/悬疑小说', value: 'I247.5/悬疑小说'},
|
||||||
|
],
|
||||||
|
onFilter: (value, record) => record.category.includes(value),
|
||||||
|
ellipsis: true,
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '总数量',
|
||||||
|
dataIndex: 'num',
|
||||||
|
key: 'num',
|
||||||
|
sorter: (a, b) => a.num - b.num, // 支持按总数量排序
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '库存量',
|
||||||
|
dataIndex: 'stock',
|
||||||
|
key: 'stock',
|
||||||
|
sorter: (a, b) => a.stock - b.stock, // 支持按库存量排序
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '是否绝版',
|
||||||
|
dataIndex: 'is_out_of_print',
|
||||||
|
key: 'is_out_of_print',
|
||||||
|
render: (text) => (text === 1 ? '是' : '否'),
|
||||||
|
sorter: (a, b) => a.is_out_of_print - b.is_out_of_print, // 支持按是否绝版排序
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
dataIndex: 'create_time',
|
||||||
|
key: 'create_time',
|
||||||
|
sorter: (a, b) => new Date(a.create_time) - new Date(b.create_time), // 支持按创建时间排序
|
||||||
|
width: 180,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '最后更新时间',
|
||||||
|
dataIndex: 'update_time',
|
||||||
|
key: 'update_time',
|
||||||
|
sorter: (a, b) => new Date(a.update_time) - new Date(b.update_time), // 支持按最后更新时间排序
|
||||||
|
width: 180,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
fixed: 'right',
|
||||||
|
width: 150,
|
||||||
|
// render: (_, record) => (
|
||||||
|
// // 这里可以添加具体的操作按钮,如编辑、删除等
|
||||||
|
// <div>
|
||||||
|
// <a-button type="primary" size="small">编辑</a-button>
|
||||||
|
// <a-button type="danger" size="small" style="margin-left: 8px">删除</a-button>
|
||||||
|
// </div>
|
||||||
|
// ),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
// 表单验证规则
|
||||||
|
const rules = reactive({
|
||||||
|
name: [
|
||||||
|
{required: true, message: '请输入图书名称', trigger: 'blur'},
|
||||||
|
],
|
||||||
|
author: [
|
||||||
|
{required: true, message: '请输入作者姓名', trigger: 'blur'},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// 生命周期
|
||||||
|
onMounted(() => {
|
||||||
|
fetchData();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取数据
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
const res = await getBooks({
|
||||||
|
page: pagination.current,
|
||||||
|
pageSize: pagination.pageSize,
|
||||||
|
});
|
||||||
|
console.log(res);
|
||||||
|
|
||||||
|
dataSource.value = res.data.list;
|
||||||
|
pagination.total = res.data.total;
|
||||||
|
} catch (error) {
|
||||||
|
message.error('获取数据失败');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 分页变化处理
|
||||||
|
const handleTableChange = (pag) => {
|
||||||
|
pagination.current = pag.current;
|
||||||
|
pagination.pageSize = pag.pageSize;
|
||||||
|
fetchData();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开添加模态框
|
||||||
|
const openAdd = () => {
|
||||||
|
isEdit.value = false;
|
||||||
|
resetForm();
|
||||||
|
visible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开编辑模态框
|
||||||
|
const openEdit = (record) => {
|
||||||
|
isEdit.value = true;
|
||||||
|
Object.assign(formState, record);
|
||||||
|
visible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交表单
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
try {
|
||||||
|
await formRef.value.validate();
|
||||||
|
confirmLoading.value = true;
|
||||||
|
|
||||||
|
if (isEdit.value) {
|
||||||
|
await updateBook(formState.id, formState);
|
||||||
|
message.success('修改成功');
|
||||||
|
} else {
|
||||||
|
await addBook(formState);
|
||||||
|
message.success('添加成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
visible.value = false;
|
||||||
|
fetchData();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('提交失败:', error);
|
||||||
|
message.error('操作失败');
|
||||||
|
} finally {
|
||||||
|
confirmLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除处理
|
||||||
|
const handleDelete = async (id) => {
|
||||||
|
try {
|
||||||
|
await deleteBook(id);
|
||||||
|
message.success('删除成功');
|
||||||
|
fetchData();
|
||||||
|
} catch (error) {
|
||||||
|
message.error('删除失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 重置表单
|
||||||
|
const resetForm = () => {
|
||||||
|
formRef.value?.resetFields();
|
||||||
|
Object.assign(formState, {
|
||||||
|
id: undefined,
|
||||||
|
name: '',
|
||||||
|
author: '',
|
||||||
|
publishDate: null,
|
||||||
|
description: '',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.book-management {
|
||||||
|
padding: 1em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: #fff;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-form-item {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -20,7 +20,17 @@ const routes = [
|
|||||||
path: '/auth',
|
path: '/auth',
|
||||||
name: 'AuthView',
|
name: 'AuthView',
|
||||||
component: () => import('../views/AuthView.vue'),
|
component: () => import('../views/AuthView.vue'),
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
name:'BackView',
|
||||||
|
path:'/back',
|
||||||
|
component:()=>import('../views/BackView.vue'),
|
||||||
|
redirect:'/back/index',
|
||||||
|
children:[
|
||||||
|
{name:'BackIndex',path:'/back/index',component:()=>import('../pages/back/BackIndex.vue')},
|
||||||
|
{name:'BackUser',path:'user',component:()=>import('../pages/back/BackUser.vue')},
|
||||||
|
{name:'BackBookAdmin',path:'/back/admin/book',component:()=>import('../pages/back/BookVueAdmin.vue')},
|
||||||
|
]},
|
||||||
];
|
];
|
||||||
|
|
||||||
// 创建路由实例
|
// 创建路由实例
|
||||||
|
@ -1,6 +1,17 @@
|
|||||||
import service from '@/apis/axios';
|
import service from '@/apis/axios';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import {auth_logout} from "@/apis/apis_auth.js";
|
import {auth_logout} from "@/apis/apis_auth.js";
|
||||||
|
// 清除会话的辅助函数
|
||||||
|
const clearSession = (state, commit) => {
|
||||||
|
state.info = null;
|
||||||
|
state.lastLogin = null;
|
||||||
|
localStorage.removeItem('userInfo');
|
||||||
|
if (state.refreshTimer) {
|
||||||
|
clearTimeout(state.refreshTimer);
|
||||||
|
state.refreshTimer = null;
|
||||||
|
}
|
||||||
|
commit('CLEAR_SESSION');
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
@ -18,13 +29,14 @@ export default {
|
|||||||
state.lastLogin = new Date().toISOString();
|
state.lastLogin = new Date().toISOString();
|
||||||
},
|
},
|
||||||
CLEAR_SESSION(state) {
|
CLEAR_SESSION(state) {
|
||||||
state.info = null;
|
// state.info = null;
|
||||||
state.lastLogin = null;
|
// state.lastLogin = null;
|
||||||
localStorage.removeItem('userInfo');
|
// localStorage.removeItem('userInfo');
|
||||||
if (state.refreshTimer) {
|
// if (state.refreshTimer) {
|
||||||
clearTimeout(state.refreshTimer);
|
// clearTimeout(state.refreshTimer);
|
||||||
state.refreshTimer = null;
|
// state.refreshTimer = null;
|
||||||
}
|
// }
|
||||||
|
clearSession(state, () => {});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@ -44,8 +56,9 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
CLEAR_SESSION({ commit }) {
|
CLEAR_SESSION({ commit }) {
|
||||||
commit('CLEAR_SESSION');
|
// commit('CLEAR_SESSION');
|
||||||
localStorage.removeItem('userInfo');
|
// localStorage.removeItem('userInfo');
|
||||||
|
clearSession(this.state, commit);
|
||||||
},
|
},
|
||||||
async logout({commit}) {
|
async logout({commit}) {
|
||||||
//向后端发起退出登录的请求
|
//向后端发起退出登录的请求
|
||||||
|
@ -1,11 +1,49 @@
|
|||||||
<script setup>
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<a-layout>
|
||||||
|
<a-layout-header class="layout-header"><header-vue/></a-layout-header>
|
||||||
|
<a-layout>
|
||||||
|
<a-layout-sider class="layout-sider"><aside-vue/></a-layout-sider>
|
||||||
|
<a-layout-content class="layout-content"><router-view></router-view></a-layout-content>
|
||||||
|
</a-layout>
|
||||||
|
<a-layout-footer class="layout-footer"></a-layout-footer>
|
||||||
|
</a-layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<script setup>
|
||||||
|
|
||||||
|
import HeaderVue from "@/components/back/layout/HeaderVue.vue";
|
||||||
|
import AsideVue from "@/components/back/layout/AsideVue.vue";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.layout-header {
|
||||||
|
text-align: left;
|
||||||
|
color: #fff;
|
||||||
|
height: 64px;
|
||||||
|
padding-inline: 50px;
|
||||||
|
line-height: 64px;
|
||||||
|
background-color: #87b9ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-content {
|
||||||
|
text-align: center;
|
||||||
|
min-height: 120px;
|
||||||
|
line-height: 120px;
|
||||||
|
color: #fff;
|
||||||
|
background-color: rgb(243, 255, 249);
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-sider {
|
||||||
|
text-align: center;
|
||||||
|
width: 256px;
|
||||||
|
line-height: 120px;
|
||||||
|
color: #fff;
|
||||||
|
background-color: rgba(95, 183, 255, 0.54);
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-footer {
|
||||||
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #87b9ff;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user