试一下

This commit is contained in:
dmz 2025-12-05 23:12:03 +08:00
parent b936c8e0ca
commit 93e373040f
20 changed files with 1646 additions and 0 deletions

8
amms_front/jsconfig.json Normal file
View File

@ -0,0 +1,8 @@
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
},
"exclude": ["node_modules", "dist"]
}

View File

@ -0,0 +1,41 @@
import axios from '@/utils/request'
// 查询收藏列表
export function listItemCollection(query) {
return axios.get('/itemCollection/list',{
params: {
...query
}
})
}
// 查询全部收藏列表
export function listAllItemCollection(query) {
return axios.get('/itemCollection/listAll', {
params: {
...query
}
})
}
// 查询收藏详细
export function getItemCollection(id) {
return axios.get('/itemCollection/info/' + id)
}
// 新增收藏
export function addItemCollection(data) {
return axios.post('/itemCollection/add', {
...data
})
}
// 修改收藏
export function updateItemCollection(data) {
return axios.put('/itemCollection', data)
}
// 删除收藏
export function delItemCollection(id) {
return axios.delete('/itemCollection/' + id)
}

View File

@ -0,0 +1,14 @@
import request from '@/utils/request'
// 登录方法
export function login(username, password) {
const data = {
username,
password
}
return request({
url: '/sysUser/login',
method: 'post',
data: data
})
}

View File

@ -0,0 +1,319 @@
<template>
<el-container class="main-container">
<!-- 内部容器使用水平排列 -->
<el-container class="horizontal-container">
<!-- 左侧菜单栏 -->
<el-aside width="200px" class="sidebar">
<div class="title">
<h4>邺城博物馆管理系统</h4>
</div>
<el-menu
active-text-color="#0B7285"
class="el-menu-vertical-demo"
:default-active="$route.path"
:unique-opened="true"
text-color="#585858"
:router="true"
style="height: calc(100vh - 60px);"
>
<template v-for="menu in adminMenuList" :key="menu.label">
<el-sub-menu v-if="menu.children && menu.children.length" :index="menu.label">
<template #title>
<el-icon><component :is="menu.icon" /></el-icon>
<span>{{ menu.label }}</span>
</template>
<el-menu-item
v-for="child in menu.children"
:key="child.route"
:index="child.route"
:route="child.route"
>
<span>{{ child.label }}</span>
</el-menu-item>
</el-sub-menu>
<el-menu-item v-else :index="menu.route" :route="menu.route">
<el-icon><component :is="menu.icon" /></el-icon>
<span>{{ menu.label }}</span>
</el-menu-item>
</template>
</el-menu>
</el-aside>
<!-- 右侧内容区域 - 包含header和main -->
<el-container class="right-content">
<!-- 顶部header - 放在右侧内容区域的顶部 -->
<el-header class="header">
<div class="user">
<div class="avator">
<el-dropdown trigger="click">
<div class="img">
<img style="width: 100%; height: 100%;" :src="getFilePrefix + avatar" alt="" />
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="handleUpdatePwd">修改密码</el-dropdown-item>
<el-dropdown-item @click="handleUserInfo">个人信息</el-dropdown-item>
<el-dropdown-item @click="handleLogout">
<span style="color: brown;">退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</el-header>
<!-- 主内容区域 -->
<el-main class="main-content">
<el-card class="content-card">
<RouterView />
</el-card>
</el-main>
</el-container>
</el-container>
<!-- 个人中心对话框 -->
<el-dialog title="修改密码" v-model="updatePwdOpen" width="400px" append-to-body>
<el-form ref="updatePwdRef" :model="updatePwdForm" :rules="updatePwdRules" label-width="80px">
<el-form-item label="旧密码" prop="oldPwd">
<el-input type="password" v-model="updatePwdForm.oldPwd" placeholder="请输入旧密码" />
</el-form-item>
<el-form-item label="新密码" prop="newPwd">
<el-input type="password" v-model="updatePwdForm.newPwd" placeholder="请输入新密码" />
</el-form-item>
<el-form-item label="确认密码" prop="confirmPwd">
<el-input type="password" v-model="updatePwdForm.confirmPwd" placeholder="请输入确认密码" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitUpdatePwd"> </el-button>
<el-button @click="handleCancelUpdatePwd"> </el-button>
</div>
</template>
</el-dialog>
</el-container>
</template>
<script setup>
import { ref, reactive, toRefs, getCurrentInstance } from 'vue'
import { DataAnalysis, Collection, Calendar, Message, Picture, User, School } from '@element-plus/icons-vue'
import { RouterView } from 'vue-router'
import { removeToken } from '@/utils/token'
import { updatePwd } from '@/api/sysUser';
import Cookies from 'js-cookie';
const avatar = ref(Cookies.get('avatar'))
const { proxy } = getCurrentInstance()
const adminMenuList = ref([
{ label: '数据统计', route: '/admin/statisticalAnalysis', icon: DataAnalysis },
{ label: '藏品管理', icon: Collection, children: [
{ label: '藏品', route: '/admin/relic' },
{ label: '藏品分类', route: '/admin/itemCategory' }
] },
{ label: '预约管理', icon: Calendar, children: [
{ label: '预约时段', route: '/admin/reservationTimeSlot' },
{ label: '预约明细', route: '/admin/reservation' }
] },
{ label: '公告管理', route: '/admin/announcement', icon: Message },
{ label: '轮播图管理', route: '/admin/carousel', icon: Picture },
{ label: '用户管理', route: '/admin/user', icon: User },
{ label: '博物馆信息管理', route: '/admin/museumIntro', icon: School }
])
//
const confirmPwdRule = (rule, value, callback) => {
if (!value) { //
callback(new Error('请输入确认密码'))
} else if (updatePwdForm.value.newPwd !== value) { //
callback(new Error('两次输入的密码不一致'))
} else { //
callback()
}
}
const updatePwdOpen = ref(false)
const data = reactive({
updatePwdForm: {
oldPwd: '',
newPwd: '',
confirmPwd: ''
},
updatePwdRules: {
oldPwd: [
{ required: true, message: '请输入旧密码', trigger: 'blur' }
],
newPwd: [
{ required: true, message: '请输入新密码', trigger: 'blur' }
],
confirmPwd: [
{ required: true, validator: confirmPwdRule, trigger: 'blur' }
]
}
})
const { updatePwdForm, updatePwdRules } = toRefs(data)
/** 修改密码操作 */
function handleUpdatePwd() {
updatePwdOpen.value = true
}
/** 提交修改密码 */
function submitUpdatePwd() {
proxy.$refs.updatePwdRef.validate((valid) => {
if (valid) {
updatePwd(updatePwdForm.value).then(res => {
if (res.code == 200) {
proxy.$message.success(res.msg)
proxy.$refs.updatePwdRef.resetFields()
updatePwdOpen.value = false
} else {
proxy.$message.error(res.msg)
}
})
}
})
}
/** 取消修改密码 */
function handleCancelUpdatePwd() {
proxy.$refs.updatePwdRef.resetFields()
updatePwdOpen.value = false
}
/** 个人信息操作 */
function handleUserInfo() {
proxy.$router.push('/admin/userInfo')
}
/** 退出登录操作 */
function handleLogout() {
console.log('退出登录')
proxy.$confirm('确定要退出系统吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
console.log('确定退出')
// logout
// token
removeToken()
//
proxy.$router.push('/login')
})
.catch(() => {
console.log('取消退出')
})
}
</script>
<style scoped>
/* 主容器设置为全屏高度 */
.main-container {
height: 100vh;
display: flex;
}
/* 水平容器 - 让侧边栏和右侧内容水平排列 */
.horizontal-container {
display: flex;
flex: 1;
flex-direction: row;
}
/* 左侧导航栏样式 */
.sidebar {
background-color: #fff;
height: 100vh;
flex-shrink: 0;
border-right: 1px solid #ebebeb;
}
/* 标题样式 */
.title {
width: 100%;
height: 60px;
box-sizing: border-box;
padding-top: 20px;
text-align: center;
}
.title span {
}
/* 菜单自适应高度 */
.sidebar .el-menu {
height: 100%;
border-right: none;
}
/* 右侧内容区域 - 包含header和main */
.right-content {
display: flex;
flex: 1;
flex-direction: column;
overflow: hidden;
}
/* 顶部header样式 */
.header {
line-height: 60px;
color: #000;
font-size: 18px;
height: 60px;
flex-shrink: 0;
}
.header .user {
float: right;
margin-right: 10px;
}
.img {
width: 40px;
height: 40px;
margin-top: 10px;
background-color: #ffffff;
border: 1px solid #b2b2b2;
box-sizing: border-box;
border-radius: 50%;
overflow: hidden;
transition: all 0.3s;
}
.img:hover {
cursor: pointer;
box-shadow: 0px 0px 20px #ffffff;
}
/* 主内容区域样式 */
.main-content {
flex: 1;
background: #f2f2f2;
overflow-y: auto;
padding: 20px;
box-sizing: border-box;
}
.content-card {
min-height: calc(100vh - 120px);
height: auto; /* 固定高度减去header和padding的高度 */
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
/* 卡片内容区域样式 */
.content-card .el-card__body {
flex: 1;
padding: 20px;
overflow-y: auto;
}
</style>

View File

@ -0,0 +1,195 @@
<template>
<div class="main">
<el-card class="login_box">
<h2>登录</h2>
<br>
<el-form
ref="formRef"
:model="loginForm"
:rules="loginFormRules">
<el-form-item prop="username">
<el-input
type="text"
class="apple-input"
v-model="loginForm.username"
placeholder="用户名"
style="width: 100%"
@keyup.enter="handleLogin()">
<template #prefix>
<el-icon><User /></el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
type="password"
class="apple-input"
v-model="loginForm.password"
placeholder="密码"
style="width: 100%"
@keyup.enter="handleLogin()">
<template #prefix>
<el-icon><Lock /></el-icon>
</template>
</el-input>
</el-form-item>
<br>
<el-form-item>
<el-button
class="login_btn"
type="success"
style="width: 100%"
@click="handleLogin()" >
登录
</el-button>
</el-form-item>
<el-form-item>
<el-button
class="login_btn"
style="width: 100%"
link
@click="jumpRegister()" >
注册
</el-button>
</el-form-item>
<el-form-item>
<el-button
class="login_btn"
style="width: 100%"
link
@click="jumpHome()" >
返回首页
</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script setup>
import { ref, reactive, getCurrentInstance } from 'vue'
import { useRouter } from 'vue-router'
import { login } from '@/api/login';
import { setToken } from '@/utils/token';
import Cookies from 'js-cookie';
const { proxy } = getCurrentInstance();
const formRef = ref();
// 使 useRouter router
const router = useRouter()
const loginForm = reactive({
username: "",
password: ""
})
const loginFormRules = {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' }
]
}
const handleLogin = () => {
formRef.value.validate((valid) => {
if (valid) {
// console.log(loginForm)
// console.log('')
// console.log(loginForm)
login(loginForm.username, loginForm.password).then((res) => {
console.log(res)
if (res.code === 200) {
proxy.$message.success(res.msg)
// token
setToken(res.data.token)
Cookies.set('username', res.data.user.username)
Cookies.set('avatar', res.data.user.avatar)
Cookies.set('nickname', res.data.user.nickname)
Cookies.set('role', res.data.user.role)
//
//
if (res.data.user.role === '1') {
router.push('/admin')
} else {
router.push('/tourist/home')
}
} else {
proxy.$message.error(res.msg)
}
})
} else {
console.log('验证失败')
return false
}
})
}
const jumpRegister = () => {
proxy.$router.push('/register')
}
const jumpHome = () => {
proxy.$router.push('/tourist/home')
}
</script>
<style scoped>
.main {
display: flex;
justify-content: flex-end;
align-items: center;
width: 100%;
height: 100%;
background-image: url("@/assets/login-back.jpg");
background-repeat: no-repeat;
background-size: 100% 100%;
padding-right: 10%;
}
.login_box{
width: 340px;
text-align: center;
/* 毛玻璃 */
/*
background: rgba(255, 255, 255, 0.6);
backdrop-filter: blur(20px);
border-radius: 15px;*/
/* 液态玻璃*/
/*
background: rgba(255, 255, 255, 0.25);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.18);
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.15);
border-radius: 15px;
*/
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.4);
box-shadow: 2px 4px 6px rgba(0, 0, 0, 0.2);
}
.login_box:hover {
transform: translateY(-2px);
box-shadow: 0 12px 36px 0 rgba(31, 38, 135, 0.2);
transition: all 0.3s ease;
}
.login_box h2 {
font-size: 25px;
}
</style>

View File

@ -0,0 +1,273 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="真实姓名" prop="realName">
<el-input
v-model="queryParams.realName"
placeholder="请输入真实姓名"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input
v-model="queryParams.idCard"
placeholder="请输入身份证号"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input
v-model="queryParams.phone"
placeholder="请输入手机号"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input
v-model="queryParams.email"
placeholder="请输入邮箱"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
>新增</el-button>
</el-col>
<!--<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
>导出</el-button>
</el-col>-->
</el-row>
<br>
<el-table v-loading="loading" :data="touristList">
<el-table-column label="用户id" align="center" prop="id" />
<el-table-column label="真实姓名" align="center" prop="realName" />
<el-table-column label="身份证号" align="center" prop="idCard" />
<el-table-column label="手机号" align="center" prop="phone" />
<el-table-column label="邮箱" align="center" prop="email" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<br>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="queryParams.pageNum"
:page-sizes="[10, 20, 30, 50]"
:page-size="queryParams.pageSize"
layout="->, total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
<!-- 添加或修改普通用户子对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="touristRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="真实姓名" prop="realName">
<el-input v-model="form.realName" placeholder="请输入真实姓名" />
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input v-model="form.idCard" placeholder="请输入身份证号" />
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="form.phone" placeholder="请输入手机号" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Tourist">
import { ref, reactive, toRefs, getCurrentInstance } from 'vue';
import { listTourist, getTourist, delTourist, addTourist, updateTourist } from "@/api/tourist";
const { proxy } = getCurrentInstance();
const touristList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const total = ref(0);
const title = ref("");
const isAdd = ref(false)
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
realName: null,
idCard: null,
phone: null,
email: null,
},
rules: {
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询普通用户子列表 */
function getList() {
loading.value = true;
listTourist(queryParams.value).then(response => {
touristList.value = response.list;
total.value = response.total;
loading.value = false;
});
}
//
function handleSizeChange(val) {
queryParams.value.pageSize = val;
getList();
}
//
function handleCurrentChange(val) {
queryParams.value.pageNum = val;
getList();
}
//
function cancel() {
open.value = false;
reset();
}
//
function reset() {
form.value = {
id: null,
realName: null,
idCard: null,
phone: null,
email: null,
updateTime: null
};
const touristRef = proxy.$refs["touristRef"]
if (touristRef) {
touristRef.resetFields();
}
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
const queryRef = proxy.$refs["queryRef"]
if (queryRef) {
queryRef.resetFields();
}
handleQuery();
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加普通用户子";
isAdd.value = true;
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const _id = row.id || ids.value
getTourist(_id).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改普通用户子";
isAdd.value = false;
});
}
/** 表单提交按钮 */
function submitForm() {
proxy.$refs["touristRef"].validate(valid => {
if (valid) {
if (isAdd.value) { //
addTourist(form.value).then(response => {
proxy.$message({
message: response.msg,
type: 'success'
})
open.value = false;
getList();
});
} else { //
updateTourist(form.value).then(response => {
proxy.$message({
message: response.msg,
type: 'success'
})
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
proxy.$confirm('是否确认删除普通用户子编号为"' + row.id + '"的数据项?').then(function() {
return delTourist(row.id);
}).then(response => {
getList();
proxy.$message({
message: response.msg,
type: 'success'
})
}).catch(() => {});
}
/** 导出按钮操作 */
// function handleExport() {
// proxy.download('system/tourist/export', {
// ...queryParams.value
// }, `tourist_${new Date().getTime()}.xlsx`)
// }
getList();
</script>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

View File

@ -0,0 +1,72 @@
package com.amms.controller;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.amms.domain.vo.Result;
import com.amms.domain.ItemCollection;
import com.amms.service.IItemCollectionService;
import java.util.List;
/**
* 收藏Controller
*/
@RestController
@RequestMapping("/itemCollection")
public class ItemCollectionController {
@Autowired
private IItemCollectionService itemCollectionService;
/**
* 查询收藏列表
*/
@GetMapping("/list")
public PageInfo list(ItemCollection itemCollection, @RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<ItemCollection> itemCollections = itemCollectionService.selectItemCollectionList(itemCollection);
return new PageInfo(itemCollections);
}
/**
* 查询全部收藏列表
*/
@GetMapping("/listAll")
public List<ItemCollection> listAll(ItemCollection itemCollection) {
return itemCollectionService.selectItemCollectionList(itemCollection);
}
/**
* 获取收藏详细信息
*/
@GetMapping(value = "/info/{id}")
public Result getInfo(@PathVariable("id") Long id) {
return Result.success(itemCollectionService.selectItemCollectionById(id));
}
/**
* 新增收藏
*/
@PostMapping("/add")
public Result add(@RequestBody ItemCollection itemCollection) {
return itemCollectionService.insertItemCollection(itemCollection) > 0 ? Result.success("新增成功") : Result.error("新增失败");
}
/**
* 修改收藏
*/
@PutMapping
public Result update(@RequestBody ItemCollection itemCollection) {
return itemCollectionService.updateItemCollection(itemCollection) > 0 ? Result.success("修改成功") : Result.error("修改失败");
}
/**
* 删除收藏
*/
@DeleteMapping("/{id}")
public Result delete(@PathVariable Long id) {
return itemCollectionService.deleteItemCollectionById(id) > 0 ? Result.success("删除成功") : Result.error("删除失败");
}
}

View File

@ -0,0 +1,71 @@
package com.amms.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
* 收藏对象 item_collection
*/
public class ItemCollection {
/** 收藏id */
private Long id;
/** 用户id */
private Long userId;
/** 藏品id */
private Long itemId;
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Long getUserId() {
return userId;
}
public void setItemId(Long itemId) {
this.itemId = itemId;
}
public Long getItemId() {
return itemId;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "ItemCollection{" +
"id=" + id +
", userId=" + userId +
", itemId=" + itemId +
", createTime=" + createTime +
'}';
}
}

View File

@ -0,0 +1,52 @@
package com.amms.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.amms.domain.ItemCollection;
/**
* 收藏Mapper接口
*/
@Mapper
public interface ItemCollectionMapper {
/**
* 查询收藏
*
* @param id 收藏主键
* @return 收藏
*/
public ItemCollection selectItemCollectionById(Long id);
/**
* 查询收藏列表
*
* @param itemCollection 收藏
* @return 收藏集合
*/
public List<ItemCollection> selectItemCollectionList(ItemCollection itemCollection);
/**
* 新增收藏
*
* @param itemCollection 收藏
* @return 结果
*/
public int insertItemCollection(ItemCollection itemCollection);
/**
* 修改收藏
*
* @param itemCollection 收藏
* @return 结果
*/
public int updateItemCollection(ItemCollection itemCollection);
/**
* 删除收藏
*
* @param id 收藏主键
* @return 结果
*/
public int deleteItemCollectionById(Long id);
}

View File

@ -0,0 +1,96 @@
package com.amms.security;
import com.amms.domain.SysUser;
import com.amms.domain.vo.Result;
import com.amms.util.JsonUtils;
import com.amms.util.RedisUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.SignatureException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtUtils jwtUtils;
@Autowired
private RedisUtils redisUtils;
@Value("${token.expireTime}")
private Long expireTime;
/**
* @param request
* @param response
* @param filterChain
* @throws ServletException
* @throws IOException
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 获取token
String token = request.getHeader("Authorization");
// 没有token即未登录放行交给下一步处理
if(token == null) {
doFilter(request,response,filterChain);
return;
}
// 有token通过jwt工具类解析tokenId
Claims claims = null;
try {
claims = jwtUtils.parseToken(token);
} catch (SignatureException e){
// 需要返回401重新登陆
response.getWriter().write("验签失败!!!");
return;
} catch (ExpiredJwtException e) {
// 需要返回401重新登陆
Result result = Result.error(401, "登录失效,请重新登录!");
response.getWriter().write(JsonUtils.toJson(result));
return;
}
// 在jwt中获取tokenId
String tokenId = claims.get("tokenId", String.class);
if (tokenId == null) {
// 放行
doFilter(request,response,filterChain);
}
// 在redis中根据tokenId获取用户信息
SysUser sysUser = redisUtils.get(tokenId, SysUser.class);
if (sysUser != null) { // 用户已登录
// 将用户信息放到SecurityContext中
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(sysUser, null, null);
SecurityContextHolder.getContext().setAuthentication(authentication);
// 重新将用户信息存储到redis中
redisUtils.set(tokenId, sysUser, expireTime, TimeUnit.MINUTES);
} else { // 用户登录失效
// 需要返回401重新登陆
Result result = Result.error(401, "登录失效,请重新登录!");
response.getWriter().write(JsonUtils.toJson(result));
return;
}
// 放行
doFilter(request,response,filterChain);
}
}

View File

@ -0,0 +1,42 @@
package com.amms.security;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.Map;
@Component
public class JwtUtils {
@Value("${token.secret}")
private String secret;
/**
* 生成token
*/
public String createToken(Map<String,Object> map) {
String token = Jwts.builder()
.setClaims(map)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 30 * 60 * 1000))
.signWith(SignatureAlgorithm.HS256, secret)
.compact();
return token;
}
/**
* 根据token解析出用户信息
*/
public Claims parseToken(String token) {
// 解析token需要使用和创建token时相同的秘钥
Claims claims = Jwts.parser().setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
return claims;
}
}

View File

@ -0,0 +1,49 @@
package com.amms.service;
import java.util.List;
import com.amms.domain.Relic;
/**
* 藏品Service接口
*/
public interface IRelicService {
/**
* 查询藏品列表
*
* @param relic 藏品
* @return 藏品集合
*/
public List<Relic> selectRelicList(Relic relic);
/**
* 查询藏品
*
* @param id 藏品主键
* @return 藏品
*/
public Relic selectRelicById(Long id);
/**
* 新增藏品
*
* @param relic 藏品
* @return 结果
*/
public int insertRelic(Relic relic);
/**
* 修改藏品
*
* @param relic 藏品
* @return 结果
*/
public int updateRelic(Relic relic);
/**
* 删除藏品信息
*
* @param id 藏品主键
* @return 结果
*/
public int deleteRelicById(Long id);
}

View File

@ -0,0 +1,75 @@
package com.amms.service;
import java.util.List;
import com.amms.domain.Reservation;
/**
* 预约Service接口
*/
public interface IReservationService {
/**
* 查询预约列表
*
* @param reservation 预约
* @return 预约集合
*/
public List<Reservation> selectReservationList(Reservation reservation);
/**
* 查询预约
*
* @param id 预约主键
* @return 预约
*/
public Reservation selectReservationById(Long id);
/**
* 新增预约
*
* @param reservation 预约
* @return 结果
*/
public int insertReservation(Reservation reservation);
/**
* 修改预约
*
* @param reservation 预约
* @return 结果
*/
public int updateReservation(Reservation reservation);
/**
* 删除预约信息
*
* @param id 预约主键
* @return 结果
*/
public int deleteReservationById(Long id);
/**
* 审核预约通过/驳回
*
* 审核通过时生成整单核验二维码Reservation.qrCode以及每位游客个人核验二维码ReservationVisitor.visitorQrCode
*
* @param reservation 预约需包含 idstatusremark
* @return 结果
*/
public int auditReservation(Reservation reservation);
/**
* 整单核验将该预约下所有游客核验状态置为1
*
* @param reservationId 预约ID
* @return 更新条数
*/
public int verifyAllVisitors(Long reservationId);
/**
* 游客个人核验将该游客核验状态置为1
*
* @param visitorId 游客ID
* @return 结果
*/
public int verifyVisitor(Long visitorId);
}

View File

@ -0,0 +1,55 @@
package com.amms.service;
import java.util.Date;
import java.util.List;
import com.amms.domain.ReservationTimeSlot;
/**
* 预约时段Service接口
*/
public interface IReservationTimeSlotService {
/**
* 查询预约时段列表
*
* @param reservationTimeSlot 预约时段
* @return 预约时段集合
*/
public List<ReservationTimeSlot> selectReservationTimeSlotList(ReservationTimeSlot reservationTimeSlot);
/**
* 查询预约时段
*
* @param id 预约时段主键
* @return 预约时段
*/
public ReservationTimeSlot selectReservationTimeSlotById(Long id);
/**
* 新增预约时段
*
* @param reservationTimeSlot 预约时段
* @return 结果
*/
public int insertReservationTimeSlot(ReservationTimeSlot reservationTimeSlot);
/**
* 修改预约时段
*
* @param reservationTimeSlot 预约时段
* @return 结果
*/
public int updateReservationTimeSlot(ReservationTimeSlot reservationTimeSlot);
/**
* 删除预约时段信息
*
* @param id 预约时段主键
* @return 结果
*/
public int deleteReservationTimeSlotById(Long id);
/**
* 批量新增预约时段根据日期范围
*/
public int batchInsertReservationTimeSlots(Date startDate, Date endDate, Date startTime, Date endTime, Integer maxPeople, Long status);
}

View File

@ -0,0 +1,49 @@
package com.amms.service;
import java.util.List;
import com.amms.domain.Tourist;
/**
* 普通用户子Service接口
*/
public interface ITouristService {
/**
* 查询普通用户子列表
*
* @param tourist 普通用户子
* @return 普通用户子集合
*/
public List<Tourist> selectTouristList(Tourist tourist);
/**
* 查询普通用户子
*
* @param id 普通用户子主键
* @return 普通用户子
*/
public Tourist selectTouristById(Long id);
/**
* 新增普通用户子
*
* @param tourist 普通用户子
* @return 结果
*/
public int insertTourist(Tourist tourist);
/**
* 修改普通用户子
*
* @param tourist 普通用户子
* @return 结果
*/
public int updateTourist(Tourist tourist);
/**
* 删除普通用户子信息
*
* @param id 普通用户子主键
* @return 结果
*/
public int deleteTouristById(Long id);
}

View File

@ -0,0 +1,80 @@
package com.amms.service.impl;
import java.util.List;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.amms.mapper.ItemCategoryMapper;
import com.amms.domain.ItemCategory;
import com.amms.service.IItemCategoryService;
import com.amms.security.SecurityUtils;
/**
* 藏品分类Service业务层处理
*/
@Service
public class ItemCategoryServiceImpl implements IItemCategoryService {
@Autowired
private ItemCategoryMapper itemCategoryMapper;
/**
* 查询藏品分类列表
*
* @param itemCategory 藏品分类
* @return 藏品分类
*/
@Override
public List<ItemCategory> selectItemCategoryList(ItemCategory itemCategory) {
return itemCategoryMapper.selectItemCategoryList(itemCategory);
}
/**
* 查询藏品分类
*
* @param id 藏品分类主键
* @return 藏品分类
*/
@Override
public ItemCategory selectItemCategoryById(Long id) {
return itemCategoryMapper.selectItemCategoryById(id);
}
/**
* 新增藏品分类
*
* @param itemCategory 藏品分类
* @return 结果
*/
@Override
public int insertItemCategory(ItemCategory itemCategory) {
itemCategory.setCreateTime(new Date());
itemCategory.setCreator(SecurityUtils.getCurrentUser().getId());
return itemCategoryMapper.insertItemCategory(itemCategory);
}
/**
* 修改藏品分类
*
* @param itemCategory 藏品分类
* @return 结果
*/
@Override
public int updateItemCategory(ItemCategory itemCategory) {
itemCategory.setUpdateTime(new Date());
itemCategory.setUpdater(SecurityUtils.getCurrentUser().getId());
return itemCategoryMapper.updateItemCategory(itemCategory);
}
/**
* 删除藏品分类信息
*
* @param id 藏品分类主键
* @return 结果
*/
@Override
public int deleteItemCategoryById(Long id) {
return itemCategoryMapper.deleteItemCategoryById(id);
}
}

View File

@ -0,0 +1,79 @@
package com.amms.service.impl;
import java.util.List;
import java.util.Date;
import com.amms.security.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.amms.mapper.ItemCollectionMapper;
import com.amms.domain.ItemCollection;
import com.amms.service.IItemCollectionService;
/**
* 收藏Service业务层处理
*/
@Service
public class ItemCollectionServiceImpl implements IItemCollectionService {
@Autowired
private ItemCollectionMapper itemCollectionMapper;
/**
* 查询收藏列表
*
* @param itemCollection 收藏
* @return 收藏
*/
@Override
public List<ItemCollection> selectItemCollectionList(ItemCollection itemCollection) {
return itemCollectionMapper.selectItemCollectionList(itemCollection);
}
/**
* 查询收藏
*
* @param id 收藏主键
* @return 收藏
*/
@Override
public ItemCollection selectItemCollectionById(Long id) {
return itemCollectionMapper.selectItemCollectionById(id);
}
/**
* 新增收藏
*
* @param itemCollection 收藏
* @return 结果
*/
@Override
public int insertItemCollection(ItemCollection itemCollection) {
itemCollection.setUserId(SecurityUtils.getCurrentUser().getId());
itemCollection.setCreateTime(new Date());
return itemCollectionMapper.insertItemCollection(itemCollection);
}
/**
* 修改收藏
*
* @param itemCollection 收藏
* @return 结果
*/
@Override
public int updateItemCollection(ItemCollection itemCollection) {
return itemCollectionMapper.updateItemCollection(itemCollection);
}
/**
* 删除收藏信息
*
* @param id 收藏主键
* @return 结果
*/
@Override
public int deleteItemCollectionById(Long id) {
return itemCollectionMapper.deleteItemCollectionById(id);
}
}

View File

@ -0,0 +1,18 @@
package com.amms.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonUtils {
private static ObjectMapper objectMapper = new ObjectMapper();
public static String toJson(Object obj) throws JsonProcessingException {
return objectMapper.writeValueAsString(obj);
}
public static <T> T fromJson(String json, Class<T> clazz) throws JsonProcessingException {
return objectMapper.readValue(json, clazz);
}
}

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.amms.mapper.ItemCollectionMapper">
<resultMap type="com.amms.domain.ItemCollection" id="ItemCollectionResult">
<result property="id" column="id" />
<result property="userId" column="user_id" />
<result property="itemId" column="item_id" />
<result property="createTime" column="create_time" />
</resultMap>
<sql id="selectItemCollectionVo">
select id, user_id, item_id, create_time from item_collection
</sql>
<select id="selectItemCollectionList" parameterType="com.amms.domain.ItemCollection" resultMap="ItemCollectionResult">
<include refid="selectItemCollectionVo"/>
<where>
<if test="userId != null "> and user_id = #{userId}</if>
<if test="itemId != null "> and item_id = #{itemId}</if>
</where>
</select>
<select id="selectItemCollectionById" parameterType="Long" resultMap="ItemCollectionResult">
<include refid="selectItemCollectionVo"/>
where id = #{id}
</select>
<insert id="insertItemCollection" parameterType="com.amms.domain.ItemCollection" useGeneratedKeys="true" keyProperty="id">
insert into item_collection
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="userId != null">user_id,</if>
<if test="itemId != null">item_id,</if>
<if test="createTime != null">create_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="userId != null">#{userId},</if>
<if test="itemId != null">#{itemId},</if>
<if test="createTime != null">#{createTime},</if>
</trim>
</insert>
<update id="updateItemCollection" parameterType="com.amms.domain.ItemCollection">
update item_collection
<trim prefix="SET" suffixOverrides=",">
<if test="userId != null">user_id = #{userId},</if>
<if test="itemId != null">item_id = #{itemId},</if>
<if test="createTime != null">create_time = #{createTime},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteItemCollectionById" parameterType="Long">
delete from item_collection where id = #{id}
</delete>
</mapper>