diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b559d64
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,31 @@
+
+
+.idea/
+.trae/
+target
+
+# ---> Java
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+replay_pid*
diff --git a/amms_front/.gitignore b/amms_front/.gitignore
new file mode 100644
index 0000000..8ee54e8
--- /dev/null
+++ b/amms_front/.gitignore
@@ -0,0 +1,30 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+.DS_Store
+dist
+dist-ssr
+coverage
+*.local
+
+/cypress/videos/
+/cypress/screenshots/
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+*.tsbuildinfo
diff --git a/amms_front/src/App.vue b/amms_front/src/App.vue
new file mode 100644
index 0000000..7e961a2
--- /dev/null
+++ b/amms_front/src/App.vue
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/amms_front/src/api/announcement.js b/amms_front/src/api/announcement.js
new file mode 100644
index 0000000..16b1f64
--- /dev/null
+++ b/amms_front/src/api/announcement.js
@@ -0,0 +1,51 @@
+import axios from '@/utils/request'
+
+// 查询公告列表
+export function listAnnouncement(query) {
+ return axios.get('/announcement/list',{
+ params: {
+ ...query
+ }
+ })
+}
+
+// 查询全部公告列表
+export function listAllAnnouncement(query) {
+ return axios.get('/announcement/listAll', {
+ params: {
+ ...query
+ }
+ })
+}
+
+// 查询公告详细
+export function getAnnouncement(id) {
+ return axios.get('/announcement/info/' + id)
+}
+
+// 新增公告
+export function addAnnouncement(data) {
+ return axios.post('/announcement/add', {
+ ...data
+ })
+}
+
+// 修改公告
+export function updateAnnouncement(data) {
+ return axios.put('/announcement', data)
+}
+
+// 设为置顶(保证仅一个置顶)
+export function setTopAnnouncement(id) {
+ return axios.put('/announcement/setTop/' + id)
+}
+
+// 删除公告
+export function delAnnouncement(id) {
+ return axios.delete('/announcement/' + id)
+}
+
+// 游客端公告列表(置顶 + 普通分页)
+export function listTouristAnnouncements(params) {
+ return axios.get('/announcement/touristList', { params })
+}
diff --git a/amms_front/src/assets/base.css b/amms_front/src/assets/base.css
new file mode 100644
index 0000000..8816868
--- /dev/null
+++ b/amms_front/src/assets/base.css
@@ -0,0 +1,86 @@
+/* color palette from */
+:root {
+ --vt-c-white: #ffffff;
+ --vt-c-white-soft: #f8f8f8;
+ --vt-c-white-mute: #f2f2f2;
+
+ --vt-c-black: #181818;
+ --vt-c-black-soft: #222222;
+ --vt-c-black-mute: #282828;
+
+ --vt-c-indigo: #2c3e50;
+
+ --vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
+ --vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
+ --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
+ --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
+
+ --vt-c-text-light-1: var(--vt-c-indigo);
+ --vt-c-text-light-2: rgba(60, 60, 60, 0.66);
+ --vt-c-text-dark-1: var(--vt-c-white);
+ --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
+}
+
+/* semantic color variables for this project */
+:root {
+ --color-background: var(--vt-c-white);
+ --color-background-soft: var(--vt-c-white-soft);
+ --color-background-mute: var(--vt-c-white-mute);
+
+ --color-border: var(--vt-c-divider-light-2);
+ --color-border-hover: var(--vt-c-divider-light-1);
+
+ --color-heading: var(--vt-c-text-light-1);
+ --color-text: var(--vt-c-text-light-1);
+
+ --section-gap: 160px;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ --color-background: var(--vt-c-black);
+ --color-background-soft: var(--vt-c-black-soft);
+ --color-background-mute: var(--vt-c-black-mute);
+
+ --color-border: var(--vt-c-divider-dark-2);
+ --color-border-hover: var(--vt-c-divider-dark-1);
+
+ --color-heading: var(--vt-c-text-dark-1);
+ --color-text: var(--vt-c-text-dark-2);
+ }
+}
+
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+ margin: 0;
+ font-weight: normal;
+}
+
+body {
+ min-height: 100vh;
+ color: var(--color-text);
+ background: var(--color-background);
+ transition:
+ color 0.5s,
+ background-color 0.5s;
+ line-height: 1.6;
+ font-family:
+ Inter,
+ -apple-system,
+ BlinkMacSystemFont,
+ 'Segoe UI',
+ Roboto,
+ Oxygen,
+ Ubuntu,
+ Cantarell,
+ 'Fira Sans',
+ 'Droid Sans',
+ 'Helvetica Neue',
+ sans-serif;
+ font-size: 15px;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
diff --git a/amms_front/src/assets/css/apple-input.css b/amms_front/src/assets/css/apple-input.css
new file mode 100644
index 0000000..9f649ca
--- /dev/null
+++ b/amms_front/src/assets/css/apple-input.css
@@ -0,0 +1,89 @@
+/*
+ Apple风格Element Plus输入框公共样式
+ 使用方法:在需要应用样式的el-input上添加 class="apple-input"
+ 示例:
+*/
+
+/* 基础样式 - 通过自定义类名限定范围 */
+.el-input.apple-input .el-input__wrapper {
+ background-color: rgba(255, 255, 255, 0.28) !important;
+ border: 1px solid rgba(255, 255, 255, 0.2) !important;
+ border-radius: 0.5rem !important;
+ padding: 0 1rem !important;
+ height: 2.75rem !important;
+ transition: all 0.3s ease !important;
+}
+
+/* 悬停状态 */
+.el-input.apple-input .el-input__wrapper:hover {
+ border-color: rgba(255, 255, 255, 0.3) !important;
+ box-shadow: none !important;
+}
+
+/* 聚焦状态 */
+.el-input.apple-input .el-input__wrapper:focus-within {
+ border-color: #0071e3 !important; /* Apple标志性蓝色 */
+ box-shadow: 0 0 0 1px #0071e3 !important;
+}
+
+/* 输入文本样式 */
+.el-input.apple-input .el-input__input {
+ color: white !important;
+ padding: 0 !important;
+ height: 100% !important;
+}
+
+/* 占位符样式 */
+.el-input.apple-input .el-input__input::placeholder {
+ color: white !important;
+}
+
+/* 后缀图标(如密码可见性切换) */
+.el-input.apple-input .el-input__suffix-inner {
+ color: rgba(255, 255, 255, 0.6) !important;
+}
+
+.el-input.apple-input .el-input__suffix-inner:hover {
+ color: white !important;
+}
+
+/* 清除按钮 */
+.el-input.apple-input .el-input__clear {
+ color: rgba(255, 255, 255, 0.6) !important;
+}
+
+.el-input.apple-input .el-input__clear:hover {
+ color: white !important;
+ background-color: rgba(255, 255, 255, 0.1) !important;
+}
+
+/* 前缀图标 */
+.el-input.apple-input .el-input__prefix {
+ color: rgba(255, 255, 255, 0.6) !important;
+}
+
+/* 可选变体:更大的输入框 */
+.el-input.apple-input.large .el-input__wrapper {
+ height: 3.25rem !important;
+ font-size: 1rem !important;
+}
+
+/* 可选变体:更小的输入框 */
+.el-input.apple-input.small .el-input__wrapper {
+ height: 2.25rem !important;
+ font-size: 0.875rem !important;
+}
+
+/* 可选变体:浅色模式适配 */
+.el-input.apple-input.light .el-input__wrapper {
+ background-color: rgba(0, 0, 0, 0.05) !important;
+ border: 1px solid rgba(0, 0, 0, 0.1) !important;
+}
+
+.el-input.apple-input.light .el-input__input {
+ color: #1d1d1f !important;
+}
+
+.el-input.apple-input.light .el-input__input::placeholder {
+ color: rgba(0, 0, 0, 0.4) !important;
+}
diff --git a/sql/amms.sql b/sql/amms.sql
new file mode 100644
index 0000000..3d4e3f0
--- /dev/null
+++ b/sql/amms.sql
@@ -0,0 +1,215 @@
+-- 用户主表(共用属性)
+DROP TABLE IF EXISTS `sys_user`;
+CREATE TABLE `sys_user` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户id',
+ `username` varchar(30) NOT NULL COMMENT '账号',
+ `password` varchar(100) DEFAULT '' COMMENT '密码',
+ `nickname` varchar(30) NOT NULL COMMENT '昵称',
+ `avatar` varchar(100) DEFAULT '' COMMENT '头像地址',
+ `status` int DEFAULT 0 COMMENT '状态(0正常 1停用 2待审核)',
+ `role` varchar(10) NOT NULL COMMENT '角色(1超级管理员 2普通用户)',
+ `creator` bigint DEFAULT NULL COMMENT '创建者id',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `updater` bigint DEFAULT NULL COMMENT '更新者id',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `remark` varchar(500) DEFAULT NULL COMMENT '备注',
+ `deleted` tinyint DEFAULT 0 COMMENT '删除标识(0未删 1已删)',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `idx_sys_user_username` (`username`)
+) COMMENT='用户主表';
+-- 超级管理员 admin 密码:123456
+INSERT INTO `sys_user` (`username`, `password`, `nickname`, `avatar`, `status`, `role`, `creator`, `create_time`, `updater`, `update_time`, `remark`, `deleted`)
+VALUES ('admin', '$2a$10$sSTvaDj1QtrEIgEglkumguRT88m0WRs61gWw7Rgm/gpP6/eZ4ffwG', '超级管理员', '', 0, '1', NULL, NOW(), NULL, NOW(), '系统默认超级管理员', 0);
+
+-- 普通用户(游客)
+DROP TABLE IF EXISTS `tourist`;
+CREATE TABLE `tourist` (
+ `id` bigint NOT NULL COMMENT '用户id(与sys_user.id一致)',
+ `real_name` varchar(30) DEFAULT NULL COMMENT '真实姓名',
+ `id_card` varchar(18) DEFAULT NULL COMMENT '身份证号',
+ `phone` varchar(11) DEFAULT NULL COMMENT '手机号',
+ `email` varchar(50) DEFAULT NULL COMMENT '邮箱',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `idx_sys_user_normal_phone` (`phone`),
+ UNIQUE KEY `idx_sys_user_normal_email` (`email`)
+) COMMENT='普通用户子表'
+
+-- 轮播图表
+DROP TABLE IF EXISTS `carousel`;
+CREATE TABLE `carousel` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '轮播图id',
+ `title` varchar(50) NOT NULL COMMENT '标题',
+ `image_url` varchar(255) NOT NULL COMMENT '图片地址',
+ `link` varchar(255) DEFAULT NULL COMMENT '跳转链接',
+ `sort` int DEFAULT 0 COMMENT '排序序号',
+ `status` tinyint DEFAULT 1 COMMENT '状态(0隐藏 1显示)',
+ `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ PRIMARY KEY (`id`),
+ KEY `idx_carousel_status` (`status`)
+) COMMENT='轮播图';
+
+-- 博物馆简介表
+DROP TABLE IF EXISTS `museum_intro`;
+CREATE TABLE `museum_intro` (
+ `museum_name` varchar(100) NOT NULL COMMENT '博物馆名称(主键)',
+ `content` text NOT NULL COMMENT '内容',
+ `logo_url` varchar(255) DEFAULT NULL COMMENT 'Logo地址',
+ `address` varchar(100) DEFAULT NULL COMMENT '地址',
+ `phone` varchar(20) DEFAULT NULL COMMENT '联系电话',
+ `open_time` time DEFAULT NULL COMMENT '营业开始时间',
+ `close_time` time DEFAULT NULL COMMENT '营业结束时间',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `updater` bigint DEFAULT NULL COMMENT '更新者id',
+ PRIMARY KEY (`museum_name`)
+) COMMENT='博物馆简介';
+INSERT INTO `museum_intro` (
+ `museum_name`,
+ `content`,
+ `logo_url`,
+ `address`,
+ `phone`,
+ `open_time`,
+ `close_time`,
+ `update_time`,
+ `updater`
+) VALUES (
+ '邺城博物馆',
+ '邺城博物馆位于河北省邺城遗址保护区,致力于系统展示东魏、北齐时期的城市文明与考古成果。馆内设基本陈列、专题展厅与数字互动空间,重点呈现佛教造像、石刻艺术、陶瓷器与城址考古发掘成果,并提供文物保护科普、研学课程与公众教育服务。',
+ '/api/files/get?fileName=museum/logo/yecity.png',
+ '河北省临漳县邺城遗址博物馆',
+ '0310-8888888',
+ '09:00:00',
+ '17:30:00',
+ NOW(),
+ 1
+);
+
+-- 藏品分类表
+DROP TABLE IF EXISTS `item_category`;
+CREATE TABLE `item_category` (
+ `id` bigint NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '分类ID',
+ `name` varchar(50) NOT NULL COMMENT '分类名称',
+ `creator` bigint NULL COMMENT '创建者',
+ `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updater` bigint NULL COMMENT '更新者',
+ `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
+ `remark` varchar(500) NULL COMMENT '备注'
+) COMMENT = '藏品分类';
+
+
+-- 藏品主表
+DROP TABLE IF EXISTS `relic`;
+CREATE TABLE `relic` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '藏品id',
+ `name` varchar(100) NOT NULL COMMENT '名称',
+ `category_id` bigint NOT NULL COMMENT '分类ID',
+ `cover_image_url` varchar(255) NOT NULL COMMENT '封面图地址',
+ `age` varchar(50) DEFAULT NULL COMMENT '年代',
+ `material` varchar(50) DEFAULT NULL COMMENT '材质',
+ `excavation_info` text DEFAULT NULL COMMENT '出土信息',
+ `story` text DEFAULT NULL COMMENT '文物故事',
+ `model_url` text DEFAULT NULL COMMENT '3D/360°图地址',
+ `is_hot` tinyint DEFAULT 0 COMMENT '热门标识(0否 1是)',
+ `status` tinyint DEFAULT 1 COMMENT '状态(0隐藏 1显示)',
+ `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `creator` bigint DEFAULT NULL COMMENT '创建者id',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `updater` bigint DEFAULT NULL COMMENT '更新者id',
+ PRIMARY KEY (`id`)
+) COMMENT = '藏品';
+
+-- 测试数据:邺城博物馆热门/普通藏品(15条)
+INSERT INTO `relic` (`name`, `category_id`, `cover_image_url`, `age`, `material`, `excavation_info`, `story`, `model_url`, `is_hot`, `status`, `create_time`, `creator`, `update_time`, `updater`) VALUES
+('北齐石刻佛像', 1, '/api/files/get?fileName=relicCover/bei_qi_shike_foxiang.jpg', '北齐', '石质', '邺城遗址石窟区出土', '北齐时期石刻造像,线条劲挺,面相安详。', NULL, 1, 1, NOW(), 1, NOW(), 1),
+('东魏青釉瓷碗', 2, '/api/files/get?fileName=relicCover/dong_wei_qingyou_ciwang.jpg', '东魏', '陶瓷', '邺城城址文化层出土', '胎质细腻,通体青釉,器形规整。', NULL, 1, 1, NOW(), 1, NOW(), 1),
+('北齐石柱础', 1, '/api/files/get?fileName=relicCover/bei_qi_zhuchu.jpg', '北齐', '石质', '邺城宫殿区基址出土', '柱础覆莲纹,雕刻工整,体现工艺水准。', NULL, 0, 1, NOW(), 1, NOW(), 1),
+('东魏鎏金饰片', 3, '/api/files/get?fileName=relicCover/dong_wei_liujin_shipian.jpg', '东魏', '金属', '邺城遗址手工业作坊出土', '鎏金工艺精湛,纹饰细密。', NULL, 1, 1, NOW(), 1, NOW(), 1),
+('北齐陶俑', 2, '/api/files/get?fileName=relicCover/bei_qi_taoyong.jpg', '北齐', '陶', '邺城墓葬出土', '俑身比例匀称,服饰简洁,表情生动。', NULL, 0, 1, NOW(), 1, NOW(), 1),
+('邺城瓦当', 4, '/api/files/get?fileName=relicCover/yecity_wadang.jpg', '北齐', '陶', '邺城宫殿区瓦件堆积出土', '瓦当纹饰清晰,常见卷云与莲纹。', NULL, 1, 1, NOW(), 1, NOW(), 1),
+('邺城石刻残片', 1, '/api/files/get?fileName=relicCover/yecity_shike_canpian.jpg', '北齐', '石质', '邺城寺院区出土', '残片可见线刻与浅浮雕技法。', NULL, 0, 1, NOW(), 1, NOW(), 1),
+('北齐碑刻', 1, '/api/files/get?fileName=relicCover/bei_qi_beike.jpg', '北齐', '石质', '邺城遗址碑廓出土', '字迹峻拔,为研究书法与历史提供资料。', NULL, 1, 1, NOW(), 1, NOW(), 1),
+('邺城铜镜', 3, '/api/files/get?fileName=relicCover/yecity_tongjing.jpg', '北齐', '青铜', '邺城民居遗址出土', '背纹精美,折射古代生活审美。', NULL, 0, 1, NOW(), 1, NOW(), 1),
+('邺城陶灯', 2, '/api/files/get?fileName=relicCover/yecity_taodeng.jpg', '东魏', '陶', '邺城手工业区出土', '造型朴素,实用性强。', NULL, 0, 1, NOW(), 1, NOW(), 1),
+('邺城青铜器', 3, '/api/files/get?fileName=relicCover/yecity_qingtongqi.jpg', '北齐', '青铜', '邺城祭祀遗址出土', '铸造规整,纹饰典雅。', NULL, 1, 1, NOW(), 1, NOW(), 1),
+('石雕护法像', 1, '/api/files/get?fileName=relicCover/shidiao_hufa.jpg', '北齐', '石质', '邺城寺院区出土', '表情威严,衣纹流畅,守护佛法之象。', NULL, 1, 1, NOW(), 1, NOW(), 1),
+('鎏金佛像', 3, '/api/files/get?fileName=relicCover/liujin_foxiang.jpg', '北齐', '金属', '邺城佛教遗迹出土', '通体鎏金,庄严华美。', NULL, 1, 1, NOW(), 1, NOW(), 1),
+('邺城瓷瓶', 2, '/api/files/get?fileName=relicCover/yecity_ciping.jpg', '东魏', '陶瓷', '邺城城址出土', '瓶身修长,青釉匀净。', NULL, 0, 1, NOW(), 1, NOW(), 1),
+('石经残卷', 1, '/api/files/get?fileName=relicCover/shijing_canjuan.jpg', '北齐', '石质', '邺城经藏区出土', '石经残刻,见证佛教经典传播。', NULL, 0, 1, NOW(), 1, NOW(), 1);
+
+-- 公告表
+DROP TABLE IF EXISTS `announcement`;
+CREATE TABLE `announcement` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '公告id',
+ `title` varchar(100) NOT NULL COMMENT '标题',
+ `content` text NOT NULL COMMENT '内容',
+ `is_top` tinyint DEFAULT 0 COMMENT '置顶标识(0否 1是)',
+ `status` tinyint DEFAULT 1 COMMENT '状态(0隐藏 1显示)',
+ `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '发布时间',
+ `creator` bigint DEFAULT NULL COMMENT '发布者id',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `updater` bigint DEFAULT NULL COMMENT '更新者id',
+ PRIMARY KEY (`id`)
+) COMMENT='公告';
+
+-- 预约时段表
+DROP TABLE IF EXISTS `reservation_time_slot`;
+CREATE TABLE `reservation_time_slot` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '时段id',
+ `date` date NOT NULL COMMENT '预约日期',
+ `start_time` time NOT NULL COMMENT '开始时间',
+ `end_time` time NOT NULL COMMENT '结束时间',
+ `max_people` int NOT NULL COMMENT '最大人数',
+ `current_people` int DEFAULT 0 COMMENT '已预约人数',
+ `status` tinyint DEFAULT 1 COMMENT '状态(0不可约 1可约)',
+ `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `creator` bigint DEFAULT NULL COMMENT '创建者id',
+ PRIMARY KEY (`id`)
+) COMMENT='预约时段';
+
+-- 预约记录表
+DROP TABLE IF EXISTS `reservation`;
+CREATE TABLE `reservation` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '预约id(主表ID)',
+ `user_id` bigint NOT NULL COMMENT '预约发起者id(关联sys_user.id)',
+ `time_slot_id` bigint NOT NULL COMMENT '预约时段id(关联reservation_time_slot.id)',
+ `total_visitors` int NOT NULL COMMENT '预约总人数(与明细表记录数一致)',
+ `reserve_time` time NOT NULL COMMENT '预约时间',
+ `qr_code` varchar(255) DEFAULT NULL COMMENT '预约凭证二维码(整单唯一)',
+ `status` tinyint DEFAULT 0 COMMENT '整单状态(0待审核 1已通过 2已取消 3已驳回)',
+ `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '预约提交时间',
+ `update_time` datetime DEFAULT NULL COMMENT '审核/更新时间',
+ `updater` bigint DEFAULT NULL COMMENT '审核者id(关联sys_user.id)',
+ `remark` varchar(500) DEFAULT NULL COMMENT '审核备注(如驳回原因)',
+ PRIMARY KEY (`id`),
+ KEY `idx_user_id` (`user_id`),
+ KEY `idx_time_slot_id` (`time_slot_id`),
+ KEY `idx_status` (`status`)
+) COMMENT='预约';
+
+-- 预约明细表
+DROP TABLE IF EXISTS `reservation_visitor`;
+CREATE TABLE `reservation_visitor` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '明细ID',
+ `reservation_id` bigint NOT NULL COMMENT '预约id',
+ `real_name` varchar(30) NOT NULL COMMENT '游客真实姓名',
+ `id_card` varchar(18) NOT NULL COMMENT '游客身份证号(唯一标识游客)',
+ `phone` varchar(11) NOT NULL COMMENT '游客手机号',
+ `visitor_qr_code` varchar(500) DEFAULT NULL COMMENT '游客个人入场二维码(可选,如分人验证)',
+ `verify_status` tinyint DEFAULT 0 COMMENT '游客入场验证状态(0未验证 1已验证)',
+ `verify_time` datetime DEFAULT NULL COMMENT '入场验证时间',
+ PRIMARY KEY (`id`),
+ KEY `idx_reservation_id` (`reservation_id`),
+ KEY `idx_id_card` (`id_card`)
+) COMMENT='游客预约明细';
+
+-- 收藏表
+DROP TABLE IF EXISTS `item_collection`;
+CREATE TABLE `item_collection` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '收藏id',
+ `user_id` bigint NOT NULL COMMENT '用户id',
+ `item_id` bigint NOT NULL COMMENT '藏品id',
+ `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '收藏时间',
+ PRIMARY KEY (`id`)
+) COMMENT='收藏';
diff --git a/sql/app.sql b/sql/app.sql
new file mode 100644
index 0000000..584c85c
--- /dev/null
+++ b/sql/app.sql
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS `sys_user`;
+CREATE TABLE `sys_user` (
+ id bigint not null auto_increment primary key comment '用户ID',
+ username varchar(30) not null comment '用户账号',
+ nickname varchar(30) not null comment '用户昵称',
+ mobile varchar(11) null default '' comment '手机号码',
+ sex int null DEFAULT 0 comment '用户性别(0男 1女 2未知)',
+ avatar varchar(100) null default '' comment '头像地址',
+ password varchar(100) null default '' comment '密码',
+ status int null default 0 comment '帐号状态(0正常 1停用)',
+ role varchar(20) not null comment '角色 admin管理员',
+ creator bigint null default 1 comment '创建者',
+ create_time datetime null default null comment '创建时间',
+ updater bigint null default 1 comment '更新者',
+ update_time datetime null default null comment '更新时间',
+ remark varchar(500) null default null comment '备注',
+ deleted tinyint null default 0 comment '删除标识'
+) comment = '用户';
diff --git a/src/main/java/com/amms/Application.java b/src/main/java/com/amms/Application.java
new file mode 100644
index 0000000..d280227
--- /dev/null
+++ b/src/main/java/com/amms/Application.java
@@ -0,0 +1,13 @@
+package com.amms;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+}
diff --git a/src/main/java/com/amms/controller/AnnouncementController.java b/src/main/java/com/amms/controller/AnnouncementController.java
new file mode 100644
index 0000000..66de09c
--- /dev/null
+++ b/src/main/java/com/amms/controller/AnnouncementController.java
@@ -0,0 +1,106 @@
+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.Announcement;
+import com.amms.service.IAnnouncementService;
+
+import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 公告Controller
+ */
+@RestController
+@RequestMapping("/announcement")
+public class AnnouncementController {
+
+ @Autowired
+ private IAnnouncementService announcementService;
+
+ /**
+ * 查询公告列表
+ */
+ @GetMapping("/list")
+ public PageInfo list(Announcement announcement, @RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize) {
+ PageHelper.startPage(pageNum, pageSize);
+ List announcements = announcementService.selectAnnouncementList(announcement);
+ return new PageInfo(announcements);
+ }
+
+ /**
+ * 查询全部公告列表
+ */
+ @GetMapping("/listAll")
+ public List listAll(Announcement announcement) {
+ return announcementService.selectAnnouncementList(announcement);
+ }
+
+ /**
+ * 获取公告详细信息
+ */
+ @GetMapping(value = "/info/{id}")
+ public Result getInfo(@PathVariable("id") Long id) {
+ return Result.success(announcementService.selectAnnouncementById(id));
+ }
+
+ /**
+ * 新增公告
+ */
+ @PostMapping("/add")
+ public Result add(@RequestBody Announcement announcement) {
+ return announcementService.insertAnnouncement(announcement) > 0 ? Result.success("新增成功") : Result.error("新增失败");
+ }
+
+ /**
+ * 修改公告
+ */
+ @PutMapping
+ public Result update(@RequestBody Announcement announcement) {
+ return announcementService.updateAnnouncement(announcement) > 0 ? Result.success("修改成功") : Result.error("修改失败");
+ }
+
+ /**
+ * 删除公告
+ */
+ @DeleteMapping("/{id}")
+ public Result delete(@PathVariable Long id) {
+ return announcementService.deleteAnnouncementById(id) > 0 ? Result.success("删除成功") : Result.error("删除失败");
+ }
+
+ /**
+ * 设为置顶(全局仅一个置顶)
+ */
+ @PutMapping("/setTop/{id}")
+ public Result setTop(@PathVariable Long id) {
+ return announcementService.setTop(id) > 0 ? Result.success("置顶成功") : Result.error("置顶失败");
+ }
+
+ /**
+ * 游客端公告列表(置顶 + 普通分页)
+ *
+ * 返回:
+ * topList - 置顶公告列表
+ * list - 普通公告当前页数据
+ * total - 普通公告总条数
+ */
+ @GetMapping("/touristList")
+ public Result touristList(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize,
+ @RequestParam(value = "title", required = false) String title) {
+ List topList = announcementService.selectTopAnnouncements();
+ PageHelper.startPage(pageNum, pageSize);
+ Announcement filter = new Announcement();
+ filter.setTitle(title);
+ List normals = announcementService.selectNormalAnnouncements(filter);
+ PageInfo pageInfo = new PageInfo(normals);
+ Map data = new HashMap<>();
+ data.put("topList", topList);
+ data.put("list", pageInfo.getList());
+ data.put("total", pageInfo.getTotal());
+ return Result.success(data);
+ }
+}
diff --git a/src/main/java/com/amms/domain/Announcement.java b/src/main/java/com/amms/domain/Announcement.java
new file mode 100644
index 0000000..8df6743
--- /dev/null
+++ b/src/main/java/com/amms/domain/Announcement.java
@@ -0,0 +1,133 @@
+package com.amms.domain;
+
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ * 公告对象 announcement
+ */
+public class Announcement {
+
+ /** 公告id */
+ private Long id;
+
+ /** 标题 */
+ private String title;
+
+ /** 内容 */
+ private String content;
+
+ /** 置顶标识(0否 1是) */
+ private Long isTop;
+
+ /** 状态(0隐藏 1显示) */
+ private Long status;
+
+ /** 发布者id */
+ private Long creator;
+
+ /** 更新者id */
+ private Long updater;
+
+ /** 创建时间 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+
+ /** 更新时间 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setIsTop(Long isTop) {
+ this.isTop = isTop;
+ }
+
+ public Long getIsTop() {
+ return isTop;
+ }
+
+ public void setStatus(Long status) {
+ this.status = status;
+ }
+
+ public Long getStatus() {
+ return status;
+ }
+
+
+ public void setCreator(Long creator) {
+ this.creator = creator;
+ }
+
+ public Long getCreator() {
+ return creator;
+ }
+
+
+ public void setUpdater(Long updater) {
+ this.updater = updater;
+ }
+
+ public Long getUpdater() {
+ return updater;
+ }
+
+ public Date getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(Date createTime) {
+ this.createTime = createTime;
+ }
+
+ public Date getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(Date updateTime) {
+ this.updateTime = updateTime;
+ }
+
+ @Override
+ public String toString() {
+ return "Announcement{" +
+ "id=" + id +
+ ", title=" + title +
+ ", content=" + content +
+ ", isTop=" + isTop +
+ ", status=" + status +
+ ", createTime=" + createTime +
+ ", creator=" + creator +
+ ", updateTime=" + updateTime +
+ ", updater=" + updater +
+ '}';
+ }
+}
diff --git a/src/main/java/com/amms/domain/dto/BatchAddReservationTimeSlotParam.java b/src/main/java/com/amms/domain/dto/BatchAddReservationTimeSlotParam.java
new file mode 100644
index 0000000..c4de86f
--- /dev/null
+++ b/src/main/java/com/amms/domain/dto/BatchAddReservationTimeSlotParam.java
@@ -0,0 +1,31 @@
+package com.amms.domain.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.util.Date;
+
+public class BatchAddReservationTimeSlotParam {
+ @JsonFormat(pattern = "yyyy-MM-dd")
+ private Date startDate;
+ @JsonFormat(pattern = "yyyy-MM-dd")
+ private Date endDate;
+ @JsonFormat(pattern = "HH:mm:ss")
+ private Date startTime;
+ @JsonFormat(pattern = "HH:mm:ss")
+ private Date endTime;
+ private Integer maxPeople;
+ private Long status;
+
+ public Date getStartDate() { return startDate; }
+ public void setStartDate(Date startDate) { this.startDate = startDate; }
+ public Date getEndDate() { return endDate; }
+ public void setEndDate(Date endDate) { this.endDate = endDate; }
+ public Date getStartTime() { return startTime; }
+ public void setStartTime(Date startTime) { this.startTime = startTime; }
+ public Date getEndTime() { return endTime; }
+ public void setEndTime(Date endTime) { this.endTime = endTime; }
+ public Integer getMaxPeople() { return maxPeople; }
+ public void setMaxPeople(Integer maxPeople) { this.maxPeople = maxPeople; }
+ public Long getStatus() { return status; }
+ public void setStatus(Long status) { this.status = status; }
+}
diff --git a/src/main/java/com/amms/mapper/AnnouncementMapper.java b/src/main/java/com/amms/mapper/AnnouncementMapper.java
new file mode 100644
index 0000000..a5fa8fe
--- /dev/null
+++ b/src/main/java/com/amms/mapper/AnnouncementMapper.java
@@ -0,0 +1,62 @@
+package com.amms.mapper;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Mapper;
+import com.amms.domain.Announcement;
+
+/**
+ * 公告Mapper接口
+ */
+@Mapper
+public interface AnnouncementMapper {
+ /**
+ * 查询公告
+ *
+ * @param id 公告主键
+ * @return 公告
+ */
+ public Announcement selectAnnouncementById(Long id);
+
+ /**
+ * 查询公告列表
+ *
+ * @param announcement 公告
+ * @return 公告集合
+ */
+ public List selectAnnouncementList(Announcement announcement);
+
+ /**
+ * 新增公告
+ *
+ * @param announcement 公告
+ * @return 结果
+ */
+ public int insertAnnouncement(Announcement announcement);
+
+ /**
+ * 修改公告
+ *
+ * @param announcement 公告
+ * @return 结果
+ */
+ public int updateAnnouncement(Announcement announcement);
+
+ /**
+ * 删除公告
+ *
+ * @param id 公告主键
+ * @return 结果
+ */
+ public int deleteAnnouncementById(Long id);
+
+ /**
+ * 查询置顶公告(显示状态)
+ */
+ public List selectTopAnnouncements();
+
+ /**
+ * 查询普通公告(非置顶且显示)
+ */
+ public List selectNormalAnnouncements(Announcement filter);
+
+}
diff --git a/src/main/java/com/amms/service/impl/AnnouncementServiceImpl.java b/src/main/java/com/amms/service/impl/AnnouncementServiceImpl.java
new file mode 100644
index 0000000..1adbe9e
--- /dev/null
+++ b/src/main/java/com/amms/service/impl/AnnouncementServiceImpl.java
@@ -0,0 +1,116 @@
+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.AnnouncementMapper;
+import com.amms.domain.Announcement;
+import com.amms.service.IAnnouncementService;
+import com.amms.security.SecurityUtils;
+
+/**
+ * 公告Service业务层处理
+ */
+@Service
+public class AnnouncementServiceImpl implements IAnnouncementService {
+
+ @Autowired
+ private AnnouncementMapper announcementMapper;
+
+ /**
+ * 查询公告列表
+ *
+ * @param announcement 公告
+ * @return 公告
+ */
+ @Override
+ public List selectAnnouncementList(Announcement announcement) {
+ return announcementMapper.selectAnnouncementList(announcement);
+ }
+
+ /**
+ * 查询公告
+ *
+ * @param id 公告主键
+ * @return 公告
+ */
+ @Override
+ public Announcement selectAnnouncementById(Long id) {
+ return announcementMapper.selectAnnouncementById(id);
+ }
+
+ /**
+ * 新增公告
+ *
+ * @param announcement 公告
+ * @return 结果
+ */
+ @Override
+ public int insertAnnouncement(Announcement announcement) {
+ announcement.setCreateTime(new Date());
+ announcement.setCreator(SecurityUtils.getCurrentUser().getId());
+ return announcementMapper.insertAnnouncement(announcement);
+ }
+
+ /**
+ * 修改公告
+ *
+ * @param announcement 公告
+ * @return 结果
+ */
+ @Override
+ public int updateAnnouncement(Announcement announcement) {
+ announcement.setUpdateTime(new Date());
+ announcement.setUpdater(SecurityUtils.getCurrentUser().getId());
+ return announcementMapper.updateAnnouncement(announcement);
+ }
+
+ /**
+ * 删除公告信息
+ *
+ * @param id 公告主键
+ * @return 结果
+ */
+ @Override
+ public int deleteAnnouncementById(Long id) {
+ return announcementMapper.deleteAnnouncementById(id);
+ }
+
+ @Override
+ public int setTop(Long id) {
+ Announcement query = new Announcement();
+ query.setIsTop(1L);
+ List tops = announcementMapper.selectAnnouncementList(query);
+ Long currentTopId = (tops != null && !tops.isEmpty()) ? tops.get(0).getId() : null;
+
+ Long userId = SecurityUtils.getCurrentUser().getId();
+ Date now = new Date();
+
+ if (currentTopId != null && !currentTopId.equals(id)) {
+ Announcement clearTop = new Announcement();
+ clearTop.setId(currentTopId);
+ clearTop.setIsTop(0L);
+ clearTop.setUpdater(userId);
+ clearTop.setUpdateTime(now);
+ announcementMapper.updateAnnouncement(clearTop);
+ }
+
+ Announcement setTop = new Announcement();
+ setTop.setId(id);
+ setTop.setIsTop(1L);
+ setTop.setUpdater(userId);
+ setTop.setUpdateTime(now);
+ return announcementMapper.updateAnnouncement(setTop);
+ }
+
+ @Override
+ public List selectTopAnnouncements() {
+ return announcementMapper.selectTopAnnouncements();
+ }
+
+ @Override
+ public List selectNormalAnnouncements(Announcement filter) {
+ return announcementMapper.selectNormalAnnouncements(filter);
+ }
+}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000..b54de7f
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -0,0 +1,70 @@
+spring:
+ application:
+ name: amms
+ jackson:
+ time-zone: GMT+8
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://localhost:3306/mms?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
+ username: root
+ password: Ding1998@
+ hikari:
+ max-lifetime: 3600000 # 最大生命周期
+ maximum-pool-size: 30 # 最大连接数
+ minimum-idle: 10 # 最小连接数
+ idle-timeout: 60000 # 空闲连接超时时间
+ connection-timeout: 60000 # 连接超时时间
+ # 文件上传
+ servlet:
+ multipart:
+ # 单个文件大小
+ max-file-size: 500MB
+ # 设置总上传的文件大小
+ max-request-size: 1000MB
+ data:
+ redis:
+ host: 127.0.0.1
+ port: 6379
+ password:
+ database: 1
+ lettuce:
+ pool:
+ # 连接池最大连接数(使用负值表示没有限制): 8
+ max-active: 8
+ # 连接池最大阻塞等待时间(使用负值表示没有限制)默认为-1
+ max-wait: -1
+ # 连接池中的最大空闲连接 默认为8
+ max-idle: 8
+ # 连接池中的最小空闲连接 默认为0
+ min-idle: 0
+server:
+ port: 8848
+ servlet:
+ context-path: /amms
+logging:
+ level:
+ root: info
+ sql: debug
+ web: info
+ file:
+ name: /Users/dmz/Work/Project/BS/2026/LogFiles/amms/log/app.log
+# token配置
+token:
+ # 令牌自定义标识
+ header: Authorization
+ # 令牌密钥
+ secret: abcdefghijklmnopqrstuvwxyz
+ # 令牌有效期(默认30分钟)
+ expireTime: 120
+# MyBatis配置
+mybatis:
+ # 搜索指定包别名
+ typeAliasesPackage: com.amms.domain
+ # 配置mapper的扫描,找到所有的mapper.xml映射文件
+ mapperLocations: classpath*:mapper/**/*Mapper.xml
+ # 加载全局的配置文件
+ configLocation: classpath:mybatis/mybatis-config.xml
+
+# 文件上传参数
+files:
+ path: /Users/dmz/Work/Project/BS/2026/Files/ammsFiles
diff --git a/src/main/resources/mapper/AnnouncementMapper.xml b/src/main/resources/mapper/AnnouncementMapper.xml
new file mode 100644
index 0000000..67038b8
--- /dev/null
+++ b/src/main/resources/mapper/AnnouncementMapper.xml
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id, title, content, is_top, status, create_time, creator, update_time, updater from announcement
+
+
+
+
+
+
+
+
+
+
+
+
+
+ insert into announcement
+
+ title,
+ content,
+ is_top,
+ status,
+ create_time,
+ creator,
+ update_time,
+ updater,
+
+
+ #{title},
+ #{content},
+ #{isTop},
+ #{status},
+ #{createTime},
+ #{creator},
+ #{updateTime},
+ #{updater},
+
+
+
+
+ update announcement
+
+ title = #{title},
+ content = #{content},
+ is_top = #{isTop},
+ status = #{status},
+ create_time = #{createTime},
+ creator = #{creator},
+ update_time = #{updateTime},
+ updater = #{updater},
+
+ where id = #{id}
+
+
+
+ delete from announcement where id = #{id}
+
+
diff --git a/src/test/java/org/example/bsbase2025/ApplicationTests.java b/src/test/java/org/example/bsbase2025/ApplicationTests.java
new file mode 100644
index 0000000..695a304
--- /dev/null
+++ b/src/test/java/org/example/bsbase2025/ApplicationTests.java
@@ -0,0 +1,14 @@
+package org.example.bsbase2025;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class ApplicationTests {
+
+ @Test
+ void contextLoads() throws JsonProcessingException {
+ }
+
+}
diff --git a/文件/22150110017陈素霞任务书.docx b/文件/22150110017陈素霞任务书.docx
new file mode 100644
index 0000000..b638c42
Binary files /dev/null and b/文件/22150110017陈素霞任务书.docx differ