Browse Source

update

element-plus-release
Nick930826 2 years ago
parent
commit
14ab5c0133
  1. 46
      package.json
  2. 227
      src/App.vue
  3. 216
      src/components/DialogAddCategory.vue
  4. 220
      src/components/DialogAddGood.vue
  5. 223
      src/components/DialogAddSwiper.vue
  6. 5
      src/components/Footer.vue
  7. 113
      src/components/Header.vue
  8. 66
      src/components/Table.vue
  9. 137
      src/main.js
  10. 7
      src/views/Account.vue
  11. 334
      src/views/AddGood.vue
  12. 86
      src/views/Category.vue
  13. 26
      src/views/Good.vue
  14. 210
      src/views/Guest.vue
  15. 2
      src/views/Index.vue
  16. 35
      src/views/IndexConfig.vue
  17. 17
      src/views/Login.vue
  18. 48
      src/views/Order.vue
  19. 46
      src/views/OrderDetail.vue
  20. 207
      src/views/Swiper.vue
  21. 35
      vite.config.js
  22. 4179
      yarn.lock

46
package.json

@ -1,5 +1,5 @@
{
"name": "vue3-admin",
"name": "admin00",
"version": "0.0.0",
"scripts": {
"dev": "vite --mode development",
@ -8,38 +8,22 @@
"serve": "vite preview"
},
"dependencies": {
"@element-plus/icons-vue": "^0.2.7",
"@sentry/browser": "^6.3.1",
"@sentry/tracing": "^6.3.1",
"axios": "^0.21.1",
"element-plus": "^2.0.2",
"@element-plus/icons-vue": "^2.0.9",
"axios": "0.21.1",
"element-plus": "^2.2.17",
"js-md5": "^0.7.3",
"node-sass": "^7.0.1",
"pushstate-server": "^3.1.0",
"qs": "^6.9.6",
"sass": "^1.49.8",
"sass-loader": "^12.6.0",
"style-loader": "^3.3.1",
"unplugin-element-plus": "^0.3.1",
"vue": "^3.0.5",
"vue-router": "^4.0.4",
"wangeditor": "^4.6.10"
"unplugin-vue-components": "^0.22.7",
"vue": "^3.2.39",
"vue-router": "^4.1.5",
"wangeditor": "^4.6.15"
},
"devDependencies": {
"@babel/core": "^7.13.8",
"@babel/runtime": "^7.13.8",
"@rollup/plugin-babel": "^5.3.0",
"@vitejs/plugin-vue": "^1.1.4",
"@vue/compiler-sfc": "^3.0.5",
"babel": "^6.23.0",
"babel-plugin-component": "^1.1.1",
"babel-plugin-import": "^1.13.3",
"element-theme-chalk": "^2.15.1",
"unplugin-auto-import": "^0.6.0",
"unplugin-vue-components": "^0.17.18",
"vite": "^2.0.1",
"vite-babel-plugin": "^0.0.2",
"vite-plugin-babel-import": "^2.0.2",
"vite-plugin-imp": "^2.0.4"
"@vitejs/plugin-vue": "2.3.3",
"@vue/compiler-sfc": "3.0.5",
"sass": "^1.54.9",
"unplugin-auto-import": "^0.11.2",
"unplugin-element-plus": "^0.4.1",
"vite": "2.1.3",
"vite-plugin-babel-import": "2.0.2"
}
}

227
src/App.vue

@ -4,37 +4,36 @@
<el-aside class="aside">
<div class="head">
<div>
<img src="https://s.weituibao.com/1582958061265/mlogo.png" alt="logo">
<img src="//s.weituibao.com/1582958061265/mlogo.png" alt="logo">
<span>vue3 admin</span>
</div>
</div>
<div class="line" />
<el-menu
:default-openeds="state.defaultOpen"
background-color="#222832"
text-color="#fff"
:router="true"
:default-active='state.currentPath'
:default-openeds="state.defaultOpen"
:default-active='state.currentPath'
>
<el-sub-menu index="1">
<template #title>
<span>Dashboard</span>
</template>
<el-menu-item-group>
<el-menu-item index="/introduce"><i-data-line width='20' /><span class="menu-cutom-title">系统介绍</span></el-menu-item>
<el-menu-item index="/dashboard"><i-odometer width='20' /><span class="menu-cutom-title">Dashboard</span></el-menu-item>
<el-menu-item index="/add"><i-plus width='20' /><span class="menu-cutom-title">添加商品</span></el-menu-item>
<el-menu-item index="/"><el-icon><Odometer /></el-icon></el-menu-item>
<el-menu-item index="/add"><el-icon><Plus /></el-icon></el-menu-item>
</el-menu-item-group>
</el-sub-menu>
<el-sub-menu index="2">
<el-sub-menu index="2">
<template #title>
<span>首页配置</span>
</template>
<el-menu-item-group>
<el-menu-item index="/swiper"><i-picture width='20' /><span class="menu-cutom-title">轮播图配置</span></el-menu-item>
<el-menu-item index="/hot"><i-star-filled width='20' /><span class="menu-cutom-title">热销商品配置</span></el-menu-item>
<el-menu-item index="/new"><i-sell width='20' /><span class="menu-cutom-title">新品上线配置</span></el-menu-item>
<el-menu-item index="/recommend"><i-pointer width='20' /><span class="menu-cutom-title">为你推荐配置</span></el-menu-item>
<el-menu-item index="/swiper"><el-icon><Picture /></el-icon></el-menu-item>
<el-menu-item index="/hot"><el-icon><StarFilled /></el-icon></el-menu-item>
<el-menu-item index="/new"><el-icon><Sell /></el-icon>线</el-menu-item>
<el-menu-item index="/recommend"><el-icon><ShoppingCart /></el-icon></el-menu-item>
</el-menu-item-group>
</el-sub-menu>
<el-sub-menu index="3">
@ -42,10 +41,10 @@
<span>模块管理</span>
</template>
<el-menu-item-group>
<el-menu-item index="/category"><i-menu width='20' /><span class="menu-cutom-title">分类管理</span></el-menu-item>
<el-menu-item index="/good"><i-goods-filled width='20' /><span class="menu-cutom-title">商品管理</span></el-menu-item>
<el-menu-item index="/guest"><i-user-filled width='20' /><span class="menu-cutom-title">会员管理</span></el-menu-item>
<el-menu-item index="/order"><i-tickets width='20' /><span class="menu-cutom-title">订单管理</span></el-menu-item>
<el-menu-item index="/category"><el-icon><Menu /></el-icon></el-menu-item>
<el-menu-item index="/good"><el-icon><Goods /></el-icon></el-menu-item>
<el-menu-item index="/guest"><el-icon><User /></el-icon></el-menu-item>
<el-menu-item index="/order"><el-icon><List /></el-icon></el-menu-item>
</el-menu-item-group>
</el-sub-menu>
<el-sub-menu index="4">
@ -53,7 +52,7 @@
<span>系统管理</span>
</template>
<el-menu-item-group>
<el-menu-item index="/account"><i-unlock width='20' /><span class="menu-cutom-title">修改密码</span></el-menu-item>
<el-menu-item index="/account"><el-icon><Lock /></el-icon></el-menu-item>
</el-menu-item-group>
</el-sub-menu>
</el-menu>
@ -72,127 +71,90 @@
</div>
</template>
<script>
import { onUnmounted, reactive } from 'vue'
<script setup>
import { reactive } from 'vue'
import { useRouter } from 'vue-router'
import Header from '@/components/Header.vue'
import Footer from '@/components/Footer.vue'
import { useRouter } from 'vue-router'
import { pathMap, localGet } from '@/utils'
export default {
name: 'App',
components: {
Header,
Footer
},
setup() {
console.log('App')
const noMenu = ['/login']
const router = useRouter()
const state = reactive({
defaultOpen: ['1', '2', '3', '4'],
showMenu: true,
currentPath: '/dashboard',
count: {
number: 1
}
})
// 退
if (window.history && window.history.pushState) {
history.pushState(null, null, document.URL);
window.addEventListener('popstate', () => {
if (!localGet('token')) {
state.showMenu = false
}
}, false);
}
const unwatch = 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]
})
import { localGet, pathMap } from '@/utils'
onUnmounted(() => {
unwatch()
})
const noMenu = ['/login']
const router = useRouter()
const state = reactive({
showMenu: true,
defaultOpen: ['1', '2', '3', '4'],
currentPath: '/',
})
return {
state
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]
})
</script>
<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;
justify-content: center;
height: 50px;
}
.head > div {
display: flex;
align-items: center;
}
.layout {
min-height: 100vh;
background-color: #ffffff;
}
.container {
height: 100vh;
}
.aside {
width: 200px!important;
background-color: #222832;
}
.head {
display: flex;
align-items: center;
justify-content: center;
height: 50px;
}
.head > div {
display: flex;
align-items: center;
}
.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;
}
.menu-cutom-title {
padding-left: 10px;
}
.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;
@ -202,17 +164,14 @@ export default {
.el-menu {
border-right: none!important;
}
.el-menu-item-group {
background-color: #222832;
}
.el-sub-menu {
.el-submenu {
border-top: 1px solid hsla(0, 0%, 100%, .05);
border-bottom: 1px solid rgba(0, 0, 0, .2);
}
.el-sub-menu:first-child {
.el-submenu:first-child {
border-top: none;
}
.el-sub-menu [class^="el-icon-"] {
.el-submenu [class^="el-icon-"] {
vertical-align: -1px!important;
}
a {
@ -220,10 +179,10 @@ export default {
text-decoration: none;
}
.el-pagination {
justify-content: center;
text-align: center;
margin-top: 20px;
}
.el-popper__arrow {
display: none;
}
</style>
</style>

216
src/components/DialogAddCategory.vue

@ -1,145 +1,123 @@
<template>
<el-dialog
:title="type == 'add' ? '添加分类' : '修改分类'"
v-model="visible"
:title="state.type == 'add' ? '添加分类' : '修改分类'"
v-model="state.visible"
width="400px"
@close="handleClose"
>
<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 :model="state.ruleForm" :rules="state.rules" ref="formRef" label-width="100px" class="good-form">
<el-form-item label="商品名称" prop="name">
<el-input type="text" v-model="state.ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="排序值" prop="rank">
<el-input type="number" max='200' v-model="ruleForm.rank"></el-input>
<el-input type="number" v-model="state.ruleForm.rank"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false"> </el-button>
<el-button @click="state.visible = false"> </el-button>
<el-button type="primary" @click="submitForm"> </el-button>
</span>
</template>
</el-dialog>
</template>
<script>
import { reactive, ref, toRefs } from 'vue'
<script setup>
import { reactive, ref } 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
const props = defineProps({
type: String, //
reload: Function //
})
const formRef = ref(null)
const route = useRoute()
const state = reactive({
visible: false,
categoryLevel: 1,
parentId: 0,
ruleForm: {
name: '',
rank: ''
},
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
})
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
}
//
const open = (id) => {
state.visible = true
if (id) {
state.id = id
getDetail(id)
state.parentId = res.parentId
state.categoryLevel = res.categoryLevel
})
}
//
const open = (id) => {
state.visible = true
if (id) {
state.id = id
// id
getDetail(id)
} else {
//
// level id
const { level = 1, parent_id = 0 } = 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 (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
// reload
if (props.reload) props.reload()
})
} else {
// id
const { level = 1, parent_id = 0 } = route.query
state.ruleForm = {
name: '',
rank: ''
}
state.parentId = parent_id
state.categoryLevel = level
//
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
// reload
if (props.reload) props.reload()
})
}
}
//
const close = () => {
state.visible = false
}
const handleClose = () => {
formRef.value.resetFields()
}
const submitForm = () => {
formRef.value.validate((valid) => {
if (valid) {
if (hasEmoji(state.ruleForm.name)) {
ElMessage.error('不要输入表情包,再输入就打死你个龟孙儿~')
return
}
if (state.ruleForm.name.length > 16) {
ElMessage.error('名称不能超过16个字符')
return
}
if (state.ruleForm.rank > 200) {
ElMessage.error('排序不能超过200')
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.parentId,
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,
handleClose
}
}
})
}
</script>

220
src/components/DialogAddGood.vue

@ -1,155 +1,131 @@
<template>
<el-dialog
:title="type == 'add' ? '添加商品' : '修改商品'"
v-model="visible"
v-model="state.visible"
width="400px"
@close="handleClose"
>
<el-form :model="ruleForm" :rules="rules" ref="formRef" label-width="100px" class="good-form">
<el-form :model="state.ruleForm" :rules="state.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-input type="text" v-model="state.ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="跳转链接" prop="link">
<el-input type="text" v-model="ruleForm.link"></el-input>
<el-input type="text" v-model="state.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-input type="number" min="0" v-model="state.ruleForm.id"></el-input>
</el-form-item>
<el-form-item label="排序值" prop="sort">
<el-input type="number" v-model="ruleForm.sort"></el-input>
<el-input type="number" v-model="state.ruleForm.sort"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false"> </el-button>
<el-button @click="state.visible = false"> </el-button>
<el-button type="primary" @click="submitForm"> </el-button>
</span>
</template>
</el-dialog>
</template>
<script>
import { reactive, ref, toRefs } from 'vue'
<script setup>
import { reactive, ref } 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
const props = defineProps({
type: String,
configType: Number,
reload: Function
})
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'] }
]
},
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
}
})
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 open = (id) => {
state.visible = true
if (id) {
state.id = id
getDetail(id)
}
}
//
const close = () => {
state.visible = false
}
const submitForm = () => {
formRef.value.validate((valid) => {
if (valid) {
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 {
state.ruleForm = {
name: '',
id: '',
link: '',
sort: ''
}
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()
})
}
}
//
const close = () => {
state.visible = false
}
const handleClose = () => {
formRef.value.resetFields()
}
const submitForm = () => {
formRef.value.validate((valid) => {
if (valid) {
if (hasEmoji(state.ruleForm.name) || hasEmoji(state.ruleForm.link)) {
ElMessage.error('不要输入表情包,再输入就打死你个龟孙儿~')
return
}
if (state.ruleForm.name.length > 128) {
ElMessage.error('商品名称不能超过128个字符')
return
}
if (state.ruleForm.sort < 0 || state.ruleForm.sort > 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,
handleClose
}
}
})
}
defineExpose({ open, close })
</script>
<style scoped>

223
src/components/DialogAddSwiper.vue

@ -1,163 +1,142 @@
<template>
<el-dialog
:title="type == 'add' ? '添加轮播图' : '修改轮播图'"
v-model="visible"
v-model="state.visible"
width="400px"
@close="handleClose"
>
<el-form :model="ruleForm" :rules="rules" ref="formRef" label-width="100px" class="good-form">
<el-form :model="state.ruleForm" :rules="state.rules" ref="formRef" label-width="100px" class="good-form">
<el-form-item label="图片" prop="url">
<el-upload
class="avatar-uploader"
:action="uploadImgServer"
:action="state.uploadImgServer"
accept="jpg,jpeg,png"
:headers="{
token: token
token: state.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>
<img style="width: 200px; height: 100px; border: 1px solid #e9e9e9;" v-if="state.ruleForm.url" :src="state.ruleForm.url" class="avatar">
<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
</el-upload>
</el-form-item>
<el-form-item label="跳转链接" prop="link">
<el-input type="text" v-model="ruleForm.link"></el-input>
<el-input type="text" v-model="state.ruleForm.link"></el-input>
</el-form-item>
<el-form-item label="排序值" prop="sort">
<el-input type="number" v-model="ruleForm.sort"></el-input>
<el-input type="number" v-model="state.ruleForm.sort"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false"> </el-button>
<el-button @click="state.visible = false"> </el-button>
<el-button type="primary" @click="submitForm"> </el-button>
</span>
</template>
</el-dialog>
</template>
<script>
import { reactive, ref, toRefs } from 'vue'
<script setup>
import { reactive, ref } from 'vue'
import axios from '@/utils/axios'
import { localGet, uploadImgServer, hasEmoji } from '@/utils'
import { localGet, uploadImgServer } from '@/utils'
import { ElMessage } from 'element-plus'
export default {
name: 'DialogAddSwiper',
props: {
type: String,
reload: Function
const props = defineProps({
type: String,
reload: Function
})
const formRef = ref(null)
const state = reactive({
uploadImgServer,
token: localGet('token') || '',
visible: false,
ruleForm: {
url: '',
link: '',
sort: ''
},
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
}
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 handleUrlSuccess = (val) => {
state.ruleForm.url = val.data || ''
})
}
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 open = (id) => {
state.visible = true
if (id) {
state.id = id
getDetail(id)
}
}
//
const close = () => {
state.visible = false
}
const submitForm = () => {
console.log(formRef.value.validate)
formRef.value.validate((valid) => {
if (valid) {
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 {
state.ruleForm = {
url: '',
link: '',
sort: ''
}
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()
})
}
}
//
const close = () => {
state.visible = false
}
const handleClose = () => {
formRef.value.resetFields()
}
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,
handleClose
}
}
})
}
defineExpose({ open, close })
</script>
<style scoped>
@ -167,6 +146,10 @@ export default {
color: #ddd;
font-size: 30px;
}
.avatar-uploader >>> .el-upload {
width: 100%;
text-align: center;
}
.avatar-uploader-icon {
display: block;
width: 100%;

5
src/components/Footer.vue

@ -7,10 +7,7 @@
</div>
</template>
<script>
export default {
name: 'Footer'
}
<script setup>
</script>
<style scoped>

113
src/components/Header.vue

@ -1,8 +1,8 @@
<template>
<div class="header">
<div class="left">
<i-back v-if="hasBack" width="14" height="14" class="el-icon-back" @click="back" />
<span style="font-size: 20px">{{ name }}</span>
<el-icon class="back" v-if="state.hasBack" @click="back"><Back /></el-icon>
<span style="font-size: 20px">{{ state.name }}</span>
</div>
<div class="right">
<el-popover
@ -14,13 +14,13 @@
<template #reference>
<div class="author">
<i class="icon el-icon-s-custom" />
{{ userInfo && userInfo.nickName || '' }}
{{ state.userInfo && state.userInfo.nickName || '' }}
<i class="el-icon-caret-bottom" />
</div>
</template>
<div class="nickname">
<p>登录名{{ userInfo && userInfo.loginUserName || '' }}</p>
<p>昵称{{ userInfo && userInfo.nickName || '' }}</p>
<p>登录名{{ state.userInfo && state.userInfo.loginUserName || '' }}</p>
<p>昵称{{ state.userInfo && state.userInfo.nickName || '' }}</p>
<el-tag size="small" effect="dark" class="logout" @click="logout">退出</el-tag>
</div>
</el-popover>
@ -28,75 +28,69 @@
</div>
</template>
<script>
import { onMounted, reactive, toRefs } from 'vue'
<script setup>
import { onMounted, reactive } 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')
window.location.reload()
})
}
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
}
const router = useRouter()
const state = reactive({
name: 'dashboard',
userInfo: null, //
hasBack: false, // icon
})
//
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(() => {
// 退 token
localRemove('token')
//
router.push({ path: '/login' })
})
}
router.afterEach((to) => {
const { id } = to.query
state.name = pathMap[to.name]
// level2 level3 icon
console.log('to.name', to.name)
state.hasBack = ['level2', 'level3'].includes(to.name)
})
//
const back = () => {
router.back()
}
</script>
<style scoped>
.header {
height: 52px;
height: 50px;
border-bottom: 1px solid #e9e9e9;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
}
.left {
display: flex;
align-items: center;
}
.el-icon-back {
.header .left .back {
border: 1px solid #e9e9e9;
padding: 4px;
border-radius: 50px;
margin-right: 10px;
padding: 5px;
border-radius: 50%;
margin-right: 5px;
cursor: pointer;
}
.right > div > .icon{
font-size: 18px;
@ -107,13 +101,14 @@ export default {
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 {
.popper-user-box .nickname {
position: relative;
color: #ffffff;
}

66
src/components/Table.vue

@ -0,0 +1,66 @@
<template>
<el-table
:load="state.loading"
:data="state.tableData"
tooltip-effect="dark"
style="width: 100%"
@selection-change="handleSelectionChange"
>
<slot name='column'></slot>
</el-table>
<el-pagination
background
layout="prev, pager, next"
:total="state.total"
:page-size="state.pageSize"
:current-page="state.currentPage"
@current-change="changePage"
/>
</template>
<script setup>
import { onMounted, reactive, getCurrentInstance } from 'vue'
import axios from '@/utils/axios'
const props = defineProps({
action: String
})
const app = getCurrentInstance()
const { goTop } = app.appContext.config.globalProperties
const state = reactive({
loading: false,
tableData: [], //
total: 0, //
currentPage: 1, //
pageSize: 10, //
multipleSelection: []
})
onMounted(() => {
getList()
})
const getList = () => {
state.loading = true
axios.get(props.action, {
params: {
pageNumber: state.currentPage,
pageSize: state.pageSize
}
}).then(res => {
state.tableData = res.list
state.total = res.totalCount
state.currentPage = res.currPage
state.loading = false
goTop && goTop() //
})
}
const handleSelectionChange = (val) => {
state.multipleSelection = val
}
const changePage = (val) => {
state.currentPage = val
getList()
}
</script>

137
src/main.js

@ -1,10 +1,34 @@
import { createApp } from 'vue'
import { ElButton, ElContainer, ElAside, ElHeader, ElMain, ElFooter, ElMenu, ElSubMenu, ElMenuItemGroup, ElMenuItem, ElForm, ElFormItem, ElInput, ElPopover, ElTag, ElCard, ElTable, ElTableColumn, ElPagination, ElDialog, ElPopconfirm, ElUpload, ElLoading, ElSelect, ElOption, ElRadioGroup, ElRadio, ElCascader, ElCheckbox, ElInputNumber } from 'element-plus'
import * as Sentry from "@sentry/browser"
import * as ElIconModules from '@element-plus/icons-vue'
import { Integrations } from "@sentry/tracing"
import {
ElButton,
ElContainer,
ElAside,
ElMenu,
ElSubMenu,
ElMenuItemGroup,
ElMenuItem,
ElForm,
ElFormItem,
ElInput,
ElCheckbox,
ElPopover,
ElTag,
ElCard,
ElTable,
ElTableColumn,
ElPopconfirm,
ElUpload,
ElDialog,
ElPagination,
ElCascader,
ElRadioGroup,
ElRadio,
ElSelect,
ElOption
} from 'element-plus'
import App from './App.vue'
import router from './router/index'
import router from '@/router'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
const orderStatus = {
0: '待支付',
@ -17,8 +41,13 @@ const orderStatus = {
'-3': '商家关闭'
}
const app = createApp(App)
// 全局过滤器
const app = createApp(App) // 生成 Vue 实例 app
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
// 全局方法
app.config.globalProperties.$filters = {
orderMap(status) {
return orderStatus[status] || '未知状态'
@ -30,73 +59,39 @@ app.config.globalProperties.$filters = {
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
}
}
}
}
// console.log('ElIconModules', ElIconModules)
function transElIconName (iconName) {
return 'i' + iconName.replace(/[A-Z]/g,(match)=> '-' + match.toLowerCase())
app.config.globalProperties.goTop = function () {
const main = document.querySelector('.main')
main.scrollTop = 0
}
for(let iconName in ElIconModules){
app.component(transElIconName(iconName), ElIconModules[iconName])
}
app.use(router)
app.use(router) // 引用路由实例
app.use(ElButton)
.use(ElContainer)
.use(ElAside)
.use(ElHeader)
.use(ElMain)
.use(ElFooter)
.use(ElMenu)
.use(ElSubMenu)
.use(ElMenuItemGroup)
.use(ElMenuItem)
.use(ElForm)
.use(ElFormItem)
.use(ElInput)
.use(ElPopover)
.use(ElTag)
.use(ElCard)
.use(ElTable)
.use(ElTableColumn)
.use(ElPagination)
.use(ElDialog)
.use(ElPopconfirm)
.use(ElUpload)
.use(ElLoading)
.use(ElSelect)
.use(ElOption)
.use(ElRadioGroup)
.use(ElRadio)
.use(ElCascader)
.use(ElCheckbox)
.use(ElInputNumber)
Sentry.init({
dsn: "https://f866b695d21d467ba523f1adf14e0a24@o584908.ingest.sentry.io/5737358",
integrations: [new Integrations.BrowserTracing()],
// Set tracesSampleRate to 1.0 to capture 100%
// of transactions for performance monitoring.
// We recommend adjusting this value in production
tracesSampleRate: 1.0,
});
app.mount('#app')
.use(ElContainer)
.use(ElAside)
.use(ElMenu)
.use(ElSubMenu)
.use(ElMenuItemGroup)
.use(ElMenuItem)
.use(ElForm)
.use(ElFormItem)
.use(ElCheckbox)
.use(ElInput)
.use(ElPopover)
.use(ElTag)
.use(ElCard)
.use(ElTable)
.use(ElTableColumn)
.use(ElPopconfirm)
.use(ElUpload)
.use(ElDialog)
.use(ElPagination)
.use(ElCascader)
.use(ElRadioGroup)
.use(ElRadio)
.use(ElSelect)
.use(ElOption)
app.mount('#app') // 挂载到 #app

7
src/views/Account.vue

@ -1,6 +1,6 @@
<template>
<el-card class="account-container">
<el-form :model="nameForm" :rules="state.rules" ref="nameRef" label-width="80px" label-position="right" class="demo-ruleForm">
<el-form :model="state.nameForm" :rules="state.rules" ref="nameRef" label-width="80px" label-position="right" class="demo-ruleForm">
<el-form-item label="登录名:" prop="loginName">
<el-input style="width: 200px" v-model="state.nameForm.loginName"></el-input>
</el-form-item>
@ -13,7 +13,7 @@
</el-form>
</el-card>
<el-card class="account-container">
<el-form :model="passForm" :rules="state.rules" ref="passRef" label-width="80px" label-position="right" class="demo-ruleForm">
<el-form :model="state.passForm" :rules="state.rules" ref="passRef" label-width="80px" label-position="right" class="demo-ruleForm">
<el-form-item label="原密码:" prop="oldpass">
<el-input style="width: 200px" v-model="state.passForm.oldpass"></el-input>
</el-form-item>
@ -28,10 +28,11 @@
</template>
<script setup>
import { onMounted, reactive, ref, toRefs } from 'vue'
import { onMounted, reactive, ref } from 'vue'
import axios from '@/utils/axios'
import { ElMessage } from 'element-plus'
import md5 from 'js-md5'
const nameRef = ref(null)
const passRef = ref(null)
const state = reactive({

334
src/views/AddGood.vue

@ -1,7 +1,7 @@
<template>
<div class="add">
<el-card class="add-container">
<el-form :model="state.goodForm" :rules="rules" ref="goodRef" label-width="100px" class="goodForm">
<el-form :model="state.goodForm" :rules="state.rules" ref="goodRef" label-width="100px" class="goodForm">
<el-form-item required label="商品分类">
<el-cascader :placeholder="state.defaultCate" style="width: 300px" :props="state.category" @change="handleChangeCate"></el-cascader>
</el-form-item>
@ -42,14 +42,14 @@
:on-success="handleUrlSuccess"
>
<img style="width: 100px; height: 100px; border: 1px solid #e9e9e9;" v-if="state.goodForm.goodsCoverImg" :src="state.goodForm.goodsCoverImg" class="avatar">
<i-plus v-else width='40' height='40' />
<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
</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-button type="primary" @click="submitAdd()">{{ state.id ? '立即修改' : '立即创建' }}</el-button>
</el-form-item>
</el-form>
</el-card>
@ -57,193 +57,172 @@
</template>
<script setup>
import { reactive, ref, toRefs, onMounted, onBeforeUnmount, getCurrentInstance } from 'vue'
import { reactive, ref, 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'
import { localGet, uploadImgServer, uploadImgsServer } from '@/utils'
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: {
goodsCoverImg: [
{ required: 'true', message: '请上传主图', trigger: ['change'] }
],
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,
categoryId: goods.goodsCategoryId
}
state.categoryId = goods.goodsCategoryId
state.defaultCate = `${firstCategory.categoryName}/${secondCategory.categoryName}/${thirdCategory.categoryName}`
if (instance) {
// html
instance.txt.html(goods.goodsDetailContent)
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')
},
})
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
}
if (params.goodsName.length > 128) {
ElMessage.error('商品名称不能超过128个字符')
return
}
if (params.goodsIntro.length > 200) {
ElMessage.error('商品简介不能超过200个字符')
return
}
if (params.tag.length > 16) {
ElMessage.error('商品标签不能超过16个字符')
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' })
})
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)
}
})
}
const handleBeforeUpload = (file) => {
console.log('file', file)
const sufix = file.name.split('.')[1] || ''
if (!['jpg', 'jpeg', 'png'].includes(sufix)) {
ElMessage.error('请上传 jpg、jpeg、png 格式的图片')
return false
})
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
}
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
}
}
const handleUrlSuccess = (val) => {
state.goodForm.goodsCoverImg = val.data || ''
}
const handleChangeCate = (val) => {
state.categoryId = val[2] || 0
}
</script>
<style scoped>
@ -259,9 +238,6 @@ const { proxy } = getCurrentInstance()
height: 100px;
color: #ddd;
font-size: 30px;
border: 1px solid #e9e9e9;
text-align: center;
line-height: 116px;
}
.avatar-uploader-icon {
display: block;

86
src/views/Category.vue

@ -2,21 +2,21 @@
<el-card class="category-container">
<template #header>
<div class="header">
<el-button type="primary" @click="handleAdd"><i-plus width='14' /> 增加</el-button>
<el-button type="primary" :icon="Plus" @click="handleAdd">增加</el-button>
<el-popconfirm
title="确定删除吗?"
confirmButtonText='确定'
cancelButtonText='取消'
@confirm="handleDelete"
confirm-button-text="确定"
cancel-button-text="取消"
>
<template #reference>
<el-button type="danger"><i-delete width='14' /> 批量删除</el-button>
<el-button type="danger" :icon="Delete">批量删除</el-button>
</template>
</el-popconfirm>
</div>
</template>
<el-table
v-loading="state.loading"
:load="state.loading"
ref="multipleTable"
:data="state.tableData"
tooltip-effect="dark"
@ -53,9 +53,9 @@
<a style="cursor: pointer; margin-right: 10px" @click="handleNext(scope.row)">下级分类</a>
<el-popconfirm
title="确定删除吗?"
confirmButtonText='确定'
cancelButtonText='取消'
@confirm="handleDeleteOne(scope.row.categoryId)"
confirm-button-text="确定"
cancel-button-text="取消"
>
<template #reference>
<a style="cursor: pointer">删除</a>
@ -73,20 +73,21 @@
:current-page="state.currentPage"
@current-change="changePage"
/>
<DialogAddCategory ref='addCate' :reload="getCategory" :type="state.type" />
</el-card>
<DialogAddCategory ref='addGood' :reload="getCategory" :type="state.type" :level="state.level" :parent_id="state.parent_id" />
</template>
<script setup>
import { onMounted, onUnmounted, reactive, ref, toRefs } from 'vue'
import { onMounted, onUnmounted, reactive, ref, toRefs, watchEffect } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import DialogAddCategory from '@/components/DialogAddCategory.vue'
import { Plus, Delete } from '@element-plus/icons-vue'
import axios from '@/utils/axios'
const multipleTable = ref(null)
const addGood = ref(null)
const router = useRouter()
const route = useRoute()
import DialogAddCategory from '@/components/DialogAddCategory.vue'
const addCate = ref(null)
const router = useRouter() //
const route = useRoute() //
const state = reactive({
loading: false,
tableData: [], //
@ -101,14 +102,18 @@ const state = reactive({
onMounted(() => {
getCategory()
})
onUnmounted(() => {
unwatch()
watchEffect(() => {
console.log(state.pageSize)
})
const unwatch = router.afterEach((to) => {
//
if (['category', 'level2', 'level3'].includes(to.name)) {
getCategory()
}
})
onUnmounted(() => {
unwatch()
})
//
const getCategory = () => {
const { level = 1, parent_id = 0 } = route.query
@ -129,15 +134,33 @@ const getCategory = () => {
state.parentId = parent_id
})
}
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
}
})
}
//
const handleAdd = () => {
state.type = 'add'
addGood.value.open()
addCate.value.open()
}
//
const handleEdit = (id) => {
state.type = 'edit'
addGood.value.open(id)
addCate.value.open(id)
}
//
const handleSelectionChange = (val) => {
@ -169,31 +192,8 @@ const handleDeleteOne = (id) => {
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
}
})
}
</script>
<style scoped>
.category-container {
min-height: 100%;
}
.el-card.is-always-shadow {
min-height: 100%!important;
}
<style>
</style>

26
src/views/Good.vue

@ -2,20 +2,15 @@
<el-card class="good-container">
<template #header>
<div class="header">
<el-button type="primary" @click="handleAdd"><i-plus width='14' /> 新增商品</el-button>
<el-button type="primary" :icon="Plus" @click="handleAdd">新增商品</el-button>
</div>
</template>
<el-table
v-loading="state.loading"
ref="multipleTable"
:load="state.loading"
:data="state.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="商品编号"
@ -82,16 +77,18 @@
</template>
<script setup>
import { onMounted, reactive, ref, toRefs } from 'vue'
import { onMounted, reactive, getCurrentInstance } from 'vue'
import axios from '@/utils/axios'
import { ElMessage } from 'element-plus'
import { Plus, Delete } from '@element-plus/icons-vue'
import { useRouter } from 'vue-router'
const multipleTable = ref(null)
const app = getCurrentInstance()
const { goTop } = app.appContext.config.globalProperties
const router = useRouter()
const state = reactive({
loading: false,
tableData: [], //
multipleSelection: [], //
total: 0, //
currentPage: 1, //
pageSize: 10 //
@ -112,6 +109,7 @@ const getGoodList = () => {
state.total = res.totalCount
state.currentPage = res.currPage
state.loading = false
goTop && goTop()
})
}
const handleAdd = () => {
@ -120,10 +118,6 @@ const handleAdd = () => {
const handleEdit = (id) => {
router.push({ path: '/add', query: { id } })
}
//
const handleSelectionChange = (val) => {
state.multipleSelection = val
}
const changePage = (val) => {
state.currentPage = val
getGoodList()
@ -145,4 +139,4 @@ const handleStatus = (id, status) => {
.el-card.is-always-shadow {
min-height: 100%!important;
}
</style>
</style>

210
src/views/Guest.vue

@ -2,153 +2,91 @@
<el-card class="guest-container">
<template #header>
<div class="header">
<el-button type="primary" @click="handleSolve">解除禁用</el-button>
<el-button type="danger" @click="handleForbid">禁用账户</el-button>
<el-button type="primary" :icon="Plus" @click="handleSolve">解除禁用</el-button>
<el-button type="danger" :icon="Delete" @click="handleForbid">禁用账户</el-button>
</div>
</template>
<el-table
v-loading="state.loading"
ref="multipleTable"
:data="state.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="state.total"
:page-size="state.pageSize"
:current-page="state.currentPage"
@current-change="changePage"
/>
<Table
action='/users'
ref="table"
>
<template #column>
<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>
</template>
</Table>
</el-card>
</template>
<script setup>
import { onMounted, reactive, ref, toRefs } from 'vue'
import axios from '@/utils/axios'
import { ref } from 'vue'
import Table from '@/components/Table.vue'
import { ElMessage } from 'element-plus'
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()
}
import { Plus, Delete } from '@element-plus/icons-vue'
import axios from '@/utils/axios'
const table = ref(null)
const handleSolve = () => {
if (!state.multipleSelection.length) {
ElMessage.error('请选择项')
return
}
axios.put(`/users/0`, {
ids: state.multipleSelection.map(item => item.userId)
}).then(() => {
ElMessage.success('解除成功')
getGuestList()
})
if (!table.value.multipleSelection.length) {
ElMessage.error('请选择项')
return
}
axios.put(`/users/0`, {
ids: table.value.multipleSelection.map(item => item.userId)
}).then(() => {
ElMessage.success('解除成功')
table.value.getList()
})
}
const handleForbid = () => {
if (!state.multipleSelection.length) {
ElMessage.error('请选择项')
return
}
axios.put(`/users/1`, {
ids: state.multipleSelection.map(item => item.userId)
}).then(() => {
ElMessage.success('禁用成功')
getGuestList()
})
if (!table.value.multipleSelection.length) {
ElMessage.error('请选择项')
return
}
axios.put(`/users/1`, {
ids: table.value.multipleSelection.map(item => item.userId)
}).then(() => {
ElMessage.success('禁用成功')
table.value.getList()
})
}
</script>
<style scoped>
.guest-container {
min-height: 100%;
}
.el-card.is-always-shadow {
min-height: 100%!important;
}
<style>
</style>

2
src/views/Index.vue

@ -32,7 +32,9 @@
<script setup>
import { onMounted, onUnmounted } from 'vue'
let myChart = null
onMounted(() => {
if (window.echarts) {
// domecharts

35
src/views/IndexConfig.vue

@ -2,21 +2,21 @@
<el-card class="index-container">
<template #header>
<div class="header">
<el-button type="primary" @click="handleAdd"><i-plus width='14' /> 增加</el-button>
<el-button type="primary" :icon="Plus" @click="handleAdd">增加</el-button>
<el-popconfirm
title="确定删除吗?"
confirmButtonText='确定'
cancelButtonText='取消'
@confirm="handleDelete"
confirm-button-text="确定"
cancel-button-text="取消"
>
<template #reference>
<el-button type="danger"><i-delete width='14' /> 批量删除</el-button>
<el-button type="danger" :icon="Delete">批量删除</el-button>
</template>
</el-popconfirm>
</div>
</template>
<el-table
v-loading="state.loading"
:load="state.loading"
ref="multipleTable"
:data="state.tableData"
tooltip-effect="dark"
@ -64,9 +64,9 @@
<a style="cursor: pointer; margin-right: 10px" @click="handleEdit(scope.row.configId)">修改</a>
<el-popconfirm
title="确定删除吗?"
@confirm="handleDeleteOne(scope.row.configId)"
confirmButtonText='确定'
cancelButtonText='取消'
@confirm="handleDeleteOne(scope.row.configId)"
>
<template #reference>
<a style="cursor: pointer">删除</a>
@ -89,8 +89,9 @@
</template>
<script setup>
import { onMounted, onUnmounted, reactive, ref, toRefs } from 'vue'
import { onMounted, reactive, ref, toRefs } from 'vue'
import { ElMessage } from 'element-plus'
import { Plus, Delete } from '@element-plus/icons-vue'
import DialogAddGood from '@/components/DialogAddGood.vue'
import { useRoute, useRouter } from 'vue-router'
import axios from '@/utils/axios'
@ -100,6 +101,7 @@ const configTypeMap = {
new: 4,
recommend: 5
}
const router = useRouter()
const route = useRoute()
const multipleTable = ref(null)
@ -115,7 +117,7 @@ const state = reactive({
configType: 3 // 3-() 4-()线 5-()
})
//
const unwatch = router.beforeEach((to) => {
router.beforeEach((to) => {
if (['hot', 'new', 'recommend'].includes(to.name)) {
state.configType = configTypeMap[to.name]
state.currentPage = 1
@ -127,9 +129,6 @@ onMounted(() => {
state.configType = configTypeMap[route.name]
getIndexConfig()
})
onUnmounted(() => {
unwatch()
})
//
const getIndexConfig = () => {
state.loading = true
@ -166,10 +165,8 @@ const handleDelete = () => {
ElMessage.error('请选择项')
return
}
axios.delete('/indexConfigs', {
data: {
ids: state.multipleSelection.map(i => i.configId)
}
axios.post('/indexConfigs/delete', {
ids: state.multipleSelection.map(i => i.configId)
}).then(() => {
ElMessage.success('删除成功')
getIndexConfig()
@ -177,10 +174,8 @@ const handleDelete = () => {
}
//
const handleDeleteOne = (id) => {
axios.delete('/indexConfigs', {
data: {
ids: [id]
}
axios.post('/indexConfigs/delete', {
ids: [id]
}).then(() => {
ElMessage.success('删除成功')
getIndexConfig()
@ -199,4 +194,4 @@ const changePage = (val) => {
.el-card.is-always-shadow {
min-height: 100%!important;
}
</style>
</style>

17
src/views/Login.vue

@ -2,7 +2,7 @@
<div class="login-body">
<div class="login-container">
<div class="head">
<img class="logo" src="https://s.weituibao.com/1582958061265/mlogo.png" />
<img class="logo" src="https://s.yezgea02.com/1582958061265/mlogo.png" />
<div class="name">
<div class="title">新蜂商城</div>
<div class="tips">Vue3.0 后台管理系统</div>
@ -18,17 +18,17 @@
<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="state.checked" @change="!checked">下次自动登录</el-checkbox>
<el-checkbox v-model="state.checked" @change="!state.checked">下次自动登录</el-checkbox>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
<script setup>
import axios from '@/utils/axios'
import md5 from 'js-md5'
import { reactive, ref, toRefs } from 'vue'
import { reactive, ref } from 'vue'
import { localSet } from '@/utils'
const loginForm = ref(null)
const state = reactive({
@ -74,7 +74,6 @@ const resetForm = () => {
align-items: center;
width: 100%;
background-color: #fff;
/* background-image: linear-gradient(25deg, #077f7c, #3aa693, #5ecfaa, #7ffac2); */
}
.login-container {
width: 420px;
@ -107,12 +106,10 @@ const resetForm = () => {
width: 70%;
margin: 0 auto;
}
</style>
<style>
.el-form--label-top .el-form-item__label {
.login-form >>> .el-form--label-top .el-form-item__label {
padding: 0;
}
.login-form .el-form-item {
margin-bottom: 12px;
.login-form >>> .el-form-item {
margin-bottom: 0;
}
</style>

48
src/views/Order.vue

@ -5,26 +5,26 @@
<el-input
style="width: 200px; margin-right: 10px"
placeholder="请输入订单号"
v-model="orderNo"
v-model="state.orderNo"
@change="handleOption"
clearable
/>
<el-select @change="handleOption" v-model="orderStatus" style="width: 200px; margin-right: 10px">
<el-select @change="handleOption" v-model="state.orderStatus" style="width: 200px; margin-right: 10px">
<el-option
v-for="item in options"
v-for="item in state.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" @click="handleConfig()"><i-document-checked width="16" />配货完成</el-button>
<el-button type="primary" @click="handleSend()"><i-van width="16" />出库</el-button>
<el-button type="danger" @click="handleClose()"><i-document-delete width="16" /> 关闭订单</el-button>
<el-button type="primary" :icon="HomeFilled" @click="handleConfig()">配货完成</el-button>
<el-button type="primary" :icon="HomeFilled" @click="handleSend()">出库</el-button>
<el-button type="danger" :icon="Delete" @click="handleClose()">关闭订单</el-button>
</div>
</template>
<el-table
v-loading="state.loading"
:load="state.loading"
:data="state.tableData"
tooltip-effect="dark"
style="width: 100%"
@ -58,7 +58,7 @@
<template #default='scope'>
<span v-if="scope.row.payType == 1">微信支付</span>
<span v-else-if="scope.row.payType == 2">支付宝支付</span>
<span v-else>支付</span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column
@ -96,6 +96,8 @@
v-if="!(scope.row.orderStatus == 4 || scope.row.orderStatus < 0)"
title="确定关闭订单吗?"
@confirm="handleClose(scope.row.orderId)"
confirm-button-text="确定"
cancel-button-text="取消"
>
<template #reference>
<a style="cursor: pointer; margin-right: 10px">关闭订单</a>
@ -105,7 +107,6 @@
</template>
</el-table-column>
</el-table>
<!--总数超过一页再展示分页器-->
<el-pagination
background
layout="prev, pager, next"
@ -118,9 +119,11 @@
</template>
<script setup>
import { onMounted, reactive, ref, toRefs } from 'vue'
import { onMounted, reactive } from 'vue'
import { ElMessage } from 'element-plus'
import { HomeFilled, Delete } from '@element-plus/icons-vue'
import axios from '@/utils/axios'
const state = reactive({
loading: false,
tableData: [], //
@ -130,6 +133,7 @@ const state = reactive({
pageSize: 10, //
orderNo: '', //
orderStatus: '', //
//
options: [{
value: '',
label: '全部'
@ -159,10 +163,11 @@ const state = reactive({
label: '商家关闭'
}]
})
//
onMounted(() => {
getOrderList()
})
//
//
const getOrderList = () => {
state.loading = true
axios.get('/orders', {
@ -179,21 +184,24 @@ const getOrderList = () => {
state.loading = false
})
}
//
const handleOption = () => {
state.currentPage = 1
getOrderList()
}
//
// checkbox
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 {
@ -202,6 +210,7 @@ const handleConfig = (id) => {
ElMessage.error('请选择项')
return
}
//
params = state.multipleSelection.map(i => i.orderId)
}
axios.put('/orders/checkDone', {
@ -211,6 +220,7 @@ const handleConfig = (id) => {
getOrderList()
})
}
//
const handleSend = (id) => {
let params
if (id) {
@ -229,6 +239,7 @@ const handleSend = (id) => {
getOrderList()
})
}
//
const handleClose = (id) => {
let params
if (id) {
@ -247,13 +258,4 @@ const handleClose = (id) => {
getOrderList()
})
}
</script>
<style scoped>
.order-container {
min-height: 100%;
}
.el-card.is-always-shadow {
min-height: 100%!important;
}
</style>
</script>

46
src/views/OrderDetail.vue

@ -8,7 +8,7 @@
</div>
</template>
<div>
{{ data.orderStatusString }}
{{ state.data.orderStatusString }}
</div>
</el-card>
<el-card class="data-item" shadow="hover">
@ -18,7 +18,7 @@
</div>
</template>
<div>
{{ data.createTime }}
{{ state.data.createTime }}
</div>
</el-card>
<el-card class="data-item" shadow="hover">
@ -28,12 +28,12 @@
</div>
</template>
<div>
{{ data.orderNo }}
{{ state.data.orderNo }}
</div>
</el-card>
</div>
<el-table
:data="tableData"
:data="state.tableData"
tooltip-effect="dark"
style="width: 100%"
>
@ -67,32 +67,24 @@
</el-card>
</template>
<script>
import { onMounted, reactive, toRefs } from 'vue'
<script setup>
import { onMounted, reactive } 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)
}
}
}
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
})
})
</script>
<style scoped>

207
src/views/Swiper.vue

@ -2,26 +2,27 @@
<el-card class="swiper-container">
<template #header>
<div class="header">
<el-button type="primary" @click="handleAdd"><i-plus width='14' /> 增加</el-button>
<el-button type="primary" :icon="Plus" @click="handleAdd">增加</el-button>
<el-popconfirm
title="确定删除吗?"
confirmButtonText='确定'
cancelButtonText='取消'
@confirm="handleDelete"
confirm-button-text="确定"
cancel-button-text="取消"
>
<template #reference>
<el-button type="danger"><i-delete width='14' /> 批量删除</el-button>
<el-button type="danger" :icon="Delete">批量删除</el-button>
</template>
</el-popconfirm>
</div>
</template>
<el-table
v-loading="loading"
:load="state.loading"
ref="multipleTable"
:data="tableData"
:data="state.tableData"
tooltip-effect="dark"
style="width: 100%"
@selection-change="handleSelectionChange">
@selection-change="handleSelectionChange"
>
<el-table-column
type="selection"
width="55">
@ -52,143 +53,91 @@
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)"
confirm-button-text="确定"
cancel-button-text="取消"
>
<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"
:total="state.total"
:page-size="state.pageSize"
:current-page="state.currentPage"
@current-change="changePage"
/>
</el-card>
<DialogAddSwiper ref='addGood' :reload="getCarousels" :type="type" />
<DialogAddSwiper ref='addSwiper' :reload="getCarousels" :type="state.type" />
</template>
<script>
<script setup>
import { onMounted, reactive, ref, toRefs } from 'vue'
import { ElMessage } from 'element-plus'
import DialogAddSwiper from '@/components/DialogAddSwiper.vue'
import { Plus, Delete } from '@element-plus/icons-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
import DialogAddSwiper from '@/components/DialogAddSwiper.vue'
const addSwiper = ref()
const state = reactive({
loading: false,
tableData: [], //
currentPage: 1,
pageSize: 10,
type: 'add', // ,
multipleSelection: [], //
total: 0, //
})
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 = () => {
console.log('addSwiper', addSwiper.value)
state.type = 'add'
addSwiper.value.open()
}
//
const handleEdit = (id) => {
state.type = 'edit'
addSwiper.value.open(id)
}
// change
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 changePage = (val) => {
state.currentPage = val
getCarousels()
}
</script>
<style scoped>
.swiper-container {
min-height: 100%;
}
.el-card.is-always-shadow {
min-height: 100%!important;
}
<style>
</style>

35
vite.config.js

@ -1,25 +1,14 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import path from 'path'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import ElementPlus from 'unplugin-element-plus/vite' // 不加这个配置,ElMessage出不来
import path from 'path'
const baseUrl = {
development: './',
beta: './',
release: './'
}
// https://vitejs.dev/config/
export default ({ mode }) => defineConfig({
export default ({ mode }) => defineConfig({
plugins: [
vue(),
// 按需加在
AutoImport({
resolvers: [ElementPlusResolver()],
}),
// 按需引入,主题色的配置,需要加上 importStyle: 'sass'
Components({
resolvers: [ElementPlusResolver({
@ -28,11 +17,20 @@ export default ({ mode }) => defineConfig({
}),
ElementPlus()
],
base: baseUrl[mode],
resolve: {
alias: {
'~': path.resolve(__dirname, './'),
'@': path.resolve(__dirname, 'src')
},
},
base: './',
server: {
proxy: {
'/api': {
target: 'http://backend-api-02.newbee.ltd/manage-api/v1', // 凡是遇到 /api 路径的请求,都映射到 target 属性
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '') // 重写 api 为 空,就是去掉它
}
}
},
css: {
@ -43,13 +41,4 @@ export default ({ mode }) => defineConfig({
},
},
},
server: {
proxy: {
'/api': {
target: 'http://backend-api-02.newbee.ltd/manage-api/v1',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '')
}
}
}
})

4179
yarn.lock
File diff suppressed because it is too large
View File

Loading…
Cancel
Save