试一下
This commit is contained in:
parent
6bc968ca6f
commit
6e02d90999
|
|
@ -0,0 +1,17 @@
|
||||||
|
import js from '@eslint/js'
|
||||||
|
import pluginVue from 'eslint-plugin-vue'
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
name: 'app/files-to-lint',
|
||||||
|
files: ['**/*.{js,mjs,jsx,vue}'],
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'app/files-to-ignore',
|
||||||
|
ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'],
|
||||||
|
},
|
||||||
|
|
||||||
|
js.configs.recommended,
|
||||||
|
...pluginVue.configs['flat/essential'],
|
||||||
|
]
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
|
|
@ -0,0 +1,41 @@
|
||||||
|
import axios from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询轮播图列表
|
||||||
|
export function listCarousel(query) {
|
||||||
|
return axios.get('/carousel/list',{
|
||||||
|
params: {
|
||||||
|
...query
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询全部轮播图列表
|
||||||
|
export function listAllCarousel(query) {
|
||||||
|
return axios.get('/carousel/listAll', {
|
||||||
|
params: {
|
||||||
|
...query
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询轮播图详细
|
||||||
|
export function getCarousel(id) {
|
||||||
|
return axios.get('/carousel/info/' + id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增轮播图
|
||||||
|
export function addCarousel(data) {
|
||||||
|
return axios.post('/carousel/add', {
|
||||||
|
...data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改轮播图
|
||||||
|
export function updateCarousel(data) {
|
||||||
|
return axios.put('/carousel', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除轮播图
|
||||||
|
export function delCarousel(id) {
|
||||||
|
return axios.delete('/carousel/' + id)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 6.6 KiB |
|
|
@ -0,0 +1,152 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<QuillEditor ref="myQuillEditor"
|
||||||
|
theme="snow"
|
||||||
|
v-model:content="content"
|
||||||
|
:options="data.editorOption"
|
||||||
|
contentType="html"
|
||||||
|
@update:content="setValue()"
|
||||||
|
/>
|
||||||
|
<!-- 使用自定义图片上传 -->
|
||||||
|
<el-upload
|
||||||
|
action="/api/files/upload"
|
||||||
|
:data="{filePath: filePath}"
|
||||||
|
:on-success="handleUploadSuccess"
|
||||||
|
name="file"
|
||||||
|
:show-file-list="false"
|
||||||
|
style="display: none"
|
||||||
|
ref="uploadRef"
|
||||||
|
>
|
||||||
|
</el-upload>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { QuillEditor } from '@vueup/vue-quill'
|
||||||
|
import '@vueup/vue-quill/dist/vue-quill.snow.css'
|
||||||
|
import { reactive, onMounted, ref, toRaw, getCurrentInstance, onUpdated, watch } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
|
||||||
|
const props = defineProps(['value', 'filePath'])
|
||||||
|
const emit = defineEmits(['updateValue'])
|
||||||
|
const content = ref('')
|
||||||
|
const myQuillEditor = ref()
|
||||||
|
const filePath = ref('')
|
||||||
|
const data = reactive({
|
||||||
|
content: '',
|
||||||
|
editorOption: {
|
||||||
|
modules: {
|
||||||
|
toolbar: [
|
||||||
|
['bold', 'italic', 'underline', 'strike'],
|
||||||
|
[{ 'size': ['small', false, 'large', 'huge'] }],
|
||||||
|
[{ 'font': [] }],
|
||||||
|
[{ 'align': [] }],
|
||||||
|
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
|
||||||
|
[{ 'indent': '-1' }, { 'indent': '+1' }],
|
||||||
|
[{ 'header': 1 }, { 'header': 2 }],
|
||||||
|
['image'],
|
||||||
|
[{ 'direction': 'rtl' }],
|
||||||
|
[{ 'color': [] }, { 'background': [] }]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
placeholder: '请输入内容...'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const uploadRef = ref('')
|
||||||
|
|
||||||
|
const imgHandler = (state) => {
|
||||||
|
if (state) {
|
||||||
|
uploadRef.value.$el.querySelector('input').click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 抛出更改内容,添加安全检查
|
||||||
|
const setValue = () => {
|
||||||
|
if (myQuillEditor.value) {
|
||||||
|
try {
|
||||||
|
const text = toRaw(myQuillEditor.value).getHTML();
|
||||||
|
emit('updateValue', text);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('获取HTML内容时出错:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleUploadSuccess(res, file) {
|
||||||
|
// 如果上传成功且编辑器实例存在
|
||||||
|
if (res && myQuillEditor.value) {
|
||||||
|
try {
|
||||||
|
// 获取富文本组件实例
|
||||||
|
const quill = toRaw(myQuillEditor.value).getQuill();
|
||||||
|
// 获取当前选择
|
||||||
|
const selection = quill.getSelection();
|
||||||
|
// 安全地获取光标位置,默认为文档末尾
|
||||||
|
const length = selection ? selection.index : quill.getLength();
|
||||||
|
// 插入图片 res.url为服务器返回的图片地址
|
||||||
|
quill.insertEmbed(length, "image", proxy.getFilePrefix + res);
|
||||||
|
// 安全地调整光标位置
|
||||||
|
try {
|
||||||
|
quill.setSelection(Math.min(length + 1, quill.getLength()));
|
||||||
|
} catch (e) {
|
||||||
|
// 光标位置设置失败不影响功能
|
||||||
|
console.warn('设置光标位置时出错:', e);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('插入图片时出错:', e);
|
||||||
|
ElMessage.error("图片插入失败");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ElMessage.error("图片插入失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onUpdated(() => {
|
||||||
|
// 只有当编辑器实例存在且值确实发生变化时才更新内容
|
||||||
|
if (myQuillEditor.value && props.value !== undefined) {
|
||||||
|
const quill = toRaw(myQuillEditor.value).getQuill();
|
||||||
|
const currentHtml = toRaw(myQuillEditor.value).getHTML();
|
||||||
|
|
||||||
|
// 避免不必要的更新
|
||||||
|
if ((props.value === '' || props.value === null || props.value === '<p></p>') && currentHtml !== '<p><br></p>') {
|
||||||
|
quill.setText('');
|
||||||
|
} else if (props.value && props.value !== currentHtml && props.value !== '<p></p>') {
|
||||||
|
try {
|
||||||
|
toRaw(myQuillEditor.value).setHTML(props.value);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('设置HTML内容时出错:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 初始化编辑器
|
||||||
|
onMounted(() => {
|
||||||
|
if (myQuillEditor.value) {
|
||||||
|
content.value = props.value || '';
|
||||||
|
const quill = toRaw(myQuillEditor.value).getQuill();
|
||||||
|
|
||||||
|
// 添加图片处理程序
|
||||||
|
try {
|
||||||
|
quill.getModule('toolbar').addHandler('image', imgHandler);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('添加工具栏处理程序时出错:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始设置内容
|
||||||
|
if (props.value && props.value !== '<p></p>') {
|
||||||
|
try {
|
||||||
|
toRaw(myQuillEditor.value).setHTML(props.value);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('初始化HTML内容时出错:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filePath.value = props.filePath;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,276 @@
|
||||||
|
<template>
|
||||||
|
<el-container>
|
||||||
|
<el-header class="top-header">
|
||||||
|
<div class="header-left">
|
||||||
|
<div class="logo">邺城博物馆</div>
|
||||||
|
</div>
|
||||||
|
<div class="header-center">
|
||||||
|
<el-menu
|
||||||
|
mode="horizontal"
|
||||||
|
:default-active="$route.path"
|
||||||
|
class="nav-menu"
|
||||||
|
:router="true"
|
||||||
|
background-color="#717171"
|
||||||
|
>
|
||||||
|
<template v-for="menu in touristMenuList" :key="menu.route">
|
||||||
|
<el-menu-item :index="menu.route" :route="menu.route">{{ menu.label }}</el-menu-item>
|
||||||
|
</template>
|
||||||
|
</el-menu>
|
||||||
|
</div>
|
||||||
|
<div class="header-right">
|
||||||
|
<div class="user" v-if="isLogged">
|
||||||
|
<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="handleMyReverse">我的预约</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click="handleMyCollection">我的收藏</el-dropdown-item>
|
||||||
|
<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>
|
||||||
|
<div class="login-btn" v-else>
|
||||||
|
<el-button type="text" @click="goLogin">登录</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-header>
|
||||||
|
<el-main>
|
||||||
|
<RouterView />
|
||||||
|
</el-main>
|
||||||
|
<el-footer class="site-footer">
|
||||||
|
<div class="footer-text">© {{ year }} 邺城博物馆 • 欢迎参观</div>
|
||||||
|
</el-footer>
|
||||||
|
</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, watch } from 'vue'
|
||||||
|
import { RouterView } from 'vue-router'
|
||||||
|
import { removeToken } from '@/utils/token'
|
||||||
|
import { updatePwd } from '@/api/sysUser';
|
||||||
|
import Cookies from 'js-cookie';
|
||||||
|
import { House, Collection, Calendar, Message, Star, User } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
|
const avatar = ref(Cookies.get('avatar'))
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
const getFilePrefix = proxy.getFilePrefix
|
||||||
|
const year = new Date().getFullYear()
|
||||||
|
const isLogged = ref(!!Cookies.get('role'))
|
||||||
|
|
||||||
|
const touristMenuList = ref([
|
||||||
|
{ label: '首页', route: '/tourist/home', icon: House },
|
||||||
|
{ label: '藏品', route: '/tourist/relic', icon: Collection },
|
||||||
|
{ label: '预约', route: '/tourist/reservation', icon: Calendar },
|
||||||
|
{ label: '公告', route: '/tourist/announcement', icon: Message },
|
||||||
|
// { label: '关于', route: '/tourist/userInfo', icon: User }
|
||||||
|
])
|
||||||
|
|
||||||
|
// 自定义确认密码校验规则
|
||||||
|
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 handleMyReverse() {
|
||||||
|
proxy.$router.push('/tourist/myReservation')
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 我的收藏操作 */
|
||||||
|
function handleMyCollection() {
|
||||||
|
proxy.$router.push('/tourist/myRelicCollection')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 修改密码操作 */
|
||||||
|
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('/tourist/userInfo')
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 退出登录操作 */
|
||||||
|
function handleLogout() {
|
||||||
|
console.log('退出登录')
|
||||||
|
proxy.$confirm('确定要退出系统吗?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
console.log('确定退出')
|
||||||
|
// 请求后端logout接口
|
||||||
|
|
||||||
|
// 清除本地token
|
||||||
|
removeToken()
|
||||||
|
Cookies.remove('role')
|
||||||
|
Cookies.remove('avatar')
|
||||||
|
Cookies.remove('username')
|
||||||
|
Cookies.remove('nickname')
|
||||||
|
isLogged.value = false
|
||||||
|
avatar.value = ''
|
||||||
|
// 跳转到登录页
|
||||||
|
proxy.$router.push('/login')
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
console.log('取消退出')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function goLogin() {
|
||||||
|
proxy.$router.push('/login')
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(() => proxy.$route.fullPath, () => {
|
||||||
|
isLogged.value = !!Cookies.get('role')
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.top-header {
|
||||||
|
height: 60px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 12px;
|
||||||
|
background: #1f1f1f;
|
||||||
|
color: #fff;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
.header-left { flex: 0 0 120px; }
|
||||||
|
.logo { font-size: 18px; font-weight: 700; letter-spacing: 2px; }
|
||||||
|
.header-center { flex: 1 1 70%; display: flex; justify-content: center; }
|
||||||
|
.header-right { flex: 0 0 80px; display: flex; align-items: center; justify-content: flex-end; }
|
||||||
|
.nav-menu { background: transparent; border-bottom: none; }
|
||||||
|
:deep(.nav-menu .el-menu-item) { color: #eaeaea; }
|
||||||
|
:deep(.nav-menu .el-menu-item.is-active) { color: #ffd04b; }
|
||||||
|
:deep(.nav-menu .el-menu-item:hover) { background: transparent; color: #ffffff; }
|
||||||
|
|
||||||
|
:deep(.nav-menu) { width: 100%; justify-content: center; }
|
||||||
|
:deep(.nav-menu .el-menu-item) { padding: 0 14px; min-width: auto; }
|
||||||
|
:deep(.nav-menu .el-menu-item:last-child) { display: inline-flex !important; }
|
||||||
|
|
||||||
|
:deep(.nav-menu .el-menu-item) { width: 150px; }
|
||||||
|
|
||||||
|
.top-header .user .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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-header .user .img:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0px 0px 20px #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-main {
|
||||||
|
background: #f2f2f2;
|
||||||
|
min-height: calc(100vh - 54px);
|
||||||
|
padding: 0;
|
||||||
|
margin-top: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-footer {
|
||||||
|
height: 54px;
|
||||||
|
background: #1a1a1a;
|
||||||
|
color: #cfcfcf;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-top: 1px solid #2a2a2a;
|
||||||
|
}
|
||||||
|
.footer-text { font-size: 13px; letter-spacing: 1px; }
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数处理
|
||||||
|
* @param {*} params 参数
|
||||||
|
*/
|
||||||
|
export function tansParams(params) {
|
||||||
|
let result = ''
|
||||||
|
for (const propName of Object.keys(params)) {
|
||||||
|
const value = params[propName];
|
||||||
|
const part = encodeURIComponent(propName) + "=";
|
||||||
|
if (value !== null && value !== "" && typeof (value) !== "undefined") {
|
||||||
|
if (typeof value === 'object') {
|
||||||
|
for (const key of Object.keys(value)) {
|
||||||
|
if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
|
||||||
|
const params = propName + '[' + key + ']';
|
||||||
|
const subPart = encodeURIComponent(params) + "=";
|
||||||
|
result += subPart + encodeURIComponent(value[key]) + "&";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result += part + encodeURIComponent(value) + "&";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 日期格式化
|
||||||
|
export function parseTime(time, pattern) {
|
||||||
|
return moment(time).format(pattern || 'YYYY-MM-DD HH:mm:ss')
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,338 @@
|
||||||
|
<template>
|
||||||
|
<div class="detail-container">
|
||||||
|
<div class="top-bar">
|
||||||
|
<el-button link size="large" :icon="ArrowLeft" @click="goBack">返回</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="detail-body" v-loading="loading">
|
||||||
|
<div class="media">
|
||||||
|
<div class="cover">
|
||||||
|
<el-image v-if="detail?.coverImageUrl" :src="getFilePrefix + detail.coverImageUrl" :preview-src-list="[getFilePrefix + detail.coverImageUrl]" preview-teleported fit="cover" />
|
||||||
|
<div v-else class="cover-empty">—</div>
|
||||||
|
<div v-if="detail?.modelUrl" class="badge360" @click="openModel">360</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info">
|
||||||
|
<div class="title">{{ detail?.name || '—' }}</div>
|
||||||
|
<!-- <div class="meta">
|
||||||
|
<span class="cat">{{ detail?.categoryInfo?.name || detail?.categoryId || '—' }}</span>
|
||||||
|
<span v-if="detail?.material" class="tag">{{ detail.material }}</span>
|
||||||
|
<span v-if="detail?.age" class="tag">{{ detail.age }}</span>
|
||||||
|
</div> -->
|
||||||
|
<div class="chips">
|
||||||
|
<span v-if="Number(detail?.isHot) === 1" class="chip hot">热门</span>
|
||||||
|
<!-- <span class="chip status" :class="Number(detail?.status) === 1 ? 'on' : 'off'">{{ Number(detail?.status) === 1 ? '显示' : '隐藏' }}</span> -->
|
||||||
|
</div>
|
||||||
|
<div class="kv-list">
|
||||||
|
<div class="kv-item">
|
||||||
|
<div class="kv-label">分类名称</div>
|
||||||
|
<div class="kv-val">{{ detail?.categoryInfo?.name || '—' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="kv-item">
|
||||||
|
<div class="kv-label">材质</div>
|
||||||
|
<div class="kv-val">{{ detail?.material || '—' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="kv-item">
|
||||||
|
<div class="kv-label">年代</div>
|
||||||
|
<div class="kv-val">{{ detail?.age || '—' }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="desc">
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">出土信息</div>
|
||||||
|
<div class="section-text">{{ detail?.excavationInfo || '—' }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="collect-bar" v-if="isLogin">
|
||||||
|
<el-button class="collect-btn" :type="isCollected ? 'danger' : 'warning'" size="large" @click="toggleCollect">
|
||||||
|
{{ isCollected ? '取消收藏' : '收藏' }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="story-panel">
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">文物故事</div>
|
||||||
|
<div class="section-text" v-html="detail?.story || '—'"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, getCurrentInstance, onMounted } from 'vue'
|
||||||
|
import { getRelic } from '@/api/relic'
|
||||||
|
import { addItemCollection, delItemCollection } from '@/api/itemCollection'
|
||||||
|
// 不再在前端获取当前用户ID,改由后端基于登录态判断
|
||||||
|
import { Back,ArrowLeft } from '@element-plus/icons-vue'
|
||||||
|
import Cookies from 'js-cookie'
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
const getFilePrefix = proxy.getFilePrefix
|
||||||
|
const loading = ref(true)
|
||||||
|
const detail = ref(null)
|
||||||
|
const isCollected = ref(false)
|
||||||
|
const collectionId = ref(null)
|
||||||
|
let relicIdCache = null
|
||||||
|
const isLogin = ref(!!Cookies.get('role'))
|
||||||
|
|
||||||
|
function formatDate(val) {
|
||||||
|
if (!val) return '—'
|
||||||
|
const d = new Date(val)
|
||||||
|
if (isNaN(d.getTime())) return '—'
|
||||||
|
const yyyy = d.getFullYear()
|
||||||
|
const MM = String(d.getMonth() + 1).padStart(2, '0')
|
||||||
|
const DD = String(d.getDate()).padStart(2, '0')
|
||||||
|
const HH = String(d.getHours()).padStart(2, '0')
|
||||||
|
const mm = String(d.getMinutes()).padStart(2, '0')
|
||||||
|
return `${yyyy}-${MM}-${DD} ${HH}:${mm}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function openModel() {
|
||||||
|
if (detail.value?.modelUrl) {
|
||||||
|
window.open(getFilePrefix + detail.value.modelUrl, '_blank')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function goBack() {
|
||||||
|
proxy.$router.back()
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshCollectStatus() {
|
||||||
|
if (!isLogin.value) {
|
||||||
|
isCollected.value = false
|
||||||
|
collectionId.value = null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const list = Array.isArray(detail.value?.itemCollections) ? detail.value.itemCollections : []
|
||||||
|
const mine = list.length ? list[0] : null
|
||||||
|
isCollected.value = !!mine
|
||||||
|
collectionId.value = mine ? mine.id : null
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchDetail() {
|
||||||
|
if (!relicIdCache) { loading.value = false; return }
|
||||||
|
getRelic(relicIdCache).then(res => {
|
||||||
|
detail.value = res.data || res
|
||||||
|
loading.value = false
|
||||||
|
refreshCollectStatus()
|
||||||
|
}).catch(() => { loading.value = false })
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleCollect() {
|
||||||
|
if (!relicIdCache) return
|
||||||
|
if (!isLogin.value) return
|
||||||
|
if (!isCollected.value) {
|
||||||
|
addItemCollection({ itemId: relicIdCache }).then(r => {
|
||||||
|
// proxy.$message.success((r && r.msg) || '已收藏')
|
||||||
|
fetchDetail()
|
||||||
|
})
|
||||||
|
} else if (collectionId.value) {
|
||||||
|
delItemCollection(collectionId.value).then(r => {
|
||||||
|
// proxy.$message.success((r && r.msg) || '已取消收藏')
|
||||||
|
fetchDetail()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const relicId = proxy.$route.params.relicId
|
||||||
|
relicIdCache = relicId
|
||||||
|
fetchDetail()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.detail-container {
|
||||||
|
width: 80%;
|
||||||
|
margin: 24px auto 40px;
|
||||||
|
padding-top: 16px;
|
||||||
|
}
|
||||||
|
.top-bar {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.detail-body {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1.3fr 1fr;
|
||||||
|
gap: 28px;
|
||||||
|
grid-auto-rows: min-content;
|
||||||
|
}
|
||||||
|
.media {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.cover {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 520px;
|
||||||
|
background: #f9f6f1;
|
||||||
|
border: 1px solid #e7dfcf;
|
||||||
|
border-radius: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.cover :deep(.el-image) {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.cover-empty {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #909399;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.badge360 {
|
||||||
|
position: absolute;
|
||||||
|
top: 16px;
|
||||||
|
left: 16px;
|
||||||
|
background: #ffffff;
|
||||||
|
color: #8a2b2b;
|
||||||
|
border: 1px solid #e8d9cf;
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-weight: 800;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.badge360:hover {
|
||||||
|
background: #fef4f4;
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: linear-gradient(180deg, #faf7f2 0%, #f7f3ea 100%);
|
||||||
|
border: 1px solid #e7dfcf;
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 16px 18px;
|
||||||
|
box-shadow: 0 6px 14px rgba(138,43,43,0.08);
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #2c1f1f;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.chips {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
.chip {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 4px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid #e8d9cf;
|
||||||
|
background: #f5e9e2;
|
||||||
|
color: #8a2b2b;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.chip.hot {
|
||||||
|
background: #ffefe6;
|
||||||
|
border-color: #ffd5bf;
|
||||||
|
color: #c64820;
|
||||||
|
}
|
||||||
|
.chip.status.on {
|
||||||
|
background: #e8f5e9;
|
||||||
|
border-color: #c8e6c9;
|
||||||
|
color: #2e7d32;
|
||||||
|
}
|
||||||
|
.chip.status.off {
|
||||||
|
background: #fdecea;
|
||||||
|
border-color: #f5c6c6;
|
||||||
|
color: #c62828;
|
||||||
|
}
|
||||||
|
.kv-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 10px 16px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.kv-item {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
.kv-label {
|
||||||
|
width: 80px;
|
||||||
|
color: #8a2b2b;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.kv-val {
|
||||||
|
color: #2c1f1f;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.cat {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #8a2b2b;
|
||||||
|
background: #f5e9e2;
|
||||||
|
border: 1px solid #e8d9cf;
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
}
|
||||||
|
.tag {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #2c1f1f;
|
||||||
|
background: #efe9df;
|
||||||
|
border: 1px solid #e0d6c7;
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
}
|
||||||
|
.desc {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
.section {
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #eadfce;
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
.section-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #2c1f1f;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.section-text {
|
||||||
|
color: #606266;
|
||||||
|
line-height: 1.9;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.story-panel {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
.collect-bar {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
.collect-btn {
|
||||||
|
padding: 18px 44px;
|
||||||
|
font-size: 18px;
|
||||||
|
border-radius: 999px;
|
||||||
|
box-shadow: 0 8px 18px rgba(138,43,43,0.12);
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.section-text :deep(img) {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
margin: 8px auto;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -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.Carousel;
|
||||||
|
import com.amms.service.ICarouselService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 轮播图Controller
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/carousel")
|
||||||
|
public class CarouselController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ICarouselService carouselService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询轮播图列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/list")
|
||||||
|
public PageInfo list(Carousel carousel, @RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize) {
|
||||||
|
PageHelper.startPage(pageNum, pageSize);
|
||||||
|
List<Carousel> carousels = carouselService.selectCarouselList(carousel);
|
||||||
|
return new PageInfo(carousels);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询全部轮播图列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/listAll")
|
||||||
|
public List<Carousel> listAll(Carousel carousel) {
|
||||||
|
return carouselService.selectCarouselList(carousel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取轮播图详细信息
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/info/{id}")
|
||||||
|
public Result getInfo(@PathVariable("id") Long id) {
|
||||||
|
return Result.success(carouselService.selectCarouselById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增轮播图
|
||||||
|
*/
|
||||||
|
@PostMapping("/add")
|
||||||
|
public Result add(@RequestBody Carousel carousel) {
|
||||||
|
return carouselService.insertCarousel(carousel) > 0 ? Result.success("新增成功") : Result.error("新增失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改轮播图
|
||||||
|
*/
|
||||||
|
@PutMapping
|
||||||
|
public Result update(@RequestBody Carousel carousel) {
|
||||||
|
return carouselService.updateCarousel(carousel) > 0 ? Result.success("修改成功") : Result.error("修改失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除轮播图
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public Result delete(@PathVariable Long id) {
|
||||||
|
return carouselService.deleteCarouselById(id) > 0 ? Result.success("删除成功") : Result.error("删除失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,161 @@
|
||||||
|
package com.amms.controller;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件处理controller
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/files")
|
||||||
|
public class FilesController {
|
||||||
|
|
||||||
|
private static Logger logger = LoggerFactory.getLogger(FilesController.class);
|
||||||
|
|
||||||
|
@Value("${files.path}")
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件上传
|
||||||
|
* @param file
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
@PostMapping("/upload")
|
||||||
|
@ResponseBody
|
||||||
|
public String upload(@RequestParam("file") MultipartFile file ,@RequestParam(name = "filePath" ,required = false) String filePath) throws IOException {
|
||||||
|
logger.info("上传文件:{}", file.getName());
|
||||||
|
File fileUploadPath = null;
|
||||||
|
// 创建目标路径
|
||||||
|
if (!filePath.equals("") && filePath != null) {
|
||||||
|
fileUploadPath = new File(path, filePath);
|
||||||
|
} else {
|
||||||
|
fileUploadPath = new File(path);
|
||||||
|
}
|
||||||
|
if (!fileUploadPath.exists()) {
|
||||||
|
fileUploadPath.mkdirs();
|
||||||
|
}
|
||||||
|
// 新文件名
|
||||||
|
String newFileName = UUID.randomUUID().toString().replace("-", "") + "-" + file.getOriginalFilename();
|
||||||
|
file.transferTo(new File(fileUploadPath, newFileName));
|
||||||
|
// 判断参数中filePath时候为null 不为空则拼接到新文件名前
|
||||||
|
if (!filePath.equals("") && filePath != null) {
|
||||||
|
if (filePath.endsWith("/")) {
|
||||||
|
newFileName = filePath + newFileName;
|
||||||
|
} else {
|
||||||
|
newFileName = filePath + "/" + newFileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
BufferedInputStream bis = null;
|
||||||
|
OutputStream os = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件(图片)
|
||||||
|
* @param fileName
|
||||||
|
* @param response
|
||||||
|
* @throws UnsupportedEncodingException
|
||||||
|
*/
|
||||||
|
@GetMapping("/get")
|
||||||
|
public void getImage(@RequestParam("fileName") String fileName, HttpServletResponse response) throws UnsupportedEncodingException {
|
||||||
|
logger.debug("加载图片,文件名:" + fileName);
|
||||||
|
File file = new File(path, fileName);
|
||||||
|
// 判断文件是否存在
|
||||||
|
if (!file.exists()) {
|
||||||
|
logger.error("文件【" + file.getAbsolutePath() + "】不存在!");
|
||||||
|
response.setStatus(404);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") );
|
||||||
|
response.setContentType("image/jpeg");
|
||||||
|
response.setContentLength((int)file.length());
|
||||||
|
FileInputStream is = null;
|
||||||
|
OutputStream os = null;
|
||||||
|
try {
|
||||||
|
is = new FileInputStream(file);
|
||||||
|
os = response.getOutputStream();
|
||||||
|
|
||||||
|
byte[] buf = new byte[8192];
|
||||||
|
int rd;
|
||||||
|
while ((rd = is.read(buf)) > 0)
|
||||||
|
os.write(buf, 0, rd);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e.getMessage());
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (is!=null) is.close();
|
||||||
|
if (os!=null) {
|
||||||
|
os.flush();
|
||||||
|
os.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除文件
|
||||||
|
* @param fileName
|
||||||
|
* @param response
|
||||||
|
* @throws UnsupportedEncodingException
|
||||||
|
*/
|
||||||
|
@GetMapping("/delete")
|
||||||
|
public void delete(@RequestParam("fileName") String fileName, HttpServletResponse response) throws UnsupportedEncodingException {
|
||||||
|
logger.error("删除文件,文件名:" + fileName);
|
||||||
|
File file = new File(path + fileName);
|
||||||
|
if (!file.exists()) {
|
||||||
|
logger.error("文件【" + fileName + "】不存在!");
|
||||||
|
response.setStatus(404);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
file.delete();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载文件
|
||||||
|
* @param fileName
|
||||||
|
* @param request
|
||||||
|
* @param response
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
@GetMapping("/download")
|
||||||
|
public void download(String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
|
logger.info("下载文件:{}", fileName);
|
||||||
|
File fileUploadPathFile = new File(path);
|
||||||
|
if (!fileUploadPathFile.exists()) {
|
||||||
|
fileUploadPathFile.mkdir();
|
||||||
|
}
|
||||||
|
File file = new File(fileUploadPathFile, fileName);
|
||||||
|
|
||||||
|
response.setContentType("application/octet-stream;charset=UTF-8");
|
||||||
|
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
|
||||||
|
response.setHeader("Content-Disposition","attachment;filename="+fileName);
|
||||||
|
response.setCharacterEncoding("UTF-8");
|
||||||
|
os = response.getOutputStream();
|
||||||
|
bis = new BufferedInputStream(new FileInputStream(file));
|
||||||
|
while(bis.read(buffer) != -1){
|
||||||
|
os.write(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
package com.amms.domain;
|
||||||
|
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 轮播图对象 carousel
|
||||||
|
*/
|
||||||
|
public class Carousel {
|
||||||
|
|
||||||
|
/** 轮播图id */
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/** 标题 */
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/** 图片地址 */
|
||||||
|
private String imageUrl;
|
||||||
|
|
||||||
|
/** 跳转链接 */
|
||||||
|
private String link;
|
||||||
|
|
||||||
|
/** 排序序号 */
|
||||||
|
private Integer sort;
|
||||||
|
|
||||||
|
/** 状态(0隐藏 1显示) */
|
||||||
|
private Long status;
|
||||||
|
|
||||||
|
/** 创建时间 */
|
||||||
|
@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 setImageUrl(String imageUrl) {
|
||||||
|
this.imageUrl = imageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getImageUrl() {
|
||||||
|
return imageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLink(String link) {
|
||||||
|
this.link = link;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLink() {
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSort(Integer sort) {
|
||||||
|
this.sort = sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSort() {
|
||||||
|
return sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(Long status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 "Carousel{" +
|
||||||
|
"id=" + id +
|
||||||
|
", title=" + title +
|
||||||
|
", imageUrl=" + imageUrl +
|
||||||
|
", link=" + link +
|
||||||
|
", sort=" + sort +
|
||||||
|
", status=" + status +
|
||||||
|
", createTime=" + createTime +
|
||||||
|
", updateTime=" + updateTime +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package com.amms.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import com.amms.domain.Carousel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 轮播图Mapper接口
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface CarouselMapper {
|
||||||
|
/**
|
||||||
|
* 查询轮播图
|
||||||
|
*
|
||||||
|
* @param id 轮播图主键
|
||||||
|
* @return 轮播图
|
||||||
|
*/
|
||||||
|
public Carousel selectCarouselById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询轮播图列表
|
||||||
|
*
|
||||||
|
* @param carousel 轮播图
|
||||||
|
* @return 轮播图集合
|
||||||
|
*/
|
||||||
|
public List<Carousel> selectCarouselList(Carousel carousel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增轮播图
|
||||||
|
*
|
||||||
|
* @param carousel 轮播图
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int insertCarousel(Carousel carousel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改轮播图
|
||||||
|
*
|
||||||
|
* @param carousel 轮播图
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int updateCarousel(Carousel carousel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除轮播图
|
||||||
|
*
|
||||||
|
* @param id 轮播图主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int deleteCarouselById(Long id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
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.CarouselMapper;
|
||||||
|
import com.amms.domain.Carousel;
|
||||||
|
import com.amms.service.ICarouselService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 轮播图Service业务层处理
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class CarouselServiceImpl implements ICarouselService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CarouselMapper carouselMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询轮播图列表
|
||||||
|
*
|
||||||
|
* @param carousel 轮播图
|
||||||
|
* @return 轮播图
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Carousel> selectCarouselList(Carousel carousel) {
|
||||||
|
return carouselMapper.selectCarouselList(carousel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询轮播图
|
||||||
|
*
|
||||||
|
* @param id 轮播图主键
|
||||||
|
* @return 轮播图
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Carousel selectCarouselById(Long id) {
|
||||||
|
return carouselMapper.selectCarouselById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增轮播图
|
||||||
|
*
|
||||||
|
* @param carousel 轮播图
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int insertCarousel(Carousel carousel) {
|
||||||
|
carousel.setCreateTime(new Date());
|
||||||
|
return carouselMapper.insertCarousel(carousel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改轮播图
|
||||||
|
*
|
||||||
|
* @param carousel 轮播图
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int updateCarousel(Carousel carousel) {
|
||||||
|
carousel.setUpdateTime(new Date());
|
||||||
|
return carouselMapper.updateCarousel(carousel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除轮播图信息
|
||||||
|
*
|
||||||
|
* @param id 轮播图主键
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int deleteCarouselById(Long id) {
|
||||||
|
return carouselMapper.deleteCarouselById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?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.CarouselMapper">
|
||||||
|
|
||||||
|
<resultMap type="com.amms.domain.Carousel" id="CarouselResult">
|
||||||
|
<result property="id" column="id" />
|
||||||
|
<result property="title" column="title" />
|
||||||
|
<result property="imageUrl" column="image_url" />
|
||||||
|
<result property="link" column="link" />
|
||||||
|
<result property="sort" column="sort" />
|
||||||
|
<result property="status" column="status" />
|
||||||
|
<result property="createTime" column="create_time" />
|
||||||
|
<result property="updateTime" column="update_time" />
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectCarouselVo">
|
||||||
|
select id, title, image_url, link, sort, status, create_time, update_time from carousel
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectCarouselList" parameterType="com.amms.domain.Carousel" resultMap="CarouselResult">
|
||||||
|
<include refid="selectCarouselVo"/>
|
||||||
|
<where>
|
||||||
|
<if test="title != null and title != ''"> and title = #{title}</if>
|
||||||
|
<if test="imageUrl != null and imageUrl != ''"> and image_url = #{imageUrl}</if>
|
||||||
|
<if test="link != null and link != ''"> and link = #{link}</if>
|
||||||
|
<if test="sort != null "> and sort = #{sort}</if>
|
||||||
|
<if test="status != null "> and status = #{status}</if>
|
||||||
|
</where>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectCarouselById" parameterType="Long" resultMap="CarouselResult">
|
||||||
|
<include refid="selectCarouselVo"/>
|
||||||
|
where id = #{id}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insertCarousel" parameterType="com.amms.domain.Carousel" useGeneratedKeys="true" keyProperty="id">
|
||||||
|
insert into carousel
|
||||||
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="title != null and title != ''">title,</if>
|
||||||
|
<if test="imageUrl != null and imageUrl != ''">image_url,</if>
|
||||||
|
<if test="link != null">link,</if>
|
||||||
|
<if test="sort != null">sort,</if>
|
||||||
|
<if test="status != null">status,</if>
|
||||||
|
<if test="createTime != null">create_time,</if>
|
||||||
|
<if test="updateTime != null">update_time,</if>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="title != null and title != ''">#{title},</if>
|
||||||
|
<if test="imageUrl != null and imageUrl != ''">#{imageUrl},</if>
|
||||||
|
<if test="link != null">#{link},</if>
|
||||||
|
<if test="sort != null">#{sort},</if>
|
||||||
|
<if test="status != null">#{status},</if>
|
||||||
|
<if test="createTime != null">#{createTime},</if>
|
||||||
|
<if test="updateTime != null">#{updateTime},</if>
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<update id="updateCarousel" parameterType="com.amms.domain.Carousel">
|
||||||
|
update carousel
|
||||||
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="title != null and title != ''">title = #{title},</if>
|
||||||
|
<if test="imageUrl != null and imageUrl != ''">image_url = #{imageUrl},</if>
|
||||||
|
<if test="link != null">link = #{link},</if>
|
||||||
|
<if test="sort != null">sort = #{sort},</if>
|
||||||
|
<if test="status != null">status = #{status},</if>
|
||||||
|
<if test="createTime != null">create_time = #{createTime},</if>
|
||||||
|
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||||
|
</trim>
|
||||||
|
where id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteCarouselById" parameterType="Long">
|
||||||
|
delete from carousel where id = #{id}
|
||||||
|
</delete>
|
||||||
|
</mapper>
|
||||||
Loading…
Reference in New Issue