mirror of
https://github.com/lkddi/nexusphp.git
synced 2026-04-21 02:20:54 +08:00
admin-import
This commit is contained in:
+170
-117
@@ -1,156 +1,209 @@
|
||||
<template>
|
||||
<el-container>
|
||||
<el-header>
|
||||
<el-row class="top-menu">
|
||||
<div class="part-left">
|
||||
<div class="layout">
|
||||
<el-container v-if="state.showMenu" class="container">
|
||||
<el-aside class="aside">
|
||||
<div class="head">
|
||||
<div>
|
||||
<a href="#">主站</a>
|
||||
<img src="https://s.weituibao.com/1582958061265/mlogo.png" alt="logo">
|
||||
<span>vue3 admin</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="part-center">
|
||||
<el-menu
|
||||
:default-active="activeIndex2"
|
||||
class="el-menu-demo"
|
||||
mode="horizontal"
|
||||
@select="handleSelect"
|
||||
background-color="#545c64"
|
||||
text-color="#fff"
|
||||
active-text-color="#ffd04b">
|
||||
<el-menu-item index="1">处理中心</el-menu-item>
|
||||
<el-submenu index="2">
|
||||
<template #title>我的工作台</template>
|
||||
<el-menu-item index="2-1">选项1</el-menu-item>
|
||||
<el-menu-item index="2-2">选项2</el-menu-item>
|
||||
<el-menu-item index="2-3">选项3</el-menu-item>
|
||||
<el-submenu index="2-4">
|
||||
<template #title>选项4</template>
|
||||
<el-menu-item index="2-4-1">选项1</el-menu-item>
|
||||
<el-menu-item index="2-4-2">选项2</el-menu-item>
|
||||
<el-menu-item index="2-4-3">选项3</el-menu-item>
|
||||
</el-submenu>
|
||||
</el-submenu>
|
||||
<el-menu-item index="3" disabled>消息中心</el-menu-item>
|
||||
<el-menu-item index="4"><a href="https://www.ele.me" target="_blank">订单管理</a></el-menu-item>
|
||||
</el-menu>
|
||||
</div>
|
||||
<div class="part-right">
|
||||
<div>个人信息</div>
|
||||
</div>
|
||||
</el-row>
|
||||
</el-header>
|
||||
<el-container>
|
||||
<el-aside width="200px">
|
||||
<div class="line" />
|
||||
<el-menu
|
||||
:uniqueOpened="true"
|
||||
default-active="2"
|
||||
class="el-menu-vertical-demo"
|
||||
@open="handleOpen"
|
||||
@close="handleClose"
|
||||
background-color="#545c64"
|
||||
text-color="#fff"
|
||||
active-text-color="#ffd04b">
|
||||
:default-openeds="state.defaultOpen"
|
||||
background-color="#222832"
|
||||
text-color="#fff"
|
||||
:router="true"
|
||||
:default-active='state.currentPath'
|
||||
>
|
||||
<el-submenu index="1">
|
||||
<template #title>
|
||||
<i class="el-icon-location"></i>
|
||||
<span>导航一</span>
|
||||
<span>Dashboard</span>
|
||||
</template>
|
||||
<el-menu-item-group>
|
||||
<template #title>分组一</template>
|
||||
<el-menu-item index="1-1">选项1</el-menu-item>
|
||||
<el-menu-item index="1-2">选项2</el-menu-item>
|
||||
<el-menu-item index="/introduce"><i class="el-icon-data-line" />系统介绍</el-menu-item>
|
||||
<el-menu-item index="/dashboard"><i class="el-icon-odometer" />Dashboard</el-menu-item>
|
||||
<el-menu-item index="/add"><i class="el-icon-plus" />添加商品</el-menu-item>
|
||||
</el-menu-item-group>
|
||||
<el-menu-item-group title="分组2">
|
||||
<el-menu-item index="1-3">选项3</el-menu-item>
|
||||
</el-menu-item-group>
|
||||
<el-submenu index="1-4">
|
||||
<template #title>选项4</template>
|
||||
<el-menu-item index="1-4-1">选项1</el-menu-item>
|
||||
</el-submenu>
|
||||
</el-submenu>
|
||||
<el-menu-item index="2">
|
||||
<i class="el-icon-menu"></i>
|
||||
<template #title>导航二</template>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="3" disabled>
|
||||
<i class="el-icon-document"></i>
|
||||
<template #title>导航三</template>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="4">
|
||||
<i class="el-icon-setting"></i>
|
||||
<template #title>导航四</template>
|
||||
</el-menu-item>
|
||||
<el-submenu index="5">
|
||||
<el-submenu index="2">
|
||||
<template #title>
|
||||
<i class="el-icon-location"></i>
|
||||
<span>导航一</span>
|
||||
<span>首页配置</span>
|
||||
</template>
|
||||
<el-menu-item-group>
|
||||
<template #title>分组一</template>
|
||||
<el-menu-item index="5-1">选项1</el-menu-item>
|
||||
<el-menu-item index="5-2">选项2</el-menu-item>
|
||||
<el-menu-item index="/swiper"><i class="el-icon-picture" />轮播图配置</el-menu-item>
|
||||
<el-menu-item index="/hot"><i class="el-icon-star-on" />热销商品配置</el-menu-item>
|
||||
<el-menu-item index="/new"><i class="el-icon-sell" />新品上线配置</el-menu-item>
|
||||
<el-menu-item index="/recommend"><i class="el-icon-thumb" />为你推荐配置</el-menu-item>
|
||||
</el-menu-item-group>
|
||||
<el-menu-item-group title="分组2">
|
||||
<el-menu-item index="5-3">选项3</el-menu-item>
|
||||
</el-submenu>
|
||||
<el-submenu index="3">
|
||||
<template #title>
|
||||
<span>模块管理</span>
|
||||
</template>
|
||||
<el-menu-item-group>
|
||||
<el-menu-item index="/category"><i class="el-icon-menu" />分类管理</el-menu-item>
|
||||
<el-menu-item index="/good"><i class="el-icon-s-goods" />商品管理</el-menu-item>
|
||||
<el-menu-item index="/guest"><i class="el-icon-user-solid" />会员管理</el-menu-item>
|
||||
<el-menu-item index="/order"><i class="el-icon-s-order" />订单管理</el-menu-item>
|
||||
</el-menu-item-group>
|
||||
</el-submenu>
|
||||
<el-submenu index="4">
|
||||
<template #title>
|
||||
<span>系统管理</span>
|
||||
</template>
|
||||
<el-menu-item-group>
|
||||
<el-menu-item index="/account"><i class="el-icon-lock" />修改密码</el-menu-item>
|
||||
<!-- <el-menu-item><i class="el-icon-upload2" />安全退出</el-menu-item> -->
|
||||
</el-menu-item-group>
|
||||
</el-submenu>
|
||||
</el-menu>
|
||||
</el-aside>
|
||||
<el-container>
|
||||
<el-main>Main</el-main>
|
||||
<el-footer>Footer</el-footer>
|
||||
<el-container class="content">
|
||||
<Header />
|
||||
<div class="main">
|
||||
<router-view />
|
||||
</div>
|
||||
<Footer />
|
||||
</el-container>
|
||||
</el-container>
|
||||
</el-container>
|
||||
<el-container v-else class="container">
|
||||
<router-view />
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive } from 'vue'
|
||||
import Header from '@/components/Header.vue'
|
||||
import Footer from '@/components/Footer.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { pathMap, localGet } from '@/utils'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
activeIndex: '1',
|
||||
activeIndex2: '1'
|
||||
};
|
||||
name: 'App',
|
||||
components: {
|
||||
Header,
|
||||
Footer
|
||||
},
|
||||
methods: {
|
||||
handleSelect(key, keyPath) {
|
||||
console.log(key, keyPath);
|
||||
console.log("select", this)
|
||||
},
|
||||
handleOpen(key, keyPath) {
|
||||
console.log(key, keyPath);
|
||||
console.log("open", this)
|
||||
},
|
||||
handleClose(key, keyPath) {
|
||||
console.log(key, keyPath);
|
||||
console.log("close", this)
|
||||
setup() {
|
||||
const noMenu = ['/login']
|
||||
const router = useRouter()
|
||||
const state = reactive({
|
||||
defaultOpen: ['1', '2', '3', '4'],
|
||||
showMenu: true,
|
||||
currentPath: '/dashboard',
|
||||
count: {
|
||||
number: 1
|
||||
}
|
||||
})
|
||||
router.beforeEach((to, from, next) => {
|
||||
if (to.path == '/login') {
|
||||
// 如果路径是 /login 则正常执行
|
||||
next()
|
||||
} else {
|
||||
// 如果不是 /login,判断是否有 token
|
||||
if (!localGet('token')) {
|
||||
// 如果没有,则跳至登录页面
|
||||
next({ path: '/login' })
|
||||
} else {
|
||||
// 否则继续执行
|
||||
next()
|
||||
}
|
||||
}
|
||||
state.showMenu = !noMenu.includes(to.path)
|
||||
state.currentPath = to.path
|
||||
document.title = pathMap[to.name]
|
||||
})
|
||||
return {
|
||||
state
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.el-header {
|
||||
padding: 0 !important;
|
||||
}
|
||||
.top-menu {
|
||||
background-color: rgb(84, 92, 100);
|
||||
padding: 0 30px;
|
||||
.part-left {
|
||||
<style scoped>
|
||||
.layout {
|
||||
min-height: 100vh;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.container {
|
||||
height: 100vh;
|
||||
}
|
||||
.aside {
|
||||
width: 200px!important;
|
||||
background-color: #222832;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
-ms-overflow-style: none;
|
||||
overflow: -moz-scrollbars-none;
|
||||
}
|
||||
.aside::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
a {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
.part-center {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
justify-content: center;
|
||||
height: 50px;
|
||||
}
|
||||
.part-right {
|
||||
.head > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.head img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.head span {
|
||||
font-size: 20px;
|
||||
color: #ffffff;
|
||||
}
|
||||
.line {
|
||||
border-top: 1px solid hsla(0,0%,100%,.05);
|
||||
border-bottom: 1px solid rgba(0,0,0,.2);
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
.main {
|
||||
height: calc(100vh - 100px);
|
||||
overflow: auto;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.el-menu {
|
||||
border-right: none!important;
|
||||
}
|
||||
.el-submenu {
|
||||
border-top: 1px solid hsla(0, 0%, 100%, .05);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, .2);
|
||||
}
|
||||
.el-submenu:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
.el-submenu [class^="el-icon-"] {
|
||||
vertical-align: -1px!important;
|
||||
}
|
||||
a {
|
||||
color: #409eff;
|
||||
text-decoration: none;
|
||||
}
|
||||
.el-pagination {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.el-popper__arrow {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="type == 'add' ? '添加分类' : '修改分类'"
|
||||
v-model="visible"
|
||||
width="400px"
|
||||
>
|
||||
<el-form :model="ruleForm" :rules="rules" ref="formRef" label-width="100px" class="good-form">
|
||||
<el-form-item label="商品名称" prop="name">
|
||||
<el-input type="text" v-model="ruleForm.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序值" prop="rank">
|
||||
<el-input type="number" v-model="ruleForm.rank"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, ref, toRefs } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import axios from '@/utils/axios'
|
||||
import { hasEmoji } from '@/utils/index'
|
||||
import { ElMessage } from 'element-plus'
|
||||
export default {
|
||||
name: 'DialogAddCategory',
|
||||
props: {
|
||||
type: String,
|
||||
reload: Function
|
||||
},
|
||||
setup(props) {
|
||||
const formRef = ref(null)
|
||||
const route = useRoute()
|
||||
const state = reactive({
|
||||
visible: false,
|
||||
categoryLevel: 1,
|
||||
parentId: 0,
|
||||
ruleForm: {
|
||||
name: '',
|
||||
rank: ''
|
||||
},
|
||||
rules: {
|
||||
name: [
|
||||
{ required: 'true', message: '名称不能为空', trigger: ['change'] }
|
||||
],
|
||||
rank: [
|
||||
{ required: 'true', message: '编号不能为空', trigger: ['change'] }
|
||||
]
|
||||
},
|
||||
id: ''
|
||||
})
|
||||
// 获取详情
|
||||
const getDetail = (id) => {
|
||||
axios.get(`/categories/${id}`).then(res => {
|
||||
state.ruleForm = {
|
||||
name: res.categoryName,
|
||||
rank: res.categoryRank
|
||||
}
|
||||
state.parentId = res.parentId
|
||||
state.categoryLevel = res.categoryLevel
|
||||
})
|
||||
}
|
||||
// 开启弹窗
|
||||
const open = (id) => {
|
||||
state.visible = true
|
||||
if (id) {
|
||||
state.id = id
|
||||
getDetail(id)
|
||||
} else {
|
||||
// 新增类目,从路由获取父分类id 和 分类级别
|
||||
const { level, parent_id } = route.query
|
||||
state.ruleForm = {
|
||||
name: '',
|
||||
rank: ''
|
||||
}
|
||||
state.parentId = parent_id
|
||||
state.categoryLevel = level
|
||||
}
|
||||
}
|
||||
// 关闭弹窗
|
||||
const close = () => {
|
||||
state.visible = false
|
||||
}
|
||||
const submitForm = () => {
|
||||
formRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
if (hasEmoji(state.ruleForm.name)) {
|
||||
ElMessage.error('不要输入表情包,再输入就打死你个龟孙儿~')
|
||||
return
|
||||
}
|
||||
if (props.type == 'add') {
|
||||
axios.post('/categories', {
|
||||
categoryLevel: state.categoryLevel,
|
||||
parentId: state.parentId,
|
||||
categoryName: state.ruleForm.name,
|
||||
categoryRank: state.ruleForm.rank
|
||||
}).then(() => {
|
||||
ElMessage.success('添加成功')
|
||||
state.visible = false
|
||||
if (props.reload) props.reload()
|
||||
})
|
||||
} else {
|
||||
axios.put('/categories', {
|
||||
categoryId: state.id,
|
||||
categoryLevel: state.categoryLevel,
|
||||
parentId: state.categoryLevel,
|
||||
categoryName: state.ruleForm.name,
|
||||
categoryRank: state.ruleForm.rank
|
||||
}).then(() => {
|
||||
ElMessage.success('修改成功')
|
||||
state.visible = false
|
||||
if (props.reload) props.reload()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
return {
|
||||
...toRefs(state),
|
||||
open,
|
||||
close,
|
||||
formRef,
|
||||
submitForm
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
@@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="type == 'add' ? '添加商品' : '修改商品'"
|
||||
v-model="visible"
|
||||
width="400px"
|
||||
>
|
||||
<el-form :model="ruleForm" :rules="rules" ref="formRef" label-width="100px" class="good-form">
|
||||
<el-form-item label="商品名称" prop="name">
|
||||
<el-input type="text" v-model="ruleForm.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="跳转链接" prop="link">
|
||||
<el-input type="text" v-model="ruleForm.link"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品编号" prop="id">
|
||||
<el-input type="number" min="0" v-model="ruleForm.id"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序值" prop="sort">
|
||||
<el-input type="number" v-model="ruleForm.sort"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, ref, toRefs } from 'vue'
|
||||
import axios from '@/utils/axios'
|
||||
import { hasEmoji } from '@/utils/index'
|
||||
import { ElMessage } from 'element-plus'
|
||||
export default {
|
||||
name: 'DialogAddHotGood',
|
||||
props: {
|
||||
type: String,
|
||||
configType: Number,
|
||||
reload: Function
|
||||
},
|
||||
setup(props) {
|
||||
const formRef = ref(null)
|
||||
const state = reactive({
|
||||
visible: false,
|
||||
ruleForm: {
|
||||
name: '',
|
||||
link: '',
|
||||
id: '',
|
||||
sort: ''
|
||||
},
|
||||
rules: {
|
||||
name: [
|
||||
{ required: 'true', message: '名称不能为空', trigger: ['change'] }
|
||||
],
|
||||
id: [
|
||||
{ required: 'true', message: '编号不能为空', trigger: ['change'] }
|
||||
],
|
||||
sort: [
|
||||
{ required: 'true', message: '排序不能为空', trigger: ['change'] }
|
||||
]
|
||||
},
|
||||
id: ''
|
||||
})
|
||||
// 获取详情
|
||||
const getDetail = (id) => {
|
||||
axios.get(`/indexConfigs/${id}`).then(res => {
|
||||
state.ruleForm = {
|
||||
name: res.configName,
|
||||
id: res.goodsId,
|
||||
link: res.redirectUrl,
|
||||
sort: res.configRank
|
||||
}
|
||||
})
|
||||
}
|
||||
// 开启弹窗
|
||||
const open = (id) => {
|
||||
state.visible = true
|
||||
if (id) {
|
||||
state.id = id
|
||||
getDetail(id)
|
||||
} else {
|
||||
state.ruleForm = {
|
||||
name: '',
|
||||
id: '',
|
||||
link: '',
|
||||
sort: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
// 关闭弹窗
|
||||
const close = () => {
|
||||
state.visible = false
|
||||
}
|
||||
const submitForm = () => {
|
||||
formRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
if (hasEmoji(state.ruleForm.name) || hasEmoji(state.ruleForm.link)) {
|
||||
ElMessage.error('不要输入表情包,再输入就打死你个龟孙儿~')
|
||||
return
|
||||
}
|
||||
if (state.ruleForm.id < 0 || state.ruleForm.id > 200) {
|
||||
ElMessage.error('商品编号不能小于 0 或大于 200')
|
||||
return
|
||||
}
|
||||
if (props.type == 'add') {
|
||||
axios.post('/indexConfigs', {
|
||||
configType: props.configType || 3,
|
||||
configName: state.ruleForm.name,
|
||||
redirectUrl: state.ruleForm.link,
|
||||
goodsId: state.ruleForm.id,
|
||||
configRank: state.ruleForm.sort
|
||||
}).then(() => {
|
||||
ElMessage.success('添加成功')
|
||||
state.visible = false
|
||||
if (props.reload) props.reload()
|
||||
})
|
||||
} else {
|
||||
axios.put('/indexConfigs', {
|
||||
configId: state.id,
|
||||
configType: props.configType || 3,
|
||||
configName: state.ruleForm.name,
|
||||
redirectUrl: state.ruleForm.link,
|
||||
goodsId: state.ruleForm.id,
|
||||
configRank: state.ruleForm.sort
|
||||
}).then(() => {
|
||||
ElMessage.success('修改成功')
|
||||
state.visible = false
|
||||
if (props.reload) props.reload()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
return {
|
||||
...toRefs(state),
|
||||
open,
|
||||
close,
|
||||
formRef,
|
||||
submitForm
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
@@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="type == 'add' ? '添加轮播图' : '修改轮播图'"
|
||||
v-model="visible"
|
||||
width="400px"
|
||||
>
|
||||
<el-form :model="ruleForm" :rules="rules" ref="formRef" label-width="100px" class="good-form">
|
||||
<el-form-item label="图片" prop="url">
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
:action="uploadImgServer"
|
||||
accept="jpg,jpeg,png"
|
||||
:headers="{
|
||||
token: token
|
||||
}"
|
||||
:show-file-list="false"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:on-success="handleUrlSuccess"
|
||||
>
|
||||
<img style="width: 200px; height: 100px; border: 1px solid #e9e9e9;" v-if="ruleForm.url" :src="ruleForm.url" class="avatar">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="跳转链接" prop="link">
|
||||
<el-input type="text" v-model="ruleForm.link"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序值" prop="sort">
|
||||
<el-input type="number" v-model="ruleForm.sort"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, ref, toRefs } from 'vue'
|
||||
import axios from '@/utils/axios'
|
||||
import { localGet, uploadImgServer, hasEmoji } from '@/utils'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
export default {
|
||||
name: 'DialogAddSwiper',
|
||||
props: {
|
||||
type: String,
|
||||
reload: Function
|
||||
},
|
||||
setup(props) {
|
||||
const formRef = ref(null)
|
||||
const state = reactive({
|
||||
uploadImgServer,
|
||||
token: localGet('token') || '',
|
||||
visible: false,
|
||||
ruleForm: {
|
||||
url: '',
|
||||
link: '',
|
||||
sort: ''
|
||||
},
|
||||
rules: {
|
||||
url: [
|
||||
{ required: 'true', message: '图片不能为空', trigger: ['change'] }
|
||||
],
|
||||
sort: [
|
||||
{ required: 'true', message: '排序不能为空', trigger: ['change'] }
|
||||
]
|
||||
},
|
||||
id: ''
|
||||
})
|
||||
// 获取详情
|
||||
const getDetail = (id) => {
|
||||
axios.get(`/carousels/${id}`).then(res => {
|
||||
state.ruleForm = {
|
||||
url: res.carouselUrl,
|
||||
link: res.redirectUrl,
|
||||
sort: res.carouselRank
|
||||
}
|
||||
})
|
||||
}
|
||||
const handleBeforeUpload = (file) => {
|
||||
const sufix = file.name.split('.')[1] || ''
|
||||
if (!['jpg', 'jpeg', 'png'].includes(sufix)) {
|
||||
ElMessage.error('请上传 jpg、jpeg、png 格式的图片')
|
||||
return false
|
||||
}
|
||||
}
|
||||
// 上传图片
|
||||
const handleUrlSuccess = (val) => {
|
||||
state.ruleForm.url = val.data || ''
|
||||
}
|
||||
// 开启弹窗
|
||||
const open = (id) => {
|
||||
state.visible = true
|
||||
if (id) {
|
||||
state.id = id
|
||||
getDetail(id)
|
||||
} else {
|
||||
state.ruleForm = {
|
||||
url: '',
|
||||
link: '',
|
||||
sort: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
// 关闭弹窗
|
||||
const close = () => {
|
||||
state.visible = false
|
||||
}
|
||||
const submitForm = () => {
|
||||
console.log(formRef.value.validate)
|
||||
formRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
if (hasEmoji(state.ruleForm.link)) {
|
||||
ElMessage.error('不要输入表情包,再输入就打死你个龟孙儿~')
|
||||
return
|
||||
}
|
||||
if (props.type == 'add') {
|
||||
axios.post('/carousels', {
|
||||
carouselUrl: state.ruleForm.url,
|
||||
redirectUrl: state.ruleForm.link,
|
||||
carouselRank: state.ruleForm.sort
|
||||
}).then(() => {
|
||||
ElMessage.success('添加成功')
|
||||
state.visible = false
|
||||
if (props.reload) props.reload()
|
||||
})
|
||||
} else {
|
||||
axios.put('/carousels', {
|
||||
carouselId: state.id,
|
||||
carouselUrl: state.ruleForm.url,
|
||||
redirectUrl: state.ruleForm.link,
|
||||
carouselRank: state.ruleForm.sort
|
||||
}).then(() => {
|
||||
ElMessage.success('修改成功')
|
||||
state.visible = false
|
||||
if (props.reload) props.reload()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
return {
|
||||
...toRefs(state),
|
||||
open,
|
||||
close,
|
||||
formRef,
|
||||
handleBeforeUpload,
|
||||
handleUrlSuccess,
|
||||
submitForm
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.avatar-uploader {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
color: #ddd;
|
||||
font-size: 30px;
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid #e9e9e9;
|
||||
padding: 32px 17px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<div class="footer">
|
||||
<div class="left">Copyright © 2019-2021 十三. All rights reserved.</div>
|
||||
<div class="right">
|
||||
<a target="_blank" href="https://github.com/newbee-ltd/vue3-admin">vue3-admin Version 3.0.0</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Footer'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.footer {
|
||||
height: 50px;
|
||||
border-top: 1px solid #e9e9e9;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<div class="header">
|
||||
<div class="left">
|
||||
<i v-if="hasBack" class="el-icon-back" @click="back"></i>
|
||||
<span style="font-size: 20px">{{ name }}</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
:width="320"
|
||||
trigger="click"
|
||||
popper-class="popper-user-box"
|
||||
>
|
||||
<template #reference>
|
||||
<div class="author">
|
||||
<i class="icon el-icon-s-custom" />
|
||||
{{ userInfo && userInfo.nickName || '' }}
|
||||
<i class="el-icon-caret-bottom" />
|
||||
</div>
|
||||
</template>
|
||||
<div class="nickname">
|
||||
<p>登录名:{{ userInfo && userInfo.loginUserName || '' }}</p>
|
||||
<p>昵称:{{ userInfo && userInfo.nickName || '' }}</p>
|
||||
<el-tag size="small" effect="dark" class="logout" @click="logout">退出</el-tag>
|
||||
</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { onMounted, reactive, toRefs } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import axios from '@/utils/axios'
|
||||
import { localRemove, pathMap } from '@/utils'
|
||||
export default {
|
||||
name: 'Header',
|
||||
setup() {
|
||||
const router = useRouter()
|
||||
const state = reactive({
|
||||
name: 'dashboard',
|
||||
userInfo: null,
|
||||
hasBack: false
|
||||
})
|
||||
onMounted(() => {
|
||||
const pathname = window.location.hash.split('/')[1] || ''
|
||||
if (!['login'].includes(pathname)) {
|
||||
getUserInfo()
|
||||
}
|
||||
})
|
||||
const getUserInfo = async () => {
|
||||
const userInfo = await axios.get('/adminUser/profile')
|
||||
state.userInfo = userInfo
|
||||
}
|
||||
const logout = () => {
|
||||
axios.delete('/logout').then(() => {
|
||||
localRemove('token')
|
||||
router.push({ path: '/login' })
|
||||
})
|
||||
}
|
||||
const back = () => {
|
||||
router.back()
|
||||
}
|
||||
router.afterEach((to) => {
|
||||
console.log('to', to)
|
||||
const { id } = to.query
|
||||
state.name = pathMap[to.name]
|
||||
if (id && to.name == 'add') {
|
||||
state.name = '编辑商品'
|
||||
}
|
||||
state.hasBack = ['level2', 'level3', 'order_detail'].includes(to.name)
|
||||
})
|
||||
return {
|
||||
...toRefs(state),
|
||||
logout,
|
||||
back
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.header {
|
||||
height: 50px;
|
||||
border-bottom: 1px solid #e9e9e9;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
}
|
||||
.el-icon-back {
|
||||
border: 1px solid #e9e9e9;
|
||||
padding: 4px;
|
||||
border-radius: 50px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.right > div > .icon{
|
||||
font-size: 18px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
.author {
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.popper-user-box {
|
||||
background: url('https://s.yezgea02.com/lingling-h5/static/account-banner-bg.png') 50% 50% no-repeat!important;
|
||||
background-size: cover!important;
|
||||
border-radius: 0!important;
|
||||
}
|
||||
.popper-user-box .nickname {
|
||||
position: relative;
|
||||
color: #ffffff;
|
||||
}
|
||||
.popper-user-box .nickname .logout {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@@ -1,58 +0,0 @@
|
||||
<template>
|
||||
<div class="hello">
|
||||
<h1>{{ msg }}</h1>
|
||||
<p>
|
||||
For a guide and recipes on how to configure / customize this project,<br>
|
||||
check out the
|
||||
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
|
||||
</p>
|
||||
<h3>Installed CLI Plugins</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
|
||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
|
||||
</ul>
|
||||
<h3>Essential Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
|
||||
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
|
||||
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
|
||||
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
|
||||
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
|
||||
</ul>
|
||||
<h3>Ecosystem</h3>
|
||||
<ul>
|
||||
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
|
||||
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
|
||||
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
|
||||
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
|
||||
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'HelloWorld',
|
||||
props: {
|
||||
msg: String
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
h3 {
|
||||
margin: 40px 0 0;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
li {
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
}
|
||||
a {
|
||||
color: #42b983;
|
||||
}
|
||||
</style>
|
||||
Vendored
+48
-4
@@ -1,8 +1,52 @@
|
||||
import { createApp } from 'vue'
|
||||
import ElementPlus from 'element-plus';
|
||||
import App from './App.vue'
|
||||
import installElementPlus from './plugins/element'
|
||||
import router from './router'
|
||||
import router from './router/index'
|
||||
|
||||
const app = createApp(App).use(router)
|
||||
installElementPlus(app)
|
||||
import 'element-plus/lib/theme-chalk/index.css'
|
||||
|
||||
// 修改后的主题样式必须放在最后面
|
||||
import '../theme/index.css'
|
||||
|
||||
const orderStatus = {
|
||||
0: '待支付',
|
||||
1: '已支付',
|
||||
2: '配货完成',
|
||||
3: '出库成功',
|
||||
4: '交易成功',
|
||||
'-1': '手动关闭',
|
||||
'-2': '超时关闭',
|
||||
'-3': '商家关闭'
|
||||
}
|
||||
|
||||
const app = createApp(App)
|
||||
// 全局过滤器
|
||||
app.config.globalProperties.$filters = {
|
||||
orderMap(status) {
|
||||
return orderStatus[status] || '未知状态'
|
||||
},
|
||||
prefix(url) {
|
||||
if (url && url.startsWith('http')) {
|
||||
return url
|
||||
} else {
|
||||
url = `http://backend-api-02.newbee.ltd${url}`
|
||||
return url
|
||||
}
|
||||
},
|
||||
resetImgUrl(imgObj, imgSrc, maxErrorNum) {
|
||||
if (maxErrorNum > 0) {
|
||||
imgObj.onerror = function() {
|
||||
resetImgUrl(imgObj, imgSrc, maxErrorNum - 1)
|
||||
}
|
||||
setTimeout(function() {
|
||||
imgObj.src = imgSrc
|
||||
}, 500)
|
||||
} else {
|
||||
imgObj.onerror = null
|
||||
imgObj.src = imgSrc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app.use(router).use(ElementPlus)
|
||||
app.mount('#app')
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<template>
|
||||
<h1>Agent Allow Page</h1>
|
||||
</template>
|
||||
@@ -1,3 +0,0 @@
|
||||
<template>
|
||||
<h1>Home Page</h1>
|
||||
</template>
|
||||
Vendored
+1
-3
@@ -1,7 +1,5 @@
|
||||
import ElementPlus from 'element-plus'
|
||||
import '../element-variables.scss'
|
||||
import locale from 'element-plus/lib/locale/lang/zh-cn'
|
||||
|
||||
export default (app) => {
|
||||
app.use(ElementPlus, { locale })
|
||||
app.use(ElementPlus, { locale })
|
||||
}
|
||||
|
||||
Vendored
+92
-20
@@ -1,23 +1,95 @@
|
||||
import { createWebHistory, createRouter } from "vue-router";
|
||||
import Home from "../pages/index";
|
||||
import AgentAllow from "../pages/agent-allow";
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: "/",
|
||||
name: "Home",
|
||||
component: Home,
|
||||
},
|
||||
{
|
||||
path: "/agent-allow",
|
||||
name: "Agent-allow",
|
||||
component: AgentAllow,
|
||||
},
|
||||
];
|
||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes,
|
||||
});
|
||||
history: createWebHashHistory(), // hash模式:createWebHashHistory,history模式:createWebHistory
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
redirect: '/introduce'
|
||||
},
|
||||
{
|
||||
path: '/introduce',
|
||||
name: 'introduce',
|
||||
component: () => import(/* webpackChunkName: "introduce" */ '../views/Introduce.vue')
|
||||
},
|
||||
{
|
||||
path: '/dashboard',
|
||||
name: 'dashboard',
|
||||
component: () => import(/* webpackChunkName: "dashboard" */ '../views/Index.vue')
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
component: () => import(/* webpackChunkName: "login" */ '../views/Login.vue')
|
||||
},
|
||||
{
|
||||
path: '/add',
|
||||
name: 'add',
|
||||
component: () => import(/* webpackChunkName: "add" */ '../views/AddGood.vue')
|
||||
},
|
||||
{
|
||||
path: '/swiper',
|
||||
name: 'swiper',
|
||||
component: () => import(/* webpackChunkName: "swiper" */ '../views/Swiper.vue')
|
||||
},
|
||||
{
|
||||
path: '/hot',
|
||||
name: 'hot',
|
||||
component: () => import(/* webpackChunkName: "hot" */ '../views/IndexConfig.vue')
|
||||
},
|
||||
{
|
||||
path: '/new',
|
||||
name: 'new',
|
||||
component: () => import(/* webpackChunkName: "new" */ '../views/IndexConfig.vue')
|
||||
},
|
||||
{
|
||||
path: '/recommend',
|
||||
name: 'recommend',
|
||||
component: () => import(/* webpackChunkName: "recommend" */ '../views/IndexConfig.vue')
|
||||
},
|
||||
{
|
||||
path: '/category',
|
||||
name: 'category',
|
||||
component: () => import(/* webpackChunkName: "category" */ '../views/Category.vue'),
|
||||
children: [
|
||||
{
|
||||
path: '/category/level2',
|
||||
name: 'level2',
|
||||
component: () => import(/* webpackChunkName: "level2" */ '../views/Category.vue'),
|
||||
},
|
||||
{
|
||||
path: '/category/level3',
|
||||
name: 'level3',
|
||||
component: () => import(/* webpackChunkName: "level3" */ '../views/Category.vue'),
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/good',
|
||||
name: 'good',
|
||||
component: () => import(/* webpackChunkName: "new" */ '../views/Good.vue')
|
||||
},
|
||||
{
|
||||
path: '/guest',
|
||||
name: 'guest',
|
||||
component: () => import(/* webpackChunkName: "guest" */ '../views/Guest.vue')
|
||||
},
|
||||
{
|
||||
path: '/order',
|
||||
name: 'order',
|
||||
component: () => import(/* webpackChunkName: "order" */ '../views/Order.vue')
|
||||
},
|
||||
{
|
||||
path: '/order_detail',
|
||||
name: 'order_detail',
|
||||
component: () => import(/* webpackChunkName: "order_detail" */ '../views/OrderDetail.vue')
|
||||
},
|
||||
{
|
||||
path: '/account',
|
||||
name: 'account',
|
||||
component: () => import(/* webpackChunkName: "account" */ '../views/Account.vue')
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
export default router;
|
||||
export default router
|
||||
Vendored
+35
@@ -0,0 +1,35 @@
|
||||
import axios from 'axios'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import router from '@/router/index'
|
||||
import { localGet } from './index'
|
||||
import config from '~/config'
|
||||
|
||||
|
||||
// 这边由于后端没有区分测试和正式,姑且都写成一个接口。
|
||||
axios.defaults.baseURL = config[import.meta.env.MODE].baseUrl
|
||||
// 携带 cookie,对目前的项目没有什么作用,因为我们是 token 鉴权
|
||||
axios.defaults.withCredentials = true
|
||||
// 请求头,headers 信息
|
||||
axios.defaults.headers['X-Requested-With'] = 'XMLHttpRequest'
|
||||
axios.defaults.headers['token'] = localGet('token') || ''
|
||||
// 默认 post 请求,使用 application/json 形式
|
||||
axios.defaults.headers.post['Content-Type'] = 'application/json'
|
||||
|
||||
// 请求拦截器,内部根据返回值,重新组装,统一管理。
|
||||
axios.interceptors.response.use(res => {
|
||||
if (typeof res.data !== 'object') {
|
||||
ElMessage.error('服务端异常!')
|
||||
return Promise.reject(res)
|
||||
}
|
||||
if (res.data.resultCode != 200) {
|
||||
if (res.data.message) ElMessage.error(res.data.message)
|
||||
if (res.data.resultCode == 419) {
|
||||
router.push({ path: '/login' })
|
||||
}
|
||||
return Promise.reject(res.data)
|
||||
}
|
||||
|
||||
return res.data.data
|
||||
})
|
||||
|
||||
export default axios
|
||||
Vendored
+46
@@ -0,0 +1,46 @@
|
||||
export function localGet (key) {
|
||||
const value = window.localStorage.getItem(key)
|
||||
try {
|
||||
return JSON.parse(window.localStorage.getItem(key))
|
||||
} catch (error) {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
export function localSet (key, value) {
|
||||
window.localStorage.setItem(key, JSON.stringify(value))
|
||||
}
|
||||
|
||||
export function localRemove (key) {
|
||||
window.localStorage.removeItem(key)
|
||||
}
|
||||
|
||||
// 判断内容是否含有表情字符,现有数据库不支持。
|
||||
export function hasEmoji (str = '') {
|
||||
const reg = /[^\u0020-\u007E\u00A0-\u00BE\u2E80-\uA4CF\uF900-\uFAFF\uFE30-\uFE4F\uFF00-\uFFEF\u0080-\u009F\u2000-\u201f\u2026\u2022\u20ac\r\n]/g;
|
||||
return str.match(reg) && str.match(reg).length
|
||||
}
|
||||
|
||||
// 单张图片上传
|
||||
export const uploadImgServer = 'http://backend-api-02.newbee.ltd/manage-api/v1/upload/file'
|
||||
// 多张图片上传
|
||||
export const uploadImgsServer = 'http://backend-api-02.newbee.ltd/manage-api/v1/upload/files'
|
||||
|
||||
export const pathMap = {
|
||||
login: '登录',
|
||||
introduce: '系统介绍',
|
||||
dashboard: '大盘数据',
|
||||
add: '添加商品',
|
||||
swiper: '轮播图配置',
|
||||
hot: '热销商品配置',
|
||||
new: '新品上线配置',
|
||||
recommend: '为你推荐配置',
|
||||
category: '分类管理',
|
||||
level2: '分类二级管理',
|
||||
level3: '分类三级管理',
|
||||
good: '商品管理',
|
||||
guest: '会员管理',
|
||||
order: '订单管理',
|
||||
order_detail: '订单详情',
|
||||
account: '修改账户'
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<el-card class="account-container">
|
||||
<el-form :model="nameForm" :rules="rules" ref="nameRef" label-width="80px" label-position="right" class="demo-ruleForm">
|
||||
<el-form-item required label="登录名:" prop="loginName">
|
||||
<el-input style="width: 200px" v-model="nameForm.loginName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item required label="昵称:" prop="nickName">
|
||||
<el-input style="width: 200px" v-model="nameForm.nickName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="danger" @click="submitName">确认修改</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<el-card class="account-container">
|
||||
<el-form :model="passForm" :rules="rules" ref="passRef" label-width="80px" label-position="right" class="demo-ruleForm">
|
||||
<el-form-item required label="原密码:" prop="oldpass">
|
||||
<el-input style="width: 200px" v-model="passForm.oldpass"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item required label="新密码:" prop="newpass">
|
||||
<el-input style="width: 200px" v-model="passForm.newpass"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="danger" @click="submitPass">确认修改</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { onMounted, reactive, ref, toRefs } from 'vue'
|
||||
import axios from '@/utils/axios'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import md5 from 'js-md5'
|
||||
export default {
|
||||
name: 'Account',
|
||||
setup() {
|
||||
const nameRef = ref(null)
|
||||
const passRef = ref(null)
|
||||
const state = reactive({
|
||||
user: null,
|
||||
nameForm: {
|
||||
loginName: '',
|
||||
nickName: ''
|
||||
},
|
||||
passForm: {
|
||||
oldpass: '',
|
||||
newpass: ''
|
||||
},
|
||||
rules: {
|
||||
loginName: [
|
||||
{ required: 'true', message: '登录名不能为空', trigger: ['change'] }
|
||||
],
|
||||
nickName: [
|
||||
{ required: 'true', message: '昵称不能为空', trigger: ['change'] }
|
||||
],
|
||||
oldpass: [
|
||||
{ required: 'true', message: '原密码不能为空', trigger: ['change'] }
|
||||
],
|
||||
newpass: [
|
||||
{ required: 'true', message: '新密码不能为空', trigger: ['change'] }
|
||||
]
|
||||
},
|
||||
})
|
||||
onMounted(() => {
|
||||
axios.get('/adminUser/profile').then(res => {
|
||||
state.user = res
|
||||
state.nameForm.loginName = res.loginUserName
|
||||
state.nameForm.nickName = res.nickName
|
||||
})
|
||||
})
|
||||
const submitName = () => {
|
||||
nameRef.value.validate((vaild) => {
|
||||
if (vaild) {
|
||||
axios.put('/adminUser/name', {
|
||||
loginUserName: state.nameForm.loginName,
|
||||
nickName: state.nameForm.nickName
|
||||
}).then(() => {
|
||||
ElMessage.success('修改成功')
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
const submitPass = () => {
|
||||
passRef.value.validate((vaild) => {
|
||||
if (vaild) {
|
||||
axios.put('/adminUser/password', {
|
||||
originalPassword: md5(state.passForm.oldpass),
|
||||
newPassword: md5(state.passForm.newpass)
|
||||
}).then(() => {
|
||||
ElMessage.success('修改成功')
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
return {
|
||||
...toRefs(state),
|
||||
nameRef,
|
||||
passRef,
|
||||
submitName,
|
||||
submitPass
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.account-container {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,267 @@
|
||||
<template>
|
||||
<div class="add">
|
||||
<el-card class="add-container">
|
||||
<el-form :model="goodForm" :rules="rules" ref="goodRef" label-width="100px" class="goodForm">
|
||||
<el-form-item required label="商品分类">
|
||||
<el-cascader :placeholder="defaultCate" style="width: 300px" :props="category" @change="handleChangeCate"></el-cascader>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品名称" prop="goodsName">
|
||||
<el-input style="width: 300px" v-model="goodForm.goodsName" placeholder="请输入商品名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品简介" prop="goodsIntro">
|
||||
<el-input style="width: 300px" type="textarea" v-model="goodForm.goodsIntro" placeholder="请输入商品简介(100字)"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品价格" prop="originalPrice">
|
||||
<el-input type="number" min="0" style="width: 300px" v-model="goodForm.originalPrice" placeholder="请输入商品价格"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品售卖价" prop="sellingPrice">
|
||||
<el-input type="number" min="0" style="width: 300px" v-model="goodForm.sellingPrice" placeholder="请输入商品售价"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品库存" prop="stockNum">
|
||||
<el-input type="number" min="0" style="width: 300px" v-model="goodForm.stockNum" placeholder="请输入商品库存"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品标签" prop="tag">
|
||||
<el-input style="width: 300px" v-model="goodForm.tag" placeholder="请输入商品小标签"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="上架状态" prop="goodsSellStatus">
|
||||
<el-radio-group v-model="goodForm.goodsSellStatus">
|
||||
<el-radio label="0">上架</el-radio>
|
||||
<el-radio label="1">下架</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item required label="商品主图" prop="goodsCoverImg">
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
:action="uploadImgServer"
|
||||
accept="jpg,jpeg,png"
|
||||
:headers="{
|
||||
token: token
|
||||
}"
|
||||
:show-file-list="false"
|
||||
:before-upload="handleBeforeUpload"
|
||||
:on-success="handleUrlSuccess"
|
||||
>
|
||||
<img style="width: 100px; height: 100px; border: 1px solid #e9e9e9;" v-if="goodForm.goodsCoverImg" :src="goodForm.goodsCoverImg" class="avatar">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="详情内容">
|
||||
<div ref='editor'></div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitAdd()">{{ id ? '立即修改' : '立即创建' }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, ref, toRefs, onMounted, onBeforeUnmount, getCurrentInstance } from 'vue'
|
||||
import WangEditor from 'wangeditor'
|
||||
import axios from '@/utils/axios'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { localGet, uploadImgServer, uploadImgsServer, hasEmoji } from '@/utils'
|
||||
export default {
|
||||
name: 'AddGood',
|
||||
setup() {
|
||||
const { proxy } = getCurrentInstance()
|
||||
console.log('proxy', proxy)
|
||||
const editor = ref(null)
|
||||
const goodRef = ref(null)
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const { id } = route.query
|
||||
const state = reactive({
|
||||
uploadImgServer,
|
||||
token: localGet('token') || '',
|
||||
id: id,
|
||||
defaultCate: '',
|
||||
goodForm: {
|
||||
goodsName: '',
|
||||
goodsIntro: '',
|
||||
originalPrice: '',
|
||||
sellingPrice: '',
|
||||
stockNum: '',
|
||||
goodsSellStatus: '0',
|
||||
goodsCoverImg: '',
|
||||
tag: ''
|
||||
},
|
||||
rules: {
|
||||
goodsName: [
|
||||
{ required: 'true', message: '请填写商品名称', trigger: ['change'] }
|
||||
],
|
||||
originalPrice: [
|
||||
{ required: 'true', message: '请填写商品价格', trigger: ['change'] }
|
||||
],
|
||||
sellingPrice: [
|
||||
{ required: 'true', message: '请填写商品售价', trigger: ['change'] }
|
||||
],
|
||||
stockNum: [
|
||||
{ required: 'true', message: '请填写商品库存', trigger: ['change'] }
|
||||
],
|
||||
},
|
||||
categoryId: '',
|
||||
category: {
|
||||
lazy: true,
|
||||
lazyLoad(node, resolve) {
|
||||
const { level = 0, value } = node
|
||||
axios.get('/categories', {
|
||||
params: {
|
||||
pageNumber: 1,
|
||||
pageSize: 1000,
|
||||
categoryLevel: level + 1,
|
||||
parentId: value || 0
|
||||
}
|
||||
}).then(res => {
|
||||
const list = res.list
|
||||
const nodes = list.map(item => ({
|
||||
value: item.categoryId,
|
||||
label: item.categoryName,
|
||||
leaf: level > 1
|
||||
}))
|
||||
resolve(nodes)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
let instance
|
||||
onMounted(() => {
|
||||
instance = new WangEditor(editor.value)
|
||||
instance.config.showLinkImg = false
|
||||
instance.config.showLinkImgAlt = false
|
||||
instance.config.showLinkImgHref = false
|
||||
instance.config.uploadImgMaxSize = 2 * 1024 * 1024 // 2M
|
||||
instance.config.uploadFileName = 'file'
|
||||
instance.config.uploadImgHeaders = {
|
||||
token: state.token
|
||||
}
|
||||
// 图片返回格式不同,需要自定义返回格式
|
||||
instance.config.uploadImgHooks = {
|
||||
// 图片上传并返回了结果,想要自己把图片插入到编辑器中
|
||||
// 例如服务器端返回的不是 { errno: 0, data: [...] } 这种格式,可使用 customInsert
|
||||
customInsert: function(insertImgFn, result) {
|
||||
console.log('result', result)
|
||||
// result 即服务端返回的接口
|
||||
// insertImgFn 可把图片插入到编辑器,传入图片 src ,执行函数即可
|
||||
if (result.data && result.data.length) {
|
||||
result.data.forEach(item => insertImgFn(item))
|
||||
}
|
||||
}
|
||||
}
|
||||
instance.config.uploadImgServer = uploadImgsServer
|
||||
Object.assign(instance.config, {
|
||||
onchange() {
|
||||
console.log('change')
|
||||
},
|
||||
})
|
||||
instance.create()
|
||||
if (id) {
|
||||
axios.get(`/goods/${id}`).then(res => {
|
||||
const { goods, firstCategory, secondCategory, thirdCategory } = res
|
||||
state.goodForm = {
|
||||
goodsName: goods.goodsName,
|
||||
goodsIntro: goods.goodsIntro,
|
||||
originalPrice: goods.originalPrice,
|
||||
sellingPrice: goods.sellingPrice,
|
||||
stockNum: goods.stockNum,
|
||||
goodsSellStatus: String(goods.goodsSellStatus),
|
||||
goodsCoverImg: proxy.$filters.prefix(goods.goodsCoverImg),
|
||||
tag: goods.tag
|
||||
}
|
||||
state.categoryId = goods.goodsCategoryId
|
||||
state.defaultCate = `${firstCategory.categoryName}/${secondCategory.categoryName}/${thirdCategory.categoryName}`
|
||||
if (instance) {
|
||||
// 初始化商品详情 html
|
||||
instance.txt.html(goods.goodsDetailContent)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
instance.destroy()
|
||||
instance = null
|
||||
})
|
||||
const submitAdd = () => {
|
||||
goodRef.value.validate((vaild) => {
|
||||
if (vaild) {
|
||||
// 默认新增用 post 方法
|
||||
let httpOption = axios.post
|
||||
let params = {
|
||||
goodsCategoryId: state.categoryId,
|
||||
goodsCoverImg: state.goodForm.goodsCoverImg,
|
||||
goodsDetailContent: instance.txt.html(),
|
||||
goodsIntro: state.goodForm.goodsIntro,
|
||||
goodsName: state.goodForm.goodsName,
|
||||
goodsSellStatus: state.goodForm.goodsSellStatus,
|
||||
originalPrice: state.goodForm.originalPrice,
|
||||
sellingPrice: state.goodForm.sellingPrice,
|
||||
stockNum: state.goodForm.stockNum,
|
||||
tag: state.goodForm.tag
|
||||
}
|
||||
if (hasEmoji(params.goodsIntro) || hasEmoji(params.goodsName) || hasEmoji(params.tag) || hasEmoji(params.goodsDetailContent)) {
|
||||
ElMessage.error('不要输入表情包,再输入就打死你个龟孙儿~')
|
||||
return
|
||||
}
|
||||
console.log('params', params)
|
||||
if (id) {
|
||||
params.goodsId = id
|
||||
// 修改商品使用 put 方法
|
||||
httpOption = axios.put
|
||||
}
|
||||
httpOption('/goods', params).then(() => {
|
||||
ElMessage.success(id ? '修改成功' : '添加成功')
|
||||
router.push({ path: '/good' })
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
const handleBeforeUpload = (file) => {
|
||||
const sufix = file.name.split('.')[1] || ''
|
||||
if (!['jpg', 'jpeg', 'png'].includes(sufix)) {
|
||||
ElMessage.error('请上传 jpg、jpeg、png 格式的图片')
|
||||
return false
|
||||
}
|
||||
}
|
||||
const handleUrlSuccess = (val) => {
|
||||
state.goodForm.goodsCoverImg = val.data || ''
|
||||
}
|
||||
const handleChangeCate = (val) => {
|
||||
state.categoryId = val[2] || 0
|
||||
}
|
||||
return {
|
||||
...toRefs(state),
|
||||
goodRef,
|
||||
submitAdd,
|
||||
handleBeforeUpload,
|
||||
handleUrlSuccess,
|
||||
editor,
|
||||
handleChangeCate
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.add {
|
||||
display: flex;
|
||||
}
|
||||
.add-container {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
}
|
||||
.avatar-uploader {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
color: #ddd;
|
||||
font-size: 30px;
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid #e9e9e9;
|
||||
padding: 32px 17px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,213 @@
|
||||
<template>
|
||||
<el-card class="category-container">
|
||||
<template #header>
|
||||
<div class="header">
|
||||
<el-button type="primary" size="small" icon="el-icon-plus" @click="handleAdd">增加</el-button>
|
||||
<el-popconfirm
|
||||
title="确定删除吗?"
|
||||
@confirm="handleDelete"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button type="danger" size="small" icon="el-icon-delete">批量删除</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</div>
|
||||
</template>
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
ref="multipleTable"
|
||||
:data="tableData"
|
||||
tooltip-effect="dark"
|
||||
style="width: 100%"
|
||||
@selection-change="handleSelectionChange">
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="categoryName"
|
||||
label="分类名称"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="categoryRank"
|
||||
label="排序值"
|
||||
width="120"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="createTime"
|
||||
label="添加时间"
|
||||
width="200"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="操作"
|
||||
width="220"
|
||||
>
|
||||
<template #default="scope">
|
||||
<a style="cursor: pointer; margin-right: 10px" @click="handleEdit(scope.row.categoryId)">修改</a>
|
||||
<a style="cursor: pointer; margin-right: 10px" @click="handleNext(scope.row)">下级分类</a>
|
||||
<el-popconfirm
|
||||
title="确定删除吗?"
|
||||
@confirm="handleDeleteOne(scope.row.categoryId)"
|
||||
>
|
||||
<template #reference>
|
||||
<a style="cursor: pointer">删除</a>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--总数超过一页,再展示分页器-->
|
||||
<el-pagination
|
||||
background
|
||||
layout="prev, pager, next"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:current-page="currentPage"
|
||||
@current-change="changePage"
|
||||
/>
|
||||
</el-card>
|
||||
<DialogAddCategory ref='addGood' :reload="getCategory" :type="type" :level="level" :parent_id="parent_id" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { onMounted, reactive, ref, toRefs } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import DialogAddCategory from '@/components/DialogAddCategory.vue'
|
||||
import axios from '@/utils/axios'
|
||||
export default {
|
||||
name: 'Category',
|
||||
components: {
|
||||
DialogAddCategory
|
||||
},
|
||||
setup() {
|
||||
const multipleTable = ref(null)
|
||||
const addGood = ref(null)
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const state = reactive({
|
||||
loading: false,
|
||||
tableData: [], // 数据列表
|
||||
multipleSelection: [], // 选中项
|
||||
total: 0, // 总条数
|
||||
currentPage: 1, // 当前页
|
||||
pageSize: 10, // 分页大小
|
||||
type: 'add', // 操作类型
|
||||
level: 1,
|
||||
parent_id: 0
|
||||
})
|
||||
onMounted(() => {
|
||||
getCategory()
|
||||
})
|
||||
router.afterEach((to) => {
|
||||
if (['category', 'level2', 'level3'].includes(to.name)) {
|
||||
getCategory()
|
||||
}
|
||||
})
|
||||
// 获取分类列表
|
||||
const getCategory = () => {
|
||||
const { level = 1, parent_id = 0 } = route.query
|
||||
state.loading = true
|
||||
axios.get('/categories', {
|
||||
params: {
|
||||
pageNumber: state.currentPage,
|
||||
pageSize: state.pageSize,
|
||||
categoryLevel: level,
|
||||
parentId: parent_id
|
||||
}
|
||||
}).then(res => {
|
||||
state.tableData = res.list
|
||||
state.total = res.totalCount
|
||||
state.currentPage = res.currPage
|
||||
state.loading = false
|
||||
state.level = level
|
||||
state.parentId = parent_id
|
||||
})
|
||||
}
|
||||
// 添加分类
|
||||
const handleAdd = () => {
|
||||
state.type = 'add'
|
||||
addGood.value.open()
|
||||
}
|
||||
// 修改分类
|
||||
const handleEdit = (id) => {
|
||||
state.type = 'edit'
|
||||
addGood.value.open(id)
|
||||
}
|
||||
// 选择项
|
||||
const handleSelectionChange = (val) => {
|
||||
state.multipleSelection = val
|
||||
}
|
||||
// 批量删除
|
||||
const handleDelete = () => {
|
||||
if (!state.multipleSelection.length) {
|
||||
ElMessage.error('请选择项')
|
||||
return
|
||||
}
|
||||
axios.delete('/categories', {
|
||||
data: {
|
||||
ids: state.multipleSelection.map(i => i.categoryId)
|
||||
}
|
||||
}).then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
getCategory()
|
||||
})
|
||||
}
|
||||
// 单个删除
|
||||
const handleDeleteOne = (id) => {
|
||||
axios.delete('/categories', {
|
||||
data: {
|
||||
ids: [id]
|
||||
}
|
||||
}).then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
getCategory()
|
||||
})
|
||||
}
|
||||
const changePage = (val) => {
|
||||
state.currentPage = val
|
||||
getCategory()
|
||||
}
|
||||
const handleNext = (item) => {
|
||||
const levelNumber = item.categoryLevel + 1
|
||||
if (levelNumber == 4) {
|
||||
ElMessage.error('没有下一级')
|
||||
return
|
||||
}
|
||||
router.push({
|
||||
name: `level${levelNumber}`,
|
||||
query: {
|
||||
level: levelNumber,
|
||||
parent_id: item.categoryId
|
||||
}
|
||||
})
|
||||
}
|
||||
return {
|
||||
...toRefs(state),
|
||||
multipleTable,
|
||||
handleSelectionChange,
|
||||
addGood,
|
||||
handleAdd,
|
||||
handleEdit,
|
||||
handleDelete,
|
||||
handleDeleteOne,
|
||||
getCategory,
|
||||
changePage,
|
||||
handleNext
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.category-container {
|
||||
min-height: 100%;
|
||||
}
|
||||
.el-card.is-always-shadow {
|
||||
min-height: 100%!important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,163 @@
|
||||
<template>
|
||||
<el-card class="swiper-container">
|
||||
<template #header>
|
||||
<div class="header">
|
||||
<el-button type="primary" size="small" icon="el-icon-plus" @click="handleAdd">新增商品</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
ref="multipleTable"
|
||||
:data="tableData"
|
||||
tooltip-effect="dark"
|
||||
style="width: 100%"
|
||||
@selection-change="handleSelectionChange">
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="goodsId"
|
||||
label="商品编号"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="goodsName"
|
||||
label="商品名"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="goodsIntro"
|
||||
label="商品简介"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="商品图片"
|
||||
width="150px"
|
||||
>
|
||||
<template #default="scope">
|
||||
<img style="width: 100px; height: 100px;" :key="scope.row.goodsId" :src="$filters.prefix(scope.row.goodsCoverImg)" alt="商品主图">
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="stockNum"
|
||||
label="商品库存"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="sellingPrice"
|
||||
label="商品售价"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="上架状态"
|
||||
>
|
||||
<template #default="scope">
|
||||
<span style="color: green;" v-if="scope.row.goodsSellStatus == 0">销售中</span>
|
||||
<span style="color: red;" v-else>已下架</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
label="操作"
|
||||
width="100"
|
||||
>
|
||||
<template #default="scope">
|
||||
<a style="cursor: pointer; margin-right: 10px" @click="handleEdit(scope.row.goodsId)">修改</a>
|
||||
<a style="cursor: pointer; margin-right: 10px" v-if="scope.row.goodsSellStatus == 0" @click="handleStatus(scope.row.goodsId, 1)">下架</a>
|
||||
<a style="cursor: pointer; margin-right: 10px" v-else @click="handleStatus(scope.row.goodsId, 0)">上架</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--总数超过一页,再展示分页器-->
|
||||
<el-pagination
|
||||
background
|
||||
layout="prev, pager, next"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:current-page="currentPage"
|
||||
@current-change="changePage"
|
||||
/>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { onMounted, reactive, ref, toRefs } from 'vue'
|
||||
import axios from '@/utils/axios'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useRouter } from 'vue-router'
|
||||
export default {
|
||||
name: 'Good',
|
||||
setup() {
|
||||
const multipleTable = ref(null)
|
||||
const router = useRouter()
|
||||
const state = reactive({
|
||||
loading: false,
|
||||
tableData: [], // 数据列表
|
||||
multipleSelection: [], // 选中项
|
||||
total: 0, // 总条数
|
||||
currentPage: 1, // 当前页
|
||||
pageSize: 10 // 分页大小
|
||||
})
|
||||
onMounted(() => {
|
||||
getGoodList()
|
||||
})
|
||||
// 获取轮播图列表
|
||||
const getGoodList = () => {
|
||||
state.loading = true
|
||||
axios.get('/goods/list', {
|
||||
params: {
|
||||
pageNumber: state.currentPage,
|
||||
pageSize: state.pageSize
|
||||
}
|
||||
}).then(res => {
|
||||
state.tableData = res.list
|
||||
state.total = res.totalCount
|
||||
state.currentPage = res.currPage
|
||||
state.loading = false
|
||||
})
|
||||
}
|
||||
const handleAdd = () => {
|
||||
router.push({ path: '/add' })
|
||||
}
|
||||
const handleEdit = (id) => {
|
||||
router.push({ path: '/add', query: { id } })
|
||||
}
|
||||
// 选择项
|
||||
const handleSelectionChange = (val) => {
|
||||
state.multipleSelection = val
|
||||
}
|
||||
const changePage = (val) => {
|
||||
state.currentPage = val
|
||||
getGoodList()
|
||||
}
|
||||
const handleStatus = (id, status) => {
|
||||
axios.put(`/goods/status/${status}`, {
|
||||
ids: id ? [id] : []
|
||||
}).then(() => {
|
||||
ElMessage.success('修改成功')
|
||||
getGoodList()
|
||||
})
|
||||
}
|
||||
return {
|
||||
...toRefs(state),
|
||||
multipleTable,
|
||||
handleSelectionChange,
|
||||
handleAdd,
|
||||
handleEdit,
|
||||
getGoodList,
|
||||
changePage,
|
||||
handleStatus
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.swiper-container {
|
||||
min-height: 100%;
|
||||
}
|
||||
.el-card.is-always-shadow {
|
||||
min-height: 100%!important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,168 @@
|
||||
<template>
|
||||
<el-card class="guest-container">
|
||||
<template #header>
|
||||
<div class="header">
|
||||
<el-button type="primary" size="small" icon="el-icon-plus" @click="handleSolve">解除禁用</el-button>
|
||||
<el-button type="danger" size="small" icon="el-icon-delete" @click="handleForbid">禁用账户</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
ref="multipleTable"
|
||||
:data="tableData"
|
||||
tooltip-effect="dark"
|
||||
style="width: 100%"
|
||||
@selection-change="handleSelectionChange">
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="nickName"
|
||||
label="昵称"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="loginName"
|
||||
label="登录名"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="身份状态"
|
||||
>
|
||||
<template #default="scope">
|
||||
<span :style="scope.row.lockedFlag == 0 ? 'color: green;' : 'color: red;'">
|
||||
{{ scope.row.lockedFlag == 0 ? '正常' : '禁用' }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="是否注销"
|
||||
>
|
||||
<template #default="scope">
|
||||
<span :style="scope.row.lockedFlag == 0 ? 'color: green;' : 'color: red;'">
|
||||
{{ scope.row.isDeleted == 0 ? '正常' : '注销' }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="createTime"
|
||||
label="注册时间"
|
||||
>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column
|
||||
label="操作"
|
||||
width="100"
|
||||
>
|
||||
<template #default="scope">
|
||||
<a style="cursor: pointer; margin-right: 10px" @confirm="handleSolve(scope.row)">解除禁用</a>
|
||||
<el-popconfirm
|
||||
title="确定禁用吗?"
|
||||
@confirm="handleForbid(scope.row)"
|
||||
>
|
||||
<template #reference>
|
||||
<a style="cursor: pointer">禁用账户</a>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
</el-table>
|
||||
<!--总数超过一页,再展示分页器-->
|
||||
<el-pagination
|
||||
background
|
||||
layout="prev, pager, next"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:current-page="currentPage"
|
||||
@current-change="changePage"
|
||||
/>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { onMounted, reactive, ref, toRefs } from 'vue'
|
||||
import axios from '@/utils/axios'
|
||||
import { ElMessage } from 'element-plus'
|
||||
export default {
|
||||
name: 'Guest',
|
||||
setup() {
|
||||
const multipleTable = ref(null)
|
||||
const state = reactive({
|
||||
loading: false,
|
||||
tableData: [], // 数据列表
|
||||
multipleSelection: [], // 选中项
|
||||
total: 0, // 总条数
|
||||
currentPage: 1, // 当前页
|
||||
pageSize: 10 // 分页大小
|
||||
})
|
||||
onMounted(() => {
|
||||
getGuestList()
|
||||
})
|
||||
// 获取轮播图列表
|
||||
const getGuestList = () => {
|
||||
state.loading = true
|
||||
axios.get('/users', {
|
||||
params: {
|
||||
pageNumber: state.currentPage,
|
||||
pageSize: state.pageSize
|
||||
}
|
||||
}).then(res => {
|
||||
state.tableData = res.list
|
||||
state.total = res.totalCount
|
||||
state.currentPage = res.currPage
|
||||
state.loading = false
|
||||
})
|
||||
}
|
||||
// 选择项
|
||||
const handleSelectionChange = (val) => {
|
||||
state.multipleSelection = val
|
||||
}
|
||||
const changePage = (val) => {
|
||||
state.currentPage = val
|
||||
getGuestList()
|
||||
}
|
||||
const handleSolve = () => {
|
||||
if (!state.multipleSelection.length) {
|
||||
ElMessage.error('请选择项')
|
||||
return
|
||||
}
|
||||
axios.put(`/users/0`, {
|
||||
ids: state.multipleSelection.map(item => item.userId)
|
||||
}).then(() => {
|
||||
ElMessage.success('解除成功')
|
||||
getGuestList()
|
||||
})
|
||||
}
|
||||
const handleForbid = () => {
|
||||
if (!state.multipleSelection.length) {
|
||||
ElMessage.error('请选择项')
|
||||
return
|
||||
}
|
||||
axios.put(`/users/1`, {
|
||||
ids: state.multipleSelection.map(item => item.userId)
|
||||
}).then(() => {
|
||||
ElMessage.success('禁用成功')
|
||||
getGuestList()
|
||||
})
|
||||
}
|
||||
return {
|
||||
...toRefs(state),
|
||||
multipleTable,
|
||||
handleSelectionChange,
|
||||
getGuestList,
|
||||
changePage,
|
||||
handleSolve,
|
||||
handleForbid
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.guest-container {
|
||||
min-height: 100%;
|
||||
}
|
||||
.el-card.is-always-shadow {
|
||||
min-height: 100%!important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<el-card class="introduce">
|
||||
<div class="order">
|
||||
<el-card class="order-item">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>今日订单数</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="item">1888</div>
|
||||
</el-card>
|
||||
<el-card class="order-item">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>今日日活</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="item">36271</div>
|
||||
</el-card>
|
||||
<el-card class="order-item">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>转化率</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="item">20%</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<div id="zoom"></div>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { onMounted, onUnmounted } from 'vue'
|
||||
|
||||
let myChart = null
|
||||
export default {
|
||||
name: 'Index',
|
||||
setup() {
|
||||
onMounted(() => {
|
||||
if (window.echarts) {
|
||||
// 基于准备好的dom,初始化echarts实例
|
||||
myChart = window.echarts.init(document.getElementById('zoom'))
|
||||
|
||||
// 指定图表的配置项和数据
|
||||
const option = {
|
||||
title: {
|
||||
text: '系统折线图'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
label: {
|
||||
backgroundColor: '#6a7985'
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: ['新增注册', '付费用户', '活跃用户', '订单数', '当日总收入']
|
||||
},
|
||||
toolbox: {
|
||||
feature: {
|
||||
saveAsImage: {}
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['2021-03-11', '2021-03-12', '2021-03-13', '2021-03-14', '2021-03-15', '2021-03-16', '2021-03-17']
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value'
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '新增注册',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
areaStyle: {},
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: [120, 132, 101, 134, 90, 230, 210]
|
||||
},
|
||||
{
|
||||
name: '付费用户',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
areaStyle: {},
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: [220, 182, 191, 234, 290, 330, 310]
|
||||
},
|
||||
{
|
||||
name: '活跃用户',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
areaStyle: {},
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: [150, 232, 201, 154, 190, 330, 410]
|
||||
},
|
||||
{
|
||||
name: '订单数',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
areaStyle: {},
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: [320, 332, 301, 334, 390, 330, 320]
|
||||
},
|
||||
{
|
||||
name: '当日总收入',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top'
|
||||
},
|
||||
areaStyle: {},
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: [820, 932, 901, 934, 1290, 1330, 1320]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 使用刚指定的配置项和数据显示图表。
|
||||
myChart.setOption(option)
|
||||
}
|
||||
})
|
||||
onUnmounted(() => {
|
||||
myChart.dispose()
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.introduce .order {
|
||||
display: flex;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
.introduce .order .order-item {
|
||||
flex: 1;
|
||||
margin-right: 20px;
|
||||
}
|
||||
.introduce .order .order-item:last-child{
|
||||
margin-right: 0;
|
||||
}
|
||||
#zoom {
|
||||
min-height: 300px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,211 @@
|
||||
<template>
|
||||
<el-card class="index-container">
|
||||
<template #header>
|
||||
<div class="header">
|
||||
<el-button type="primary" size="small" icon="el-icon-plus" @click="handleAdd">增加</el-button>
|
||||
<el-popconfirm
|
||||
title="确定删除吗?"
|
||||
@confirm="handleDelete"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button type="danger" size="small" icon="el-icon-delete">批量删除</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</div>
|
||||
</template>
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
ref="multipleTable"
|
||||
:data="tableData"
|
||||
tooltip-effect="dark"
|
||||
style="width: 100%"
|
||||
@selection-change="handleSelectionChange">
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="configName"
|
||||
label="商品名称"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="跳转链接"
|
||||
>
|
||||
<template #default="scope">
|
||||
<a target="_blank" :href="scope.row.redirectUrl">{{ scope.row.redirectUrl }}</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="configRank"
|
||||
label="排序值"
|
||||
width="120"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="goodsId"
|
||||
label="商品编号"
|
||||
width="200"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="createTime"
|
||||
label="添加时间"
|
||||
width="200"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="操作"
|
||||
width="100"
|
||||
>
|
||||
<template #default="scope">
|
||||
<a style="cursor: pointer; margin-right: 10px" @click="handleEdit(scope.row.configId)">修改</a>
|
||||
<el-popconfirm
|
||||
title="确定删除吗?"
|
||||
@confirm="handleDeleteOne(scope.row.configId)"
|
||||
>
|
||||
<template #reference>
|
||||
<a style="cursor: pointer">删除</a>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--总数超过一页,再展示分页器-->
|
||||
<el-pagination
|
||||
background
|
||||
layout="prev, pager, next"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:current-page="currentPage"
|
||||
@current-change="changePage"
|
||||
/>
|
||||
</el-card>
|
||||
<DialogAddGood ref='addGood' :reload="getIndexConfig" :type="type" :configType="configType" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { onMounted, reactive, ref, toRefs } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import DialogAddGood from '@/components/DialogAddGood.vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import axios from '@/utils/axios'
|
||||
// 首页配置类型参数
|
||||
const configTypeMap = {
|
||||
hot: 3,
|
||||
new: 4,
|
||||
recommend: 5
|
||||
}
|
||||
export default {
|
||||
name: 'Hot',
|
||||
components: {
|
||||
DialogAddGood
|
||||
},
|
||||
setup() {
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const multipleTable = ref(null)
|
||||
const addGood = ref(null)
|
||||
const state = reactive({
|
||||
loading: false,
|
||||
tableData: [], // 数据列表
|
||||
multipleSelection: [], // 选中项
|
||||
total: 0, // 总条数
|
||||
currentPage: 1, // 当前页
|
||||
pageSize: 10, // 分页大小
|
||||
type: 'add', // 操作类型
|
||||
configType: 3 // 3-(首页)热销商品 4-(首页)新品上线 5-(首页)为你推荐
|
||||
})
|
||||
// 监听路由变化
|
||||
router.beforeEach((to) => {
|
||||
if (['hot', 'new', 'recommend'].includes(to.name)) {
|
||||
state.configType = configTypeMap[to.name]
|
||||
state.currentPage = 1
|
||||
getIndexConfig()
|
||||
}
|
||||
})
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
state.configType = configTypeMap[route.name]
|
||||
getIndexConfig()
|
||||
})
|
||||
// 首页热销商品列表
|
||||
const getIndexConfig = () => {
|
||||
state.loading = true
|
||||
axios.get('/indexConfigs', {
|
||||
params: {
|
||||
pageNumber: state.currentPage,
|
||||
pageSize: state.pageSize,
|
||||
configType: state.configType
|
||||
}
|
||||
}).then(res => {
|
||||
state.tableData = res.list
|
||||
state.total = res.totalCount
|
||||
state.currentPage = res.currPage
|
||||
state.loading = false
|
||||
})
|
||||
}
|
||||
// 添加商品
|
||||
const handleAdd = () => {
|
||||
state.type = 'add'
|
||||
addGood.value.open()
|
||||
}
|
||||
// 修改商品
|
||||
const handleEdit = (id) => {
|
||||
state.type = 'edit'
|
||||
addGood.value.open(id)
|
||||
}
|
||||
// 选择项
|
||||
const handleSelectionChange = (val) => {
|
||||
state.multipleSelection = val
|
||||
}
|
||||
// 删除
|
||||
const handleDelete = () => {
|
||||
if (!state.multipleSelection.length) {
|
||||
ElMessage.error('请选择项')
|
||||
return
|
||||
}
|
||||
axios.post('/indexConfigs/delete', {
|
||||
ids: state.multipleSelection.map(i => i.configId)
|
||||
}).then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
getIndexConfig()
|
||||
})
|
||||
}
|
||||
// 单个删除
|
||||
const handleDeleteOne = (id) => {
|
||||
axios.post('/indexConfigs/delete', {
|
||||
ids: [id]
|
||||
}).then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
getIndexConfig()
|
||||
})
|
||||
}
|
||||
const changePage = (val) => {
|
||||
state.currentPage = val
|
||||
getIndexConfig()
|
||||
}
|
||||
return {
|
||||
...toRefs(state),
|
||||
multipleTable,
|
||||
handleSelectionChange,
|
||||
addGood,
|
||||
handleAdd,
|
||||
handleEdit,
|
||||
handleDelete,
|
||||
handleDeleteOne,
|
||||
getIndexConfig,
|
||||
changePage
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.index-container {
|
||||
min-height: 100%;
|
||||
}
|
||||
.el-card.is-always-shadow {
|
||||
min-height: 100%!important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<el-card class="account-container">
|
||||
<h1>系统简介</h1>
|
||||
<div style="line-height: 30px">
|
||||
vue3-admin 是一套企业级后台管理系统,基于 Spring Boot 、Vue 3.0 相关技术栈开发,供各位开发者们体验和学习,一定给你最好的学习体验。
|
||||
</div>
|
||||
<img style="width: 70%;
|
||||
display: block;
|
||||
margin: 0 auto;" src="https://s.yezgea02.com/1616331765416/WechatIMG40038.png" alt="">
|
||||
<h1>开发及部署文档</h1>
|
||||
<img style="width: 70%;
|
||||
display: block;
|
||||
margin: 0 auto;" src="https://s.yezgea02.com/1616938239101/419241616938196_.pic.jpg" />
|
||||
<ul class="course" @click="goJuejin">
|
||||
<li>开篇词:通关Vue3.0 企业级项目开发,升职加薪快人一步</li>
|
||||
<li>项目须知与课程约定</li>
|
||||
<li>大势所趋:“前后端分离”开发模式</li>
|
||||
<li>Vue 3.0 简介及开发环境搭建</li>
|
||||
<li>Vue 3.0 组合 API 入口 Setup 浅析</li>
|
||||
<li>Vue 3.0 之响应式系统 API</li>
|
||||
<li>Vue 3.0 之生命周期钩子函数、提供注入</li>
|
||||
<li>Vue 3.0 性能和业务层面上的提升</li>
|
||||
<li>Vite 2.0 原理分析及简单插件编写</li>
|
||||
<li>Vue-Router 4.x 使用方法及路由原理</li>
|
||||
<li>Vue 3.0 实战项目启动篇</li>
|
||||
<li>技术选型之 Spring Boot</li>
|
||||
<li>后端开发环境搭建</li>
|
||||
<li>快速搭建一个 Spring Boot 项目</li>
|
||||
<li>Spring Boot 实践之 Web 功能开发</li>
|
||||
<li>Spring Boot 实践之文件上传处理</li>
|
||||
<li>Spring Boot 实践之整合 MyBatis 操作数据库</li>
|
||||
<li>Spring Boot 实践之整合 Lombok</li>
|
||||
<li>Spring Boot 实践之整合 Swagger 生成接口文档</li>
|
||||
<li>后端 API 项目启动和运行注意事项</li>
|
||||
</ul>
|
||||
<ul class="course" @click="goJuejin">
|
||||
<li>接口参数处理和统一响应结果处理</li>
|
||||
<li>API 接口开发实战之用户登录接口开发</li>
|
||||
<li>API 接口开发实战之用户身份认证详解</li>
|
||||
<li>API 接口开发实战之轮播图管理模块接口开发</li>
|
||||
<li>API 接口开发实战之商品分类管理模块接口开发</li>
|
||||
<li>API 接口开发实战之商品管理模块接口开发</li>
|
||||
<li>API 接口开发实战之商品配置管理模块接口开发</li>
|
||||
<li>API 接口开发实战之订单管理模块接口开发</li>
|
||||
<li>成为一名有独立开发能力的前端工程师</li>
|
||||
<li>Vite 2.0 + Vue 3.0 + Element-plus 搭建管理后台项目</li>
|
||||
<li>Vue 3.0 实战之管理后台左右栏目布局(Menu 菜单组件)</li>
|
||||
<li>Vue 3.0 实战之登录鉴权(Form 表单组件)</li>
|
||||
<li>Vue 3.0 实战之首页大盘数据(Echart 5.x)</li>
|
||||
<li>Vue 3.0 实战之首页配置 Table</li>
|
||||
<li>Vue 3.0 实战之分类管理(多级共用 Table)</li>
|
||||
<li>Vue 3.0 实战之商品管理</li>
|
||||
<li>Vue 3.0 实战之订单管理(操作多级判断)</li>
|
||||
<li>Vue 3.0 实战之会员管理、账户修改</li>
|
||||
<li>pm2 实现一键部署云端服务器</li>
|
||||
<li>常见问题汇总讲解</li>
|
||||
</ul>
|
||||
<h1>技术选型</h1>
|
||||
<ul style="font-weight: bold;">
|
||||
<li>Vue 3.x</li>
|
||||
<li>Vite 2.x</li>
|
||||
<li>Vue-Router 4.x</li>
|
||||
<li>Element-Plus(适配全新 Vue 3.x 的 PC 端组件库)</li>
|
||||
<li>Echarts 5.0</li>
|
||||
<li>axios</li>
|
||||
<li>wangEditor</li>
|
||||
</ul>
|
||||
<h1>联系作者</h1>
|
||||
<ul>
|
||||
<li>我的邮箱:2449207463@qq.com</li>
|
||||
<li>QQ技术交流群:932227898、707779034</li>
|
||||
</ul>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Introduce',
|
||||
setup() {
|
||||
const goJuejin = () => {
|
||||
console.log('goJuejin')
|
||||
window.open('https://juejin.cn/book/6933939264455442444', 'target')
|
||||
}
|
||||
|
||||
return {
|
||||
goJuejin
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.course {
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
}
|
||||
.course li {
|
||||
line-height: 36px;
|
||||
color: #409eff;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<div class="login-body">
|
||||
<div class="login-container">
|
||||
<div class="head">
|
||||
<img class="logo" src="https://s.weituibao.com/1582958061265/mlogo.png" />
|
||||
<div class="name">
|
||||
<div class="title">新蜂商城</div>
|
||||
<div class="tips">Vue3.0 后台管理系统</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-form label-position="top" :rules="rules" :model="ruleForm" ref="loginForm" class="login-form">
|
||||
<el-form-item label="账号" prop="username">
|
||||
<el-input type="text" v-model.trim="ruleForm.username" autocomplete="off"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input type="password" v-model.trim="ruleForm.password" autocomplete="off"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div style="color: #333">登录表示您已同意<a>《服务条款》</a></div>
|
||||
<el-button style="width: 100%" type="primary" @click="submitForm">立即登录</el-button>
|
||||
<el-checkbox v-model="checked" @change="!checked">下次自动登录</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from '@/utils/axios'
|
||||
import md5 from 'js-md5'
|
||||
import { reactive, ref, toRefs } from 'vue'
|
||||
import { localSet } from '@/utils'
|
||||
export default {
|
||||
name: 'Login',
|
||||
setup() {
|
||||
const loginForm = ref(null)
|
||||
const state = reactive({
|
||||
ruleForm: {
|
||||
username: '',
|
||||
password: ''
|
||||
},
|
||||
checked: true,
|
||||
rules: {
|
||||
username: [
|
||||
{ required: 'true', message: '账户不能为空', trigger: 'blur' }
|
||||
],
|
||||
password: [
|
||||
{ required: 'true', message: '密码不能为空', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
})
|
||||
const submitForm = async () => {
|
||||
loginForm.value.validate((valid) => {
|
||||
if (valid) {
|
||||
axios.post('/adminUser/login', {
|
||||
userName: state.ruleForm.username || '',
|
||||
passwordMd5: md5(state.ruleForm.password)
|
||||
}).then(res => {
|
||||
localSet('token', res)
|
||||
window.location.href = '/'
|
||||
})
|
||||
} else {
|
||||
console.log('error submit!!')
|
||||
return false;
|
||||
}
|
||||
})
|
||||
}
|
||||
const resetForm = () => {
|
||||
loginForm.value.resetFields();
|
||||
}
|
||||
return {
|
||||
...toRefs(state),
|
||||
loginForm,
|
||||
submitForm,
|
||||
resetForm
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.login-body {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
/* background-image: linear-gradient(25deg, #077f7c, #3aa693, #5ecfaa, #7ffac2); */
|
||||
}
|
||||
.login-container {
|
||||
width: 420px;
|
||||
height: 500px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0px 21px 41px 0px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.head {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 40px 0 20px 0;
|
||||
}
|
||||
.head img {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
.head .title {
|
||||
font-size: 28px;
|
||||
color: #1BAEAE;
|
||||
font-weight: bold;
|
||||
}
|
||||
.head .tips {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
.login-form {
|
||||
width: 70%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.el-form--label-top .el-form-item__label {
|
||||
padding: 0;
|
||||
}
|
||||
.login-form .el-form-item {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,276 @@
|
||||
<template>
|
||||
<el-card class="order-container">
|
||||
<template #header>
|
||||
<div class="header">
|
||||
<el-input
|
||||
style="width: 200px; margin-right: 10px"
|
||||
placeholder="请输入订单号"
|
||||
v-model="orderNo"
|
||||
@change="handleOption"
|
||||
size="small"
|
||||
clearable
|
||||
/>
|
||||
<el-select @change="handleOption" v-model="orderStatus" size="small" style="width: 200px; margin-right: 10px">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
<!-- <el-button type="primary" size="small" icon="el-icon-edit">修改订单</el-button> -->
|
||||
<el-button type="primary" size="small" icon="el-icon-s-home" @click="handleConfig()">配货完成</el-button>
|
||||
<el-button type="primary" size="small" icon="el-icon-s-home" @click="handleSend()">出库</el-button>
|
||||
<el-button type="danger" size="small" icon="el-icon-delete" @click="handleClose()">关闭订单</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
ref="multipleTable"
|
||||
:data="tableData"
|
||||
tooltip-effect="dark"
|
||||
style="width: 100%"
|
||||
@selection-change="handleSelectionChange">
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="orderNo"
|
||||
label="订单号"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="totalPrice"
|
||||
label="订单总价"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="orderStatus"
|
||||
label="订单状态"
|
||||
>
|
||||
<template #default="scope">
|
||||
<span>{{ $filters.orderMap(scope.row.orderStatus) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="payType"
|
||||
label="支付方式"
|
||||
>
|
||||
<template #default='scope'>
|
||||
<span v-if="scope.row.payType == 1">微信支付</span>
|
||||
<span v-else-if="scope.row.payType == 2">支付宝支付</span>
|
||||
<span v-else>未知</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="createTime"
|
||||
label="创建时间"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="操作"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-popconfirm
|
||||
v-if="scope.row.orderStatus == 1"
|
||||
title="确定配货完成吗?"
|
||||
@confirm="handleConfig(scope.row.orderId)"
|
||||
>
|
||||
<template #reference>
|
||||
<a style="cursor: pointer; margin-right: 10px">配货完成</a>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
<el-popconfirm
|
||||
v-if="scope.row.orderStatus == 2"
|
||||
title="确定出库吗?"
|
||||
@confirm="handleSend(scope.row.orderId)"
|
||||
>
|
||||
<template #reference>
|
||||
<a style="cursor: pointer; margin-right: 10px">出库</a>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
<el-popconfirm
|
||||
v-if="!(scope.row.orderStatus == 4 || scope.row.orderStatus < 0)"
|
||||
title="确定关闭订单吗?"
|
||||
@confirm="handleClose(scope.row.orderId)"
|
||||
>
|
||||
<template #reference>
|
||||
<a style="cursor: pointer; margin-right: 10px">关闭订单</a>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
<router-link :to="{ path: '/order_detail', query: { id: scope.row.orderId }}">订单详情</router-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--总数超过一页,再展示分页器-->
|
||||
<el-pagination
|
||||
background
|
||||
layout="prev, pager, next"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:current-page="currentPage"
|
||||
@current-change="changePage"
|
||||
/>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { onMounted, reactive, ref, toRefs } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import axios from '@/utils/axios'
|
||||
export default {
|
||||
name: 'Order',
|
||||
setup() {
|
||||
const multipleTable = ref(null)
|
||||
const addGood = ref(null)
|
||||
const state = reactive({
|
||||
loading: false,
|
||||
tableData: [], // 数据列表
|
||||
multipleSelection: [], // 选中项
|
||||
total: 0, // 总条数
|
||||
currentPage: 1, // 当前页
|
||||
pageSize: 10, // 分页大小
|
||||
orderNo: '', // 订单号
|
||||
orderStatus: '', // 订单状态
|
||||
options: [{
|
||||
value: '',
|
||||
label: '全部'
|
||||
}, {
|
||||
value: 0,
|
||||
label: '待支付'
|
||||
}, {
|
||||
value: 1,
|
||||
label: '已支付'
|
||||
}, {
|
||||
value: 2,
|
||||
label: '配货完成'
|
||||
}, {
|
||||
value: 3,
|
||||
label: '出库成功'
|
||||
}, {
|
||||
value: 4,
|
||||
label: '交易成功'
|
||||
}, {
|
||||
value: -1,
|
||||
label: '手动关闭'
|
||||
}, {
|
||||
value: -2,
|
||||
label: '超时关闭'
|
||||
}, {
|
||||
value: -3,
|
||||
label: '商家关闭'
|
||||
}]
|
||||
})
|
||||
onMounted(() => {
|
||||
getOrderList()
|
||||
})
|
||||
// 获取轮播图列表
|
||||
const getOrderList = () => {
|
||||
state.loading = true
|
||||
axios.get('/orders', {
|
||||
params: {
|
||||
pageNumber: state.currentPage,
|
||||
pageSize: state.pageSize,
|
||||
orderNo: state.orderNo,
|
||||
orderStatus: state.orderStatus
|
||||
}
|
||||
}).then(res => {
|
||||
state.tableData = res.list
|
||||
state.total = res.totalCount
|
||||
state.currentPage = res.currPage
|
||||
state.loading = false
|
||||
})
|
||||
}
|
||||
const handleOption = () => {
|
||||
state.currentPage = 1
|
||||
getOrderList()
|
||||
}
|
||||
// 选择项
|
||||
const handleSelectionChange = (val) => {
|
||||
state.multipleSelection = val
|
||||
}
|
||||
const changePage = (val) => {
|
||||
state.currentPage = val
|
||||
getOrderList()
|
||||
}
|
||||
const handleConfig = (id) => {
|
||||
console.log('id', id)
|
||||
let params
|
||||
if (id) {
|
||||
params = [id]
|
||||
} else {
|
||||
if (!state.multipleSelection.length) {
|
||||
console.log('state.multipleSelection', state.multipleSelection.length)
|
||||
ElMessage.error('请选择项')
|
||||
return
|
||||
}
|
||||
params = state.multipleSelection.map(i => i.orderId)
|
||||
}
|
||||
axios.put('/orders/checkDone', {
|
||||
ids: params
|
||||
}).then(() => {
|
||||
ElMessage.success('配货成功')
|
||||
getOrderList()
|
||||
})
|
||||
}
|
||||
const handleSend = (id) => {
|
||||
let params
|
||||
if (id) {
|
||||
params = [id]
|
||||
} else {
|
||||
if (!state.multipleSelection.length) {
|
||||
ElMessage.error('请选择项')
|
||||
return
|
||||
}
|
||||
params = state.multipleSelection.map(i => i.orderId)
|
||||
}
|
||||
axios.put('/orders/checkOut', {
|
||||
ids: params
|
||||
}).then(() => {
|
||||
ElMessage.success('出库成功')
|
||||
getOrderList()
|
||||
})
|
||||
}
|
||||
const handleClose = (id) => {
|
||||
let params
|
||||
if (id) {
|
||||
params = [id]
|
||||
} else {
|
||||
if (!state.multipleSelection.length) {
|
||||
ElMessage.error('请选择项')
|
||||
return
|
||||
}
|
||||
params = state.multipleSelection.map(i => i.orderId)
|
||||
}
|
||||
axios.put('/orders/close', {
|
||||
ids: params
|
||||
}).then(() => {
|
||||
ElMessage.success('关闭成功')
|
||||
getOrderList()
|
||||
})
|
||||
}
|
||||
return {
|
||||
...toRefs(state),
|
||||
multipleTable,
|
||||
handleSelectionChange,
|
||||
addGood,
|
||||
getOrderList,
|
||||
changePage,
|
||||
handleOption,
|
||||
handleConfig,
|
||||
handleSend,
|
||||
handleClose
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.order-container {
|
||||
min-height: 100%;
|
||||
}
|
||||
.el-card.is-always-shadow {
|
||||
min-height: 100%!important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<el-card class="order-container">
|
||||
<div class="data">
|
||||
<el-card class="data-item" shadow="hover">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>订单状态</span>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
{{ data.orderStatusString }}
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card class="data-item" shadow="hover">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>创建时间</span>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
{{ data.createTime }}
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card class="data-item" shadow="hover">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>订单号</span>
|
||||
</div>
|
||||
</template>
|
||||
<div>
|
||||
{{ data.orderNo }}
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<el-table
|
||||
:data="tableData"
|
||||
tooltip-effect="dark"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column
|
||||
label="商品图片"
|
||||
>
|
||||
<template #default="scope">
|
||||
<img style="width: 100px" :key="scope.row.goodsId" :src="$filters.prefix(scope.row.goodsCoverImg)" alt="商品主图">
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="goodsId"
|
||||
label="商品编号"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="goodsName"
|
||||
label="商品名"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="goodsCount"
|
||||
label="商品数量"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="sellingPrice"
|
||||
label="价格"
|
||||
>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { onMounted, reactive, toRefs } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import axios from '@/utils/axios'
|
||||
export default {
|
||||
name: 'OrderDetail',
|
||||
setup() {
|
||||
const route = useRoute()
|
||||
const { id } = route.query
|
||||
const state = reactive({
|
||||
data: {},
|
||||
tableData: []
|
||||
})
|
||||
onMounted(() => {
|
||||
axios.get(`/orders/${id}`).then(res => {
|
||||
console.log(res)
|
||||
state.data = res
|
||||
state.tableData = res.newBeeMallOrderItemVOS
|
||||
})
|
||||
})
|
||||
|
||||
return {
|
||||
...toRefs(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.data {
|
||||
display: flex;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
.data .data-item {
|
||||
flex: 1;
|
||||
margin: 0 10px;
|
||||
}
|
||||
.el-table {
|
||||
border: 1px solid #EBEEF5;
|
||||
border-bottom: none;
|
||||
}
|
||||
.has-gutter th {
|
||||
border-right: 1px solid #EBEEF5;
|
||||
}
|
||||
|
||||
.has-gutter th:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
.el-table__row td {
|
||||
border-right: 1px solid #EBEEF5;
|
||||
}
|
||||
.el-table__row td:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,190 @@
|
||||
<template>
|
||||
<el-card class="swiper-container">
|
||||
<template #header>
|
||||
<div class="header">
|
||||
<el-button type="primary" size="small" icon="el-icon-plus" @click="handleAdd">增加</el-button>
|
||||
<el-popconfirm
|
||||
title="确定删除吗?"
|
||||
@confirm="handleDelete"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button type="danger" size="small" icon="el-icon-delete">批量删除</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</div>
|
||||
</template>
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
ref="multipleTable"
|
||||
:data="tableData"
|
||||
tooltip-effect="dark"
|
||||
style="width: 100%"
|
||||
@selection-change="handleSelectionChange">
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="轮播图"
|
||||
width="200">
|
||||
<template #default="scope">
|
||||
<img style="width: 150px;height: 150px" :src="scope.row.carouselUrl" alt="轮播图">
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="跳转链接"
|
||||
>
|
||||
<template #default="scope">
|
||||
<a target="_blank" :href="scope.row.redirectUrl">{{ scope.row.redirectUrl }}</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="carouselRank"
|
||||
label="排序值"
|
||||
width="120"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="createTime"
|
||||
label="添加时间"
|
||||
width="200"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="操作"
|
||||
width="100"
|
||||
>
|
||||
<template #default="scope">
|
||||
<a style="cursor: pointer; margin-right: 10px" @click="handleEdit(scope.row.carouselId)">修改</a>
|
||||
<el-popconfirm
|
||||
title="确定删除吗?"
|
||||
@confirm="handleDeleteOne(scope.row.carouselId)"
|
||||
>
|
||||
<template #reference>
|
||||
<a style="cursor: pointer">删除</a>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--总数超过一页,再展示分页器-->
|
||||
<el-pagination
|
||||
background
|
||||
layout="prev, pager, next"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:current-page="currentPage"
|
||||
@current-change="changePage"
|
||||
/>
|
||||
</el-card>
|
||||
<DialogAddSwiper ref='addGood' :reload="getCarousels" :type="type" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { onMounted, reactive, ref, toRefs } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import DialogAddSwiper from '@/components/DialogAddSwiper.vue'
|
||||
import axios from '@/utils/axios'
|
||||
export default {
|
||||
name: 'Swiper',
|
||||
components: {
|
||||
DialogAddSwiper
|
||||
},
|
||||
setup() {
|
||||
const multipleTable = ref(null)
|
||||
const addGood = ref(null)
|
||||
const state = reactive({
|
||||
loading: false,
|
||||
tableData: [], // 数据列表
|
||||
multipleSelection: [], // 选中项
|
||||
total: 0, // 总条数
|
||||
currentPage: 1, // 当前页
|
||||
pageSize: 10, // 分页大小
|
||||
type: 'add', // 操作类型
|
||||
})
|
||||
onMounted(() => {
|
||||
getCarousels()
|
||||
})
|
||||
// 获取轮播图列表
|
||||
const getCarousels = () => {
|
||||
state.loading = true
|
||||
axios.get('/carousels', {
|
||||
params: {
|
||||
pageNumber: state.currentPage,
|
||||
pageSize: state.pageSize
|
||||
}
|
||||
}).then(res => {
|
||||
state.tableData = res.list
|
||||
state.total = res.totalCount
|
||||
state.currentPage = res.currPage
|
||||
state.loading = false
|
||||
})
|
||||
}
|
||||
// 添加轮播项
|
||||
const handleAdd = () => {
|
||||
state.type = 'add'
|
||||
addGood.value.open()
|
||||
}
|
||||
// 修改轮播图
|
||||
const handleEdit = (id) => {
|
||||
state.type = 'edit'
|
||||
addGood.value.open(id)
|
||||
}
|
||||
// 选择项
|
||||
const handleSelectionChange = (val) => {
|
||||
state.multipleSelection = val
|
||||
}
|
||||
// 批量删除
|
||||
const handleDelete = () => {
|
||||
if (!state.multipleSelection.length) {
|
||||
ElMessage.error('请选择项')
|
||||
return
|
||||
}
|
||||
axios.delete('/carousels', {
|
||||
data: {
|
||||
ids: state.multipleSelection.map(i => i.carouselId)
|
||||
}
|
||||
}).then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
getCarousels()
|
||||
})
|
||||
}
|
||||
// 单个删除
|
||||
const handleDeleteOne = (id) => {
|
||||
axios.delete('/carousels', {
|
||||
data: {
|
||||
ids: [id]
|
||||
}
|
||||
}).then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
getCarousels()
|
||||
})
|
||||
}
|
||||
const changePage = (val) => {
|
||||
state.currentPage = val
|
||||
getCarousels()
|
||||
}
|
||||
return {
|
||||
...toRefs(state),
|
||||
multipleTable,
|
||||
handleSelectionChange,
|
||||
addGood,
|
||||
handleAdd,
|
||||
handleEdit,
|
||||
handleDelete,
|
||||
handleDeleteOne,
|
||||
getCarousels,
|
||||
changePage
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.swiper-container {
|
||||
min-height: 100%;
|
||||
}
|
||||
.el-card.is-always-shadow {
|
||||
min-height: 100%!important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user