merge
This commit is contained in:
commit
1387938b75
@ -20,9 +20,10 @@
|
|||||||
"@types/node": "^18.11.10",
|
"@types/node": "^18.11.10",
|
||||||
"@vitejs/plugin-vue": "^3.2.0",
|
"@vitejs/plugin-vue": "^3.2.0",
|
||||||
"@vitejs/plugin-vue-jsx": "^2.1.1",
|
"@vitejs/plugin-vue-jsx": "^2.1.1",
|
||||||
"typescript": "^4.9.3",
|
|
||||||
"vite": "^3.2.4",
|
|
||||||
"less": "^4.1.3",
|
"less": "^4.1.3",
|
||||||
|
"typescript": "^4.9.3",
|
||||||
|
"unplugin-vue-define-options": "^1.0.0",
|
||||||
|
"vite": "^3.2.4",
|
||||||
"vue-tsc": "^1.0.11"
|
"vue-tsc": "^1.0.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,8 @@
|
|||||||
--info-color: #1890ff;
|
--info-color: #1890ff;
|
||||||
--info-color-deprecated-bg: #e6f7ff;
|
--info-color-deprecated-bg: #e6f7ff;
|
||||||
--info-color-deprecated-border: #91d5ff;
|
--info-color-deprecated-border: #91d5ff;
|
||||||
|
--placeholder-color: #ccc;
|
||||||
|
--border-color: #d9d9d9;
|
||||||
|
|
||||||
--primary-color-text: #333;
|
--primary-color-text: #333;
|
||||||
--font-size: 14px;
|
--font-size: 14px;
|
||||||
@ -48,7 +50,8 @@
|
|||||||
--border-radius-middle: calc(var(--border-radius) + 2px);
|
--border-radius-middle: calc(var(--border-radius) + 2px);
|
||||||
--border-radius-large: calc(var(--border-radius) + 3px);
|
--border-radius-large: calc(var(--border-radius) + 3px);
|
||||||
|
|
||||||
--header-height: 80px;
|
--header-bg: #001529;
|
||||||
|
--header-height: 50px;
|
||||||
--left-menu-width: 200px;
|
--left-menu-width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,13 +122,55 @@ body {
|
|||||||
.pointer-cursor {
|
.pointer-cursor {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
table{
|
|
||||||
width: 100%;
|
.table-wrapper {
|
||||||
border-left: solid 1px #eee;
|
.table-toolbar{
|
||||||
border-top: solid 1px #eee;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border: solid 1px #eee;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
th{
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
}
|
||||||
|
td, th {
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: solid 1px #eee;
|
||||||
|
padding: 6px 8px;
|
||||||
|
}
|
||||||
|
tr{
|
||||||
|
&:hover{
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
td,th {
|
|
||||||
border-right: solid 1px #eee;
|
.page-wrapper {
|
||||||
border-bottom: solid 1px #eee;
|
margin: 20px 0;
|
||||||
padding:2px 4px;
|
font-size: 12px;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
.page-item {
|
||||||
|
cursor: pointer;
|
||||||
|
border: solid 1px var(--primary-2);
|
||||||
|
border-radius: var(--border-radius-middle);
|
||||||
|
display: inline-block;
|
||||||
|
padding: 4px 6px;
|
||||||
|
margin: 0 5px;
|
||||||
|
min-width: 26px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&:hover, &.current-page {
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
color: var(--primary-color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.display-flex{
|
||||||
|
display: flex;
|
||||||
}
|
}
|
94
admin-fe/src/components/button/Index.vue
Normal file
94
admin-fe/src/components/button/Index.vue
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<template>
|
||||||
|
<button :disabled="disabled || loading" class="btn" :class="{
|
||||||
|
'btn-primary':btnType == 'primary',
|
||||||
|
'btn-default':btnType == 'default',
|
||||||
|
'btn-text':btnType == 'text',
|
||||||
|
'btn-link':btnType == 'link',
|
||||||
|
}">
|
||||||
|
<span v-if="loading" class="btn-icon">
|
||||||
|
<Loading v-if="loading" class="btn-icon-loading"/>
|
||||||
|
</span>
|
||||||
|
<slot></slot>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {defineOptions} from "unplugin-vue-define-options/macros";
|
||||||
|
import {computed} from "vue";
|
||||||
|
import Loading from "../icon/Loading.vue";
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'PButton'
|
||||||
|
})
|
||||||
|
type ButtonProps = {
|
||||||
|
type?: 'primary' | 'default' | 'text' | 'link'
|
||||||
|
/**
|
||||||
|
* 是否正在加载中
|
||||||
|
*/
|
||||||
|
loading?: boolean
|
||||||
|
disabled?: boolean
|
||||||
|
}
|
||||||
|
const props = defineProps<ButtonProps>()
|
||||||
|
const btnType = computed(() => props.type || 'primary')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
@keyframes anim-loading {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 5px 15px;
|
||||||
|
line-height: 20px;
|
||||||
|
border-radius: var(--border-radius-middle);
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
&.btn-primary {
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
color: white;
|
||||||
|
&:hover{
|
||||||
|
background-color: var(--primary-color-hover);
|
||||||
|
}
|
||||||
|
&:active{
|
||||||
|
background-color: var(--primary-color-active);
|
||||||
|
}
|
||||||
|
&[disabled]{
|
||||||
|
background-color: var(--primary-3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.btn-default {
|
||||||
|
}
|
||||||
|
|
||||||
|
&.btn-text {
|
||||||
|
}
|
||||||
|
|
||||||
|
&.btn-link {
|
||||||
|
padding:2px;
|
||||||
|
background: none;
|
||||||
|
color: var(--primary-color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon {
|
||||||
|
margin-right: 5px;
|
||||||
|
|
||||||
|
.btn-icon-loading {
|
||||||
|
height: 16px !important;
|
||||||
|
width: 16px !important;
|
||||||
|
vertical-align: middle;
|
||||||
|
animation: anim-loading 1s infinite linear;
|
||||||
|
//transition: transform ;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
17
admin-fe/src/components/icon/ArrowDown.vue
Normal file
17
admin-fe/src/components/icon/ArrowDown.vue
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<svg :style="sizeStyle" class="icon-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
|
||||||
|
<path fill="currentColor"
|
||||||
|
d="M500.8 604.779L267.307 371.392l-45.227 45.27 278.741 278.613L779.307 416.66l-45.248-45.248z"></path>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import {defineComponent} from "vue";
|
||||||
|
import iconComponent from "./iconComponent";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "ArrowDown",
|
||||||
|
props: iconComponent.props,
|
||||||
|
setup: iconComponent.setup
|
||||||
|
})
|
||||||
|
</script>
|
18
admin-fe/src/components/icon/Loading.vue
Normal file
18
admin-fe/src/components/icon/Loading.vue
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<template>
|
||||||
|
<svg :style="sizeStyle" class="icon-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
|
||||||
|
<path fill="currentColor"
|
||||||
|
d="M270.4 214.4C336 160 420 128 512 128c212 0 384 172 384 384h64c0-247.2-200.8-448-448-448-107.2 0-205.6 37.6-282.4 100l40.8 50.4z"
|
||||||
|
p-id="2703"></path>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import {defineComponent} from "vue";
|
||||||
|
import iconComponent from "./iconComponent";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "Loading",
|
||||||
|
props: iconComponent.props,
|
||||||
|
setup: iconComponent.setup
|
||||||
|
})
|
||||||
|
</script>
|
@ -24,144 +24,151 @@ import Eye from "../icon/Eye.vue";
|
|||||||
import EyeClose from "../icon/EyeClose.vue";
|
import EyeClose from "../icon/EyeClose.vue";
|
||||||
|
|
||||||
interface PInputEvents {
|
interface PInputEvents {
|
||||||
'update:modelValue': (value: string) => void
|
'update:modelValue': (value: any) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
type PInputProps = {
|
type PInputProps = {
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
modelValue?: string
|
modelValue?: any
|
||||||
type?: 'text' | 'password' | 'textarea'
|
type?: 'text' | 'password' | 'textarea'
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<PInputProps>()
|
const props = defineProps<PInputProps>()
|
||||||
const emit = defineEmits<PInputEvents>()
|
const emit = defineEmits<PInputEvents>()
|
||||||
const slots = useSlots()
|
const slots = useSlots()
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
focus: false,
|
focus: false,
|
||||||
hover: false,
|
hover: false,
|
||||||
passwordVisible: false
|
passwordVisible: false
|
||||||
})
|
})
|
||||||
const inputType = computed(() => {
|
const inputType = computed(() => {
|
||||||
const type = props.type || 'text';
|
const type = props.type || 'text';
|
||||||
if (type === 'password' && state.passwordVisible) return 'text';
|
if (type === 'password' && state.passwordVisible) return 'text';
|
||||||
return type;
|
return type;
|
||||||
})
|
})
|
||||||
const value = computed({
|
const value = computed({
|
||||||
get() {
|
get() {
|
||||||
return props.modelValue
|
return props.modelValue
|
||||||
},
|
},
|
||||||
set(value) {
|
set(value) {
|
||||||
emit('update:modelValue', value)
|
emit('update:modelValue', value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
@height: 30px;
|
||||||
|
|
||||||
.p-input-box-focus {
|
.p-input-box-focus {
|
||||||
|
|
||||||
border-color: #2a7dc9;
|
border-color: #2a7dc9;
|
||||||
box-shadow: 0 0 0 2px #0960bd33;
|
box-shadow: 0 0 0 2px #0960bd33;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-input {
|
.p-input {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding: 4px 11px;
|
padding: 0px 11px;
|
||||||
color: #000000d9;
|
color: #000000d9;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 1.5715;
|
line-height: 1.5715;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
background-image: none;
|
background-image: none;
|
||||||
border: 1px solid #d9d9d9;
|
border: 1px solid #d9d9d9;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
transition: all .3s;
|
transition: all .3s;
|
||||||
|
height: @height;
|
||||||
|
|
||||||
&::-moz-placeholder {
|
&::-moz-placeholder {
|
||||||
opacity: 1
|
opacity: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
color: #bfbfbf;
|
color: #bfbfbf;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
user-select: none
|
user-select: none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
&:placeholder-shown {
|
&:placeholder-shown {
|
||||||
text-overflow: ellipsis
|
text-overflow: ellipsis
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: #2a7dc9;
|
border-color: #2a7dc9;
|
||||||
border-right-width: 1px !important
|
border-right-width: 1px !important
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-input-rtl .p-input:hover {
|
.p-input-rtl .p-input:hover {
|
||||||
border-right-width: 0;
|
border-right-width: 0;
|
||||||
border-left-width: 1px !important
|
border-left-width: 1px !important
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus, .p-input-focused {
|
&:focus, .p-input-focused {
|
||||||
border-right-width: 1px !important;
|
border-right-width: 1px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-input-disabled {
|
.p-input-disabled {
|
||||||
color: #00000040;
|
color: #00000040;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
border-color: #d9d9d9;
|
border-color: #d9d9d9;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
opacity: 1
|
opacity: 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.p-input-wrapper {
|
.p-input-wrapper {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-input-wrapper-group {
|
.p-input-wrapper-group {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding: 4px 6px;
|
padding: 0px 6px;
|
||||||
color: #000000d9;
|
color: #000000d9;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 1.5715;
|
line-height: 1.5715;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
background-image: none;
|
background-image: none;
|
||||||
border: 1px solid #d9d9d9;
|
border: 1px solid #d9d9d9;
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
transition: all .3s;
|
transition: all .3s;
|
||||||
|
height: @height;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: #2a7dc9;
|
border-color: #2a7dc9;
|
||||||
border-right-width: 1px !important
|
border-right-width: 1px !important
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-input {
|
.p-input {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
margin: 0 6px;
|
margin: 0 6px;
|
||||||
|
height: 28px;
|
||||||
&:focus {
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
&:focus {
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-input-prefix, .p-input-suffix {
|
.p-input-prefix, .p-input-suffix {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: none;
|
flex: none;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,7 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="modal" v-if="modalVisible">
|
<div class="modal" v-if="modalVisible">
|
||||||
<div class="modal-mask"></div>
|
<div class="modal-mask"></div>
|
||||||
<div class="modal-content">
|
<div class="modal-content" :style="{
|
||||||
|
width: width+(/(px|%)/.test(width)?'':'px')
|
||||||
|
}">
|
||||||
<div class="modal-close" @click="modalVisible = false">关闭</div>
|
<div class="modal-close" @click="modalVisible = false">关闭</div>
|
||||||
<slot/>
|
<slot/>
|
||||||
</div>
|
</div>
|
||||||
@ -12,8 +14,12 @@
|
|||||||
import {computed} from "vue";
|
import {computed} from "vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "modal",
|
name: "Modal",
|
||||||
props: {
|
props: {
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: '500px'
|
||||||
|
},
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
require: true
|
require: true
|
||||||
|
79
admin-fe/src/components/pager/Pager.vue
Normal file
79
admin-fe/src/components/pager/Pager.vue
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page-wrapper">
|
||||||
|
<span v-if="showRefresh" class="page-item refresh" @click="$emit('refresh')">刷新</span>
|
||||||
|
<span v-if="page > 1" class="prev-page page-item" @click="$emit('page-change',--page)">上一页</span>
|
||||||
|
<span class="page-item page-first" :class="{'current-page':page == 1}"
|
||||||
|
@click="$emit('page-change',(page=1))">1</span>
|
||||||
|
<template v-for="index in pageData">
|
||||||
|
<span class="page-item" :class="{'current-page':page == index}" @click="$emit('page-change',(page=index))">{{
|
||||||
|
index
|
||||||
|
}}</span>
|
||||||
|
</template>
|
||||||
|
<span class="page-item page-end" :class="{'current-page':page == totalPage}"
|
||||||
|
@click="$emit('page-change',(page=totalPage))">{{
|
||||||
|
totalPage
|
||||||
|
}}</span>
|
||||||
|
<span v-if="page < totalPage" class="page-item next-page" @click="$emit('page-change',++ page)">下一页</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {computed, defineComponent, ref} from 'vue'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "Pager",
|
||||||
|
props: {
|
||||||
|
/**
|
||||||
|
* 总条数
|
||||||
|
*/
|
||||||
|
total: {
|
||||||
|
type: Number,
|
||||||
|
require: true
|
||||||
|
},
|
||||||
|
showRefresh: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 每页的条数
|
||||||
|
*/
|
||||||
|
pageSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 10
|
||||||
|
},
|
||||||
|
currentPage: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['refresh', 'page-change'],
|
||||||
|
setup(props) {
|
||||||
|
const totalPage = computed(() => Math.ceil((props.total || 0) / props.pageSize))
|
||||||
|
const page = ref(props.currentPage)
|
||||||
|
const pageData = computed(() => {
|
||||||
|
// 循环使用的开始和结束页码
|
||||||
|
let start = page.value - 2, end = page.value + 2
|
||||||
|
if (start <= 1) {
|
||||||
|
// 补足少的页码
|
||||||
|
end += 1 - start;
|
||||||
|
start = 2;
|
||||||
|
}
|
||||||
|
if (end >= totalPage.value) {
|
||||||
|
end = totalPage.value - 1;
|
||||||
|
start = end - 4;
|
||||||
|
if (start <= 1) {
|
||||||
|
start = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const pages = []
|
||||||
|
for (; start <= end; start++) {
|
||||||
|
pages.push(start)
|
||||||
|
}
|
||||||
|
return pages
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
totalPage, page, pageData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
4
admin-fe/src/components/pager/index.ts
Normal file
4
admin-fe/src/components/pager/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import PagerComponent from './Pager.vue'
|
||||||
|
|
||||||
|
const Pager = PagerComponent
|
||||||
|
export default Pager
|
33
admin-fe/src/components/select/Option.vue
Normal file
33
admin-fe/src/components/select/Option.vue
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<template>
|
||||||
|
<li :ref="element" @click="onClick($event)">
|
||||||
|
<slot></slot>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import {defineComponent, onMounted, onUpdated, ref} from "vue";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "POption",
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: [String, Number, Object],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['select'],
|
||||||
|
setup(props,context) {
|
||||||
|
function onClick(e) {
|
||||||
|
e.target.data = props.value
|
||||||
|
}
|
||||||
|
const element = ref<HTMLElement>()
|
||||||
|
|
||||||
|
return {
|
||||||
|
element,onClick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
159
admin-fe/src/components/select/Select.vue
Normal file
159
admin-fe/src/components/select/Select.vue
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
<template>
|
||||||
|
<div class="select-wrapper" :class="{active:isActive}" v-click-outside="onClose">
|
||||||
|
<div class="select-box-wrapper" @click="isActive = !isActive">
|
||||||
|
<div class="select-value">{{ selectValue }}<span v-if="!selectValue" class="placeholder">{{ placeholder }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="icon-arrow">
|
||||||
|
<ArrowDown class="icon-select-arrow"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="select-options-wrapper">
|
||||||
|
<ul @click="onSelect">
|
||||||
|
<slot></slot>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import ArrowDown from "../icon/ArrowDown.vue";
|
||||||
|
import {defineComponent, nextTick, ref, SetupContext} from "vue";
|
||||||
|
import {CHANGE_EVENT, UPDATE_MODEL_EVENT} from "../../service/constants";
|
||||||
|
|
||||||
|
export interface OptionItemType {
|
||||||
|
label: string;
|
||||||
|
value?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
// declare var OptionItemArray: OptionItemType[];
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "PSelect",
|
||||||
|
components: {ArrowDown},
|
||||||
|
props: {
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请选择'
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number, Object]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: [
|
||||||
|
UPDATE_MODEL_EVENT,
|
||||||
|
CHANGE_EVENT,
|
||||||
|
'focus',
|
||||||
|
'blur',
|
||||||
|
],
|
||||||
|
setup(props, ctx: SetupContext) {
|
||||||
|
const selectValue = ref(props.modelValue)
|
||||||
|
const isActive = ref(false)
|
||||||
|
|
||||||
|
function onSelect(e: MouseEvent) {
|
||||||
|
// 原生dom操作
|
||||||
|
const target = e.target as HTMLElement;
|
||||||
|
if (target.tagName.toLowerCase() != 'li') return;
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
//
|
||||||
|
const text = target.textContent
|
||||||
|
selectValue.value = text
|
||||||
|
const arr = [].slice.call (target.parentElement.children)
|
||||||
|
arr.forEach(ele => (ele as HTMLElement).classList.remove("selected"))
|
||||||
|
target.classList.add("selected")
|
||||||
|
console.log(target.data)
|
||||||
|
ctx.emit(UPDATE_MODEL_EVENT,target.data)
|
||||||
|
onClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onClose() {
|
||||||
|
isActive.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
selectValue, isActive, onClose, onSelect
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.select-wrapper {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
.select-options-wrapper {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-box-wrapper {
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
box-shadow: 0 0 3px var(--primary-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-box-wrapper {
|
||||||
|
display: inline-flex;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
padding: 3px 6px;
|
||||||
|
color: #000000d9;
|
||||||
|
font-size: 14px;
|
||||||
|
background-color: #fff;
|
||||||
|
background-image: none;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: var(--border-radius-middle);
|
||||||
|
transition: all .3s;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
color: var(--placeholder-color)
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-value {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 右侧图标
|
||||||
|
.icon-arrow {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--border-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-options-wrapper {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
background-color: #fff;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 32px;
|
||||||
|
box-shadow: 0 0 7px rgba(0, 0, 0, 0.1);
|
||||||
|
border-radius: var(--border-radius-middle);
|
||||||
|
|
||||||
|
ul, li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
line-height: 30px;
|
||||||
|
padding: 0 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
0
admin-fe/src/components/uploader/index.ts
Normal file
0
admin-fe/src/components/uploader/index.ts
Normal file
71
admin-fe/src/components/uploader/uploader.vue
Normal file
71
admin-fe/src/components/uploader/uploader.vue
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<template>
|
||||||
|
<div class="upload-wrapper">
|
||||||
|
<input type="file" :id="fileUploaderId" :accept="accept" @change="onFileSelectChange" class="file-handler"/>
|
||||||
|
<label :for="fileUploaderId">
|
||||||
|
<!-- 上传触发元素的插槽 -->
|
||||||
|
<slot/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import {defineComponent} from "vue";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "Uploader"
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import http from "../../util/http";
|
||||||
|
|
||||||
|
type PropsType = {
|
||||||
|
/**
|
||||||
|
* 上传路径
|
||||||
|
*/
|
||||||
|
action: string
|
||||||
|
/**
|
||||||
|
* 文件上传默认的参数名称,默认为file
|
||||||
|
*/
|
||||||
|
fieldName?: string
|
||||||
|
/**
|
||||||
|
* 允许上传的文件类型,默认为*表示所有文件
|
||||||
|
*/
|
||||||
|
accept?: string
|
||||||
|
|
||||||
|
modelValue?: string
|
||||||
|
}
|
||||||
|
type EmitsType = {
|
||||||
|
onSuccess: () => void
|
||||||
|
onError: () => void
|
||||||
|
'update:modelValue': (value: string) => void
|
||||||
|
}
|
||||||
|
type FileUploadResultModel = {
|
||||||
|
url: string
|
||||||
|
name?: string
|
||||||
|
}
|
||||||
|
const props = defineProps<PropsType>()
|
||||||
|
const emits = defineEmits<EmitsType>()
|
||||||
|
const fileUploaderId = Math.random().toString(16).substring(3)
|
||||||
|
|
||||||
|
async function onFileSelectChange(e: InputEvent) {
|
||||||
|
//@ts-ignore
|
||||||
|
const files = e.target.files as FileList
|
||||||
|
if (!files || files.length == 0) return;
|
||||||
|
const data = {},fieldName = props.fieldName || 'file'
|
||||||
|
data[fieldName] = files[0];
|
||||||
|
const ret = await http.request<FileUploadResultModel>(props.action, data, 'post', 'form')
|
||||||
|
emits('update:modelValue', ret.url)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.upload-wrapper{
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.file-handler{
|
||||||
|
opacity: 0;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
</style>
|
60
admin-fe/src/directive/click_outside.ts
Normal file
60
admin-fe/src/directive/click_outside.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import type {
|
||||||
|
ObjectDirective,
|
||||||
|
} from 'vue'
|
||||||
|
|
||||||
|
const nodeList = new Map<Element, Function>();
|
||||||
|
document.addEventListener('mousedown', (e: MouseEvent) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
// @ts-ignore
|
||||||
|
const paths = e.path as Element[];
|
||||||
|
// console.log(paths)
|
||||||
|
// 已经绑定过指令的元素
|
||||||
|
nodeList.forEach((fn, ele) => {
|
||||||
|
// 当前点击元素的数组
|
||||||
|
for (const c of paths) {
|
||||||
|
// 找到对应的元素 说明是点击了该元素或者他的子元素
|
||||||
|
if (c == ele) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 没有找到 说明在外面 可以出发事件
|
||||||
|
fn.call(null)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 定义指令
|
||||||
|
const clickOutside: ObjectDirective = {
|
||||||
|
// 在绑定元素的 attribute 前
|
||||||
|
// 或事件监听器应用前调用
|
||||||
|
created(el, binding, vnode, prevVnode) {
|
||||||
|
// 下面会介绍各个参数的细节
|
||||||
|
nodeList.set(el,binding.value)
|
||||||
|
// console.log(nodeList)
|
||||||
|
},
|
||||||
|
// 在元素被插入到 DOM 前调用
|
||||||
|
beforeMount(el, binding, vnode, prevVnode) {
|
||||||
|
},
|
||||||
|
// 在绑定元素的父组件
|
||||||
|
// 及他自己的所有子节点都挂载完成后调用
|
||||||
|
mounted(el, binding, vnode, prevVnode) {
|
||||||
|
},
|
||||||
|
// 绑定元素的父组件更新前调用
|
||||||
|
beforeUpdate(el, binding, vnode, prevVnode) {
|
||||||
|
},
|
||||||
|
// 在绑定元素的父组件
|
||||||
|
// 及他自己的所有子节点都更新后调用
|
||||||
|
updated(el, binding, vnode, prevVnode) {
|
||||||
|
},
|
||||||
|
// 绑定元素的父组件卸载前调用
|
||||||
|
beforeUnmount(el, binding, vnode, prevVnode) {
|
||||||
|
nodeList.delete(el)
|
||||||
|
// console.log('remove ', index, el)
|
||||||
|
// nodeList.splice(index, 1)// 移除要销毁的元素
|
||||||
|
// console.log(nodeList)
|
||||||
|
},
|
||||||
|
// 绑定元素的父组件卸载后调用
|
||||||
|
unmounted(el, binding, vnode, prevVnode) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default clickOutside
|
@ -4,8 +4,9 @@ import {createPinia} from 'pinia'
|
|||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
import {httpConfig} from "./util/http";
|
import {httpConfig} from "./util/http";
|
||||||
import './assets/app.css'
|
import './assets/app.less'
|
||||||
import PInput from "./components/input";
|
import PInput from "./components/input";
|
||||||
|
import clickOutside from "./directive/click_outside";
|
||||||
|
|
||||||
httpConfig.baseURL = "http://localhost:8080"
|
httpConfig.baseURL = "http://localhost:8080"
|
||||||
|
|
||||||
@ -14,5 +15,6 @@ const app = createApp(App)
|
|||||||
app.use(router)
|
app.use(router)
|
||||||
app.use(createPinia());
|
app.use(createPinia());
|
||||||
app.component('PInput',PInput)
|
app.component('PInput',PInput)
|
||||||
|
app.directive('click-outside',clickOutside)
|
||||||
// 将应用实例挂载到 模板中
|
// 将应用实例挂载到 模板中
|
||||||
app.mount('#vue-root-app')
|
app.mount('#vue-root-app')
|
@ -2,24 +2,61 @@ import {RouteRecordRaw} from "vue-router";
|
|||||||
import Home from '../views/admin/Home.vue'
|
import Home from '../views/admin/Home.vue'
|
||||||
import Login from '../views/Login.vue'
|
import Login from '../views/Login.vue'
|
||||||
import NotFound from '../views/NotFound.vue'
|
import NotFound from '../views/NotFound.vue'
|
||||||
|
import Test from '../views/Test.vue'
|
||||||
import AdminLayout from '../views/layout/AdminLayout.vue'
|
import AdminLayout from '../views/layout/AdminLayout.vue'
|
||||||
import UserIndex from '../views/user/index.vue'
|
import UserIndex from '../views/user/index.vue'
|
||||||
|
import GoodsIndex from '../views/goods/index.vue'
|
||||||
|
import OrderIndex from '../views/goods/Order.vue'
|
||||||
|
|
||||||
|
export const AdminRoutes: RouteRecordRaw[] = [
|
||||||
|
{
|
||||||
|
path: 'home',
|
||||||
|
name: 'Home',
|
||||||
|
component: Home,
|
||||||
|
meta: {
|
||||||
|
title: 'Home'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'user',
|
||||||
|
name: 'UserIndex',
|
||||||
|
component: UserIndex,
|
||||||
|
meta: {
|
||||||
|
title: '用户管理'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'goods',
|
||||||
|
name: 'GoodsIndex',
|
||||||
|
component: GoodsIndex,
|
||||||
|
meta: {
|
||||||
|
title: '商品管理'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'order',
|
||||||
|
name: 'OrderIndex',
|
||||||
|
component: OrderIndex,
|
||||||
|
meta: {
|
||||||
|
title: '订单管理'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'test',
|
||||||
|
name: 'TestIndex',
|
||||||
|
component: Test,
|
||||||
|
meta: {
|
||||||
|
title: '测试页'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
const routes: RouteRecordRaw[] = [
|
const routes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
component: AdminLayout,
|
component: AdminLayout,
|
||||||
redirect: '/home',
|
redirect: '/home',
|
||||||
children: [
|
children: AdminRoutes
|
||||||
{
|
|
||||||
path: 'home',
|
|
||||||
component: Home
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'user',
|
|
||||||
component: UserIndex
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: '/login',
|
||||||
|
3
admin-fe/src/service/constants.ts
Normal file
3
admin-fe/src/service/constants.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const UPDATE_MODEL_EVENT = 'update:modelValue'
|
||||||
|
export const CHANGE_EVENT = 'change'
|
||||||
|
export const INPUT_EVENT = 'input'
|
@ -52,7 +52,6 @@ export const useUserStore = defineStore('user-store', () => {
|
|||||||
const data = await http.get<AdminLoginModel>('/admin/user/info')
|
const data = await http.get<AdminLoginModel>('/admin/user/info')
|
||||||
localStorage.removeItem(TOKEN_KEY)
|
localStorage.removeItem(TOKEN_KEY)
|
||||||
userinfo.value = null
|
userinfo.value = null
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {userinfo, login, logout, updateInfo, token}
|
return {userinfo, login, logout, updateInfo, token}
|
||||||
|
31
admin-fe/src/service/types.d.ts
vendored
31
admin-fe/src/service/types.d.ts
vendored
@ -26,4 +26,35 @@ type UserInfoModel = {
|
|||||||
status: number;
|
status: number;
|
||||||
pointInfo: PointInfoModel;
|
pointInfo: PointInfoModel;
|
||||||
parent?: UserInfoModel | null;
|
parent?: UserInfoModel | null;
|
||||||
|
}
|
||||||
|
type GoodsModel = {
|
||||||
|
id?: number;
|
||||||
|
category?: number;
|
||||||
|
type?: number;
|
||||||
|
title?: string;
|
||||||
|
originPrice?: number;
|
||||||
|
price?: number;
|
||||||
|
stock?: number;
|
||||||
|
limitCount?: number;
|
||||||
|
cover?: string;
|
||||||
|
description?: string;
|
||||||
|
notice?: string;
|
||||||
|
onlineTime?: string;
|
||||||
|
offlineTime?: string;
|
||||||
|
createTime?: string;
|
||||||
|
updateTime?: string;
|
||||||
|
status?: number;
|
||||||
|
}
|
||||||
|
type OrderInfoModel = {
|
||||||
|
id?: string;
|
||||||
|
gid?: number;
|
||||||
|
orderTitle?: string;
|
||||||
|
price?: number;
|
||||||
|
count?: number;
|
||||||
|
uid?: number;
|
||||||
|
data?: any;
|
||||||
|
createTime?: string;
|
||||||
|
updateTime?: string;
|
||||||
|
status?: number;
|
||||||
|
owner?: UserInfoModel;
|
||||||
}
|
}
|
@ -1,12 +1,13 @@
|
|||||||
import {toast} from "../components/message";
|
import {toast} from "../components/message";
|
||||||
import {useUserStore} from "../service/store";
|
import {useUserStore} from "../service/store";
|
||||||
|
import router from '../router'
|
||||||
|
|
||||||
export type HttpMethod = 'get' | 'post' | 'delete' | 'put'
|
export type HttpMethod = 'get' | 'post' | 'delete' | 'put'
|
||||||
|
|
||||||
export enum RequestDataContentType {
|
export enum RequestDataContentType {
|
||||||
JSON = 'application/json;charset=UTF-8',
|
JSON = 'application/json;charset=UTF-8',
|
||||||
FORM = 'application/x-www-form-urlencoded;charset=UTF-8',
|
FORM = 'application/x-www-form-urlencoded;charset=UTF-8',
|
||||||
FORM_DATA = 'multipart/form-data;charset=UTF-8',
|
FORM_DATA = 'multipart/form-data',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const httpConfig = {
|
export const httpConfig = {
|
||||||
@ -41,6 +42,17 @@ class Http {
|
|||||||
return this.request<T>(url, data, 'get')
|
return this.request<T>(url, data, 'get')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
put<T>(url, data = null) {
|
||||||
|
return this.request<T>(url, data, 'put')
|
||||||
|
}
|
||||||
|
|
||||||
|
remove<T>(url, data = null) {
|
||||||
|
return this.request<T>(url, data, 'delete')
|
||||||
|
}
|
||||||
|
delete<T>(url, data = null) {
|
||||||
|
return this.request<T>(url, data, 'delete')
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GET /xxxx?a=1&b=2
|
* GET /xxxx?a=1&b=2
|
||||||
* NAME: value
|
* NAME: value
|
||||||
@ -56,7 +68,9 @@ class Http {
|
|||||||
*/
|
*/
|
||||||
request<T>(url: string, data: any = null, method: HttpMethod = 'post', type: 'normal' | 'form' = 'normal') {
|
request<T>(url: string, data: any = null, method: HttpMethod = 'post', type: 'normal' | 'form' = 'normal') {
|
||||||
return new Promise<T>((resolve, reject) => {
|
return new Promise<T>((resolve, reject) => {
|
||||||
let contentType = RequestDataContentType.FORM;
|
const headers: any = {
|
||||||
|
'Content-Type': RequestDataContentType.FORM
|
||||||
|
}
|
||||||
if (data) {
|
if (data) {
|
||||||
if (type === 'form') {
|
if (type === 'form') {
|
||||||
const form = new FormData();
|
const form = new FormData();
|
||||||
@ -64,12 +78,13 @@ class Http {
|
|||||||
form.append(key, data[key]);
|
form.append(key, data[key]);
|
||||||
}
|
}
|
||||||
data = form; // 将data有{} => formData
|
data = form; // 将data有{} => formData
|
||||||
contentType = RequestDataContentType.FORM_DATA; // 由于使用formData
|
// contentType = RequestDataContentType.FORM_DATA; // 由于使用formData
|
||||||
|
delete headers['Content-Type'];
|
||||||
method = 'post';
|
method = 'post';
|
||||||
} else if (method == 'post') {
|
} else if (method == 'post' || method == 'put') {
|
||||||
// 将数据对象 转成json
|
// 将数据对象 转成json
|
||||||
data = JSON.stringify(data);
|
data = JSON.stringify(data);
|
||||||
contentType = RequestDataContentType.JSON;
|
headers['Content-Type'] = RequestDataContentType.JSON;
|
||||||
} else {
|
} else {
|
||||||
// 装对象转成 key=value&key=value
|
// 装对象转成 key=value&key=value
|
||||||
const params = [];
|
const params = [];
|
||||||
@ -80,10 +95,6 @@ class Http {
|
|||||||
url += '?' + params.join('&')
|
url += '?' + params.join('&')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const headers: any = {
|
|
||||||
'Content-Type': contentType
|
|
||||||
}
|
|
||||||
const token = useUserStore().token();
|
const token = useUserStore().token();
|
||||||
if (token) headers.token = token
|
if (token) headers.token = token
|
||||||
fetch(httpConfig.baseURL + url, {
|
fetch(httpConfig.baseURL + url, {
|
||||||
@ -99,9 +110,11 @@ class Http {
|
|||||||
// 需要统一处理数据
|
// 需要统一处理数据
|
||||||
if (code === 403) {
|
if (code === 403) {
|
||||||
toast("登录凭证无效或者已过期")
|
toast("登录凭证无效或者已过期")
|
||||||
// if (r.fullPath != '/login') {
|
// 通过router获取当前路由
|
||||||
// router.replace('/login');
|
const route = router.currentRoute;
|
||||||
// }
|
if (route.fullPath != '/login') {
|
||||||
|
router.replace('/login');
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
} else if (err) {
|
} else if (err) {
|
||||||
toast(httpConfig.globalErrorHandler[code])
|
toast(httpConfig.globalErrorHandler[code])
|
||||||
|
@ -63,7 +63,7 @@ p{
|
|||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
}
|
}
|
||||||
.login-wrapper {
|
.login-wrapper {
|
||||||
width: 500px;
|
width: 300px;
|
||||||
margin: 50px auto;
|
margin: 50px auto;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,43 +1,59 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="demo-box">
|
<div class="demo-box">
|
||||||
<div class="form-item">
|
<div>
|
||||||
<PInput placeholder="测试21" v-model="data.a">
|
<div class="form-item">
|
||||||
<template #suffix>
|
<PInput placeholder="测试21" v-model="data.a">
|
||||||
<span>密码</span>
|
<template #suffix>
|
||||||
</template>
|
<span>密码</span>
|
||||||
</PInput>
|
</template>
|
||||||
</div>
|
</PInput>
|
||||||
<div class="form-item">
|
</div>
|
||||||
<PInput type="password" placeholder="测试12" v-model="data.b"/>
|
<div class="form-item">
|
||||||
</div>
|
<PInput type="password" placeholder="测试12" v-model="data.b"/>
|
||||||
<div class="form-item">
|
</div>
|
||||||
<PInput type="password" placeholder="测试12" v-model="data.b"/>
|
<div class="form-item">
|
||||||
</div>
|
<PInput type="password" placeholder="测试12" v-model="data.b"/>
|
||||||
<div>
|
</div>
|
||||||
{{ JSON.stringify(data) }}
|
<div>
|
||||||
</div>
|
{{ JSON.stringify(data) }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<hr>
|
||||||
|
商品类型
|
||||||
|
<p-select v-model="select">
|
||||||
|
<p-option v-for="op in options" :key="op.value" :value="op">{{ op.label }}</p-option>
|
||||||
|
</p-select>
|
||||||
|
{{ JSON.stringify(select) }}
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import PInput from "../components/input";
|
import PInput from "../components/input";
|
||||||
import {reactive} from "vue";
|
import {reactive, ref} from "vue";
|
||||||
|
import PSelect from "../components/select/Select.vue";
|
||||||
|
import POption from "../components/select/Option.vue";
|
||||||
|
|
||||||
const data = reactive({
|
const data = reactive({
|
||||||
a: '1',
|
a: '1',
|
||||||
b: '2'
|
b: '2'
|
||||||
})
|
})
|
||||||
|
const options = [
|
||||||
|
{value: 1, label: '普通商品'},
|
||||||
|
{value: 2, label: '精选商品'},
|
||||||
|
{value: 3, label: '秒杀商品'},
|
||||||
|
]
|
||||||
|
const select = ref()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.demo-box {
|
.demo-box {
|
||||||
width: 500px;
|
width: 500px;
|
||||||
border: solid 1px #f00;
|
border: solid 1px #f00;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-item {
|
.form-item {
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
140
admin-fe/src/views/goods/Order.vue
Normal file
140
admin-fe/src/views/goods/Order.vue
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<div class="table-toolbar">
|
||||||
|
<div class="search-form">
|
||||||
|
<span>订单编号:<PInput style="width:200px" v-model="param.id" placeholder="要查询的订单编号"/></span>
|
||||||
|
<span>标题:<PInput style="width:200px" v-model="param.title" placeholder="要查询的订单标题"/></span>
|
||||||
|
<span>订单开始:<PInput style="width:200px" v-model="param.createTimeStart" placeholder="要查询的订单开始时间"/></span>
|
||||||
|
<span>订单结束:<PInput style="width:200px" v-model="param.createTimeEnd" placeholder="要查询的订单结束时间"/></span>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<PButton type="default" @click="onReset">重置</PButton>
|
||||||
|
</span>
|
||||||
|
<span><PButton :loading="searching" @click="onSearch">搜索</PButton></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>订单编号</th>
|
||||||
|
<th>标题</th>
|
||||||
|
<th>价格</th>
|
||||||
|
<th>数量</th>
|
||||||
|
<th>状态</th>
|
||||||
|
<th>用户</th>
|
||||||
|
<th>创建时间</th>
|
||||||
|
<th>操作</th>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="it in goodsList" :key="it.id">
|
||||||
|
<td>{{ it.id }}</td>
|
||||||
|
<td>{{ it.orderTitle }}</td>
|
||||||
|
<td>{{ it.price }}</td>
|
||||||
|
<td>{{ it.count }}</td>
|
||||||
|
<td>{{ StatusEnum[it.status] || '未知' }}</td>
|
||||||
|
<td>{{ it.owner?.nickname }}</td>
|
||||||
|
<td>{{ it.createTime }}</td>
|
||||||
|
<td width="160">
|
||||||
|
<PButton v-if="it.status == 1" type="link" @click="updateStatus(it.id,2)">确认</PButton>
|
||||||
|
<PButton v-if="it.status < 3" type="link" @click="updateStatus(it.id,3)">取消</PButton>
|
||||||
|
<PButton v-if="it.status < 3" type="link" @click="updateStatus(it.id,4)">完成</PButton>
|
||||||
|
<PButton type="link" @click="removeData(it.id)">删除</PButton>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<Pager :total="totalCount" show-refresh @refresh="loadDataList" @page-change="onPageChange"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {onMounted, reactive, ref} from "vue";
|
||||||
|
import http, {DataListModel} from "../../util/http";
|
||||||
|
import message from "../../components/message";
|
||||||
|
import Pager from "../../components/pager/Pager.vue";
|
||||||
|
import PButton from "../../components/button/Index.vue";
|
||||||
|
|
||||||
|
const StatusEnum = {
|
||||||
|
1: '待确认',
|
||||||
|
2: '已确认',
|
||||||
|
3: '已取消',
|
||||||
|
4: '已完成',
|
||||||
|
0: '已删除'
|
||||||
|
}
|
||||||
|
const param = reactive({
|
||||||
|
id: null,
|
||||||
|
title: null,
|
||||||
|
createTimeStart: null,
|
||||||
|
createTimeEnd: null,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10
|
||||||
|
})
|
||||||
|
|
||||||
|
const goodsList = ref<OrderInfoModel[]>([]);
|
||||||
|
const totalCount = ref(0)
|
||||||
|
const searching = ref(false)
|
||||||
|
|
||||||
|
function onPageChange(currentPage: number) {
|
||||||
|
param.page = currentPage;
|
||||||
|
loadDataList();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onReset() {
|
||||||
|
param.page = 1;
|
||||||
|
param.title = null;
|
||||||
|
param.id = null
|
||||||
|
param.createTimeStart = null
|
||||||
|
param.createTimeEnd = null
|
||||||
|
loadDataList();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSearch() {
|
||||||
|
param.page = 1;
|
||||||
|
loadDataList();
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadDataList() {
|
||||||
|
searching.value = true
|
||||||
|
http.post<DataListModel<OrderInfoModel>>('/admin/order/list', param).then(res => {
|
||||||
|
goodsList.value = res.items
|
||||||
|
totalCount.value = res.total
|
||||||
|
}).finally(() => searching.value = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateStatus(id: string, status: number) {
|
||||||
|
if (!confirm('是否继续操作?')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await http.put(`/admin/order/${id}/status?status=${status}`);
|
||||||
|
message.toast('操作成功');
|
||||||
|
loadDataList();
|
||||||
|
} catch (e) {
|
||||||
|
message.toast(e.message || '操作失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除用户
|
||||||
|
* @param id 要删除的用户id
|
||||||
|
*/
|
||||||
|
async function removeData(id: string) {
|
||||||
|
if (!confirm('是否删除?')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await http.delete(`/admin/order/${id}`);
|
||||||
|
message.toast('删除成功');
|
||||||
|
loadDataList();
|
||||||
|
} catch (e) {
|
||||||
|
message.toast(e.message || '删除失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(loadDataList)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.search-form span {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
296
admin-fe/src/views/goods/index.vue
Normal file
296
admin-fe/src/views/goods/index.vue
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<div class="table-toolbar">
|
||||||
|
<div class="search-form">
|
||||||
|
<span>标题:<PInput style="width:200px" v-model="param.title" placeholder="要查询的商品标题"/></span>
|
||||||
|
<span>
|
||||||
|
分类:
|
||||||
|
<PSelect v-model="param.category">
|
||||||
|
<POption v-for="(text,value) in CategoryEnum" :key="value" :value="value">{{text}}</POption>
|
||||||
|
</PSelect>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<PButton type="default" @click="onReset">重置</PButton>
|
||||||
|
</span>
|
||||||
|
<span><PButton :loading="searching" @click="onSearch">搜索</PButton></span>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-extra">
|
||||||
|
<PButton @click="onEditData({id:0})">新增</PButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>商品编号</th>
|
||||||
|
<th>标题</th>
|
||||||
|
<th>图片</th>
|
||||||
|
<th>分类</th>
|
||||||
|
<th>类型</th>
|
||||||
|
<th>原价</th>
|
||||||
|
<th>售卖价</th>
|
||||||
|
<th>库存</th>
|
||||||
|
<th>限购数量</th>
|
||||||
|
<th>上架时间</th>
|
||||||
|
<th>下架时间</th>
|
||||||
|
<th>状态</th>
|
||||||
|
<th>操作</th>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="it in goodsList" :key="it.id">
|
||||||
|
<td>{{ it.id }}</td>
|
||||||
|
<td>{{ it.title }}</td>
|
||||||
|
<td><img :src="it.cover" style="width: 32px;height: 32px;"/></td>
|
||||||
|
<td>{{ CategoryEnum[it.category] || '未知' }}</td>
|
||||||
|
<td>{{ TypeEnum[it.type] || '未知' }}</td>
|
||||||
|
<td>{{ it.originPrice == 0 ? '-' : it.originPrice }}</td>
|
||||||
|
<td>{{ it.price }}</td>
|
||||||
|
<td>{{ it.stock }}</td>
|
||||||
|
<td>{{ it.limitCount }}</td>
|
||||||
|
<td>{{ it.onlineTime }}</td>
|
||||||
|
<td>{{ it.offlineTime }}</td>
|
||||||
|
<td>{{ StatusEnum[it.status] || '未知' }}</td>
|
||||||
|
<td>
|
||||||
|
<PButton type="link" @click="onEditData(it)">编辑</PButton>
|
||||||
|
<PButton type="link">禁用</PButton>
|
||||||
|
<PButton type="link" @click="removeData(it.id)">删除</PButton>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<Pager :total="totalCount" show-refresh @refresh="loadDataList" @page-change="onPageChange"/>
|
||||||
|
</div>
|
||||||
|
<Modal v-model="modalVisible">
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<span>标题</span>
|
||||||
|
<p>
|
||||||
|
<PInput placeholder="请输入标题" v-model="editData.title"/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="display-flex">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<span>分类</span>
|
||||||
|
<p>
|
||||||
|
<select v-model="editData.category">
|
||||||
|
<option v-for="(text,value) in CategoryEnum" :key="value" :value="value">{{ text }}</option>
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>类型</span>
|
||||||
|
<p>
|
||||||
|
<select v-model="editData.type">
|
||||||
|
<option v-for="(text,value) in TypeEnum" :key="value" :value="value">{{ text }}</option>
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>商品图片</span>
|
||||||
|
<!-- 上传组件 -->
|
||||||
|
<Uploader action="/file/upload" v-model="editData.cover">
|
||||||
|
<div v-if="editData.cover">
|
||||||
|
<img :src="editData.cover" alt="" style="width: 120px;height: 120px;">
|
||||||
|
</div>
|
||||||
|
<div v-else>选择商品图</div>
|
||||||
|
</Uploader>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>描述</span>
|
||||||
|
<p>
|
||||||
|
<PInput placeholder="请输入描述" v-model="editData.description"/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>原价</span>
|
||||||
|
<p>
|
||||||
|
<PInput type="number" placeholder="请输入原价" v-model="editData.originPrice"/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>销售价格</span>
|
||||||
|
<p>
|
||||||
|
<PInput type="number" placeholder="请输入销售价格" v-model="editData.price"/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>库存</span>
|
||||||
|
<p>
|
||||||
|
<PInput type="number" placeholder="请输入库存" v-model="editData.stock"/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>限购数量</span>
|
||||||
|
<p>
|
||||||
|
<PInput type="number" placeholder="请输入限购数量" v-model="editData.limitCount"/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>上架时间</span>
|
||||||
|
<p>
|
||||||
|
<PInput placeholder="请输入上架时间" v-model="editData.onlineTime"/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>下架时间</span>
|
||||||
|
<p>
|
||||||
|
<PInput placeholder="请输入下架时间" v-model="editData.offlineTime"/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<PButton @click="saveGoodsData">提交</PButton>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {onMounted, reactive, ref} from "vue";
|
||||||
|
import http, {DataListModel} from "../../util/http";
|
||||||
|
import message from "../../components/message";
|
||||||
|
import Modal from "../../components/modal/modal.vue";
|
||||||
|
import Pager from "../../components/pager/Pager.vue";
|
||||||
|
import Uploader from "../../components/uploader/uploader.vue";
|
||||||
|
import PButton from "../../components/button/Index.vue";
|
||||||
|
import PSelect, {OptionItemType} from "../../components/select/Select.vue";
|
||||||
|
import POption from "../../components/select/Option.vue";
|
||||||
|
|
||||||
|
//
|
||||||
|
//商品类别(1:普通 2:精选 3:秒杀 4:抽奖)
|
||||||
|
const CategoryEnum = {
|
||||||
|
1: '普通',
|
||||||
|
2: '精选',
|
||||||
|
3: '秒杀',
|
||||||
|
4: '抽奖',
|
||||||
|
}
|
||||||
|
//商品类型(1:实物 2:虚拟)
|
||||||
|
const TypeEnum = {
|
||||||
|
1: '实物',
|
||||||
|
2: '虚拟'
|
||||||
|
}
|
||||||
|
|
||||||
|
const options: OptionItemType[] = [
|
||||||
|
{
|
||||||
|
label: '普通', value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '精选', value: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '秒杀', value: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const StatusEnum = {
|
||||||
|
1: '正常',
|
||||||
|
2: '禁用',
|
||||||
|
0: '已删除'
|
||||||
|
}
|
||||||
|
const param = reactive({
|
||||||
|
title: null,
|
||||||
|
category: null,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10
|
||||||
|
})
|
||||||
|
const modalVisible = ref(false)
|
||||||
|
|
||||||
|
const goodsList = ref<GoodsModel[]>([]);
|
||||||
|
const editData = reactive<GoodsModel>({
|
||||||
|
id: 0
|
||||||
|
});
|
||||||
|
const totalCount = ref(0)
|
||||||
|
const searching = ref(false)
|
||||||
|
const saving = ref(false)
|
||||||
|
|
||||||
|
function onPageChange(currentPage: number) {
|
||||||
|
param.page = currentPage;
|
||||||
|
loadDataList();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onReset() {
|
||||||
|
param.page = 1;
|
||||||
|
param.title = null;
|
||||||
|
param.category = null
|
||||||
|
loadDataList();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSearch() {
|
||||||
|
param.page = 1;
|
||||||
|
loadDataList();
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadDataList() {
|
||||||
|
searching.value = true
|
||||||
|
http.post<DataListModel<GoodsModel>>('/admin/goods/list', param).then(res => {
|
||||||
|
goodsList.value = res.items
|
||||||
|
totalCount.value = res.total
|
||||||
|
}).finally(() => searching.value = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillDataToObject(obj: any, data: any, keys: string[]) {
|
||||||
|
keys.forEach(key => {
|
||||||
|
if (typeof (data[key]) === 'undefined') {
|
||||||
|
if (typeof (obj[key]) != 'undefined') {
|
||||||
|
// 如果数据的字段不存在则将在字段的值设置为null
|
||||||
|
obj[key] = null;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
obj[key] = data[key]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const fieldKey = [
|
||||||
|
'id', 'cover', 'title',
|
||||||
|
'type', 'category', 'description',
|
||||||
|
'offlineTime', 'onlineTime', 'price',
|
||||||
|
'originPrice', 'stock', 'limitCount',
|
||||||
|
]
|
||||||
|
|
||||||
|
function onEditData(data: GoodsModel) {
|
||||||
|
fillDataToObject(editData, data, fieldKey)
|
||||||
|
modalVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveGoodsData() {
|
||||||
|
try {
|
||||||
|
saving.value = true
|
||||||
|
if (editData.id <= 0) {
|
||||||
|
await http.post('/admin/goods', editData)
|
||||||
|
} else {
|
||||||
|
await http.put(`/admin/goods/${editData.id}`, editData)
|
||||||
|
}
|
||||||
|
modalVisible.value = false;
|
||||||
|
message.toast('保存成功');
|
||||||
|
loadDataList();
|
||||||
|
} catch (e) {
|
||||||
|
message.toast(e.message || '保存失败')
|
||||||
|
} finally {
|
||||||
|
saving.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除用户
|
||||||
|
* @param id 要删除的用户id
|
||||||
|
*/
|
||||||
|
async function removeData(id: number) {
|
||||||
|
if (!confirm('是否删除?')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await http.delete(`/admin/goods/${id}`);
|
||||||
|
message.toast('删除成功');
|
||||||
|
loadDataList();
|
||||||
|
} catch (e) {
|
||||||
|
message.toast(e.message || '删除失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(loadDataList)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.search-form span {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -6,14 +6,17 @@
|
|||||||
<span>
|
<span>
|
||||||
{{ userStore.userinfo?.account }}
|
{{ userStore.userinfo?.account }}
|
||||||
</span>
|
</span>
|
||||||
|
<span @click="logout">退出</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="left-menu">
|
<div class="left-menu">
|
||||||
<div class="title">积分管理系统</div>
|
<div class="title">积分管理系统</div>
|
||||||
<div class="menu-list">
|
<div class="menu-list">
|
||||||
<router-link active-class="active-menu" to="/home">HOME</router-link>
|
<router-link v-for="r in AdminRoutes" active-class="active-menu" :to="'/' + r.path">{{
|
||||||
<router-link active-class="active-menu" to="/user">用户管理</router-link>
|
r.meta.title
|
||||||
|
}}
|
||||||
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
@ -27,18 +30,26 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import {useUserStore} from "../../service/store";
|
import {useUserStore} from "../../service/store";
|
||||||
|
import {useRouter} from "vue-router";
|
||||||
|
import {AdminRoutes} from './../../router/routes'
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
userStore.logout()
|
||||||
|
router.replace('/login')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
|
||||||
.app-admin-layout {
|
.app-admin-layout {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
background-color: var(--primary-color);
|
background-color: var(--header-bg);
|
||||||
color: white;
|
color: white;
|
||||||
line-height: var(--header-height);
|
line-height: var(--header-height);
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
@ -48,6 +59,7 @@ const userStore = useUserStore();
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
z-index: 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
@ -56,34 +68,42 @@ const userStore = useUserStore();
|
|||||||
|
|
||||||
.left-menu {
|
.left-menu {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
background-color: black;
|
background-color: #fff;
|
||||||
color: white;
|
color:#333;
|
||||||
|
box-shadow: 0 2px 3px rgba(0,0,0,0.4);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
z-index: 10;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
.title{
|
|
||||||
|
.title {
|
||||||
height: var(--header-height);
|
height: var(--header-height);
|
||||||
background-color: #333;
|
background-color: var(--header-bg);
|
||||||
line-height: var(--header-height);
|
line-height: var(--header-height);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
color:white;
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
}
|
}
|
||||||
.menu-list{
|
|
||||||
|
.menu-list {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
a{
|
|
||||||
|
a {
|
||||||
display: block;
|
display: block;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color:white;
|
padding: 10px 20px;
|
||||||
padding:10px 20px;
|
color:#333;
|
||||||
&.active-menu{
|
|
||||||
background-color: #666666;
|
&.active-menu {
|
||||||
color: white;
|
background-color: var(--primary-1);
|
||||||
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-wrapper {
|
.content-wrapper {
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
|
@ -1,35 +1,38 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<table>
|
<div class="table-wrapper">
|
||||||
<tr>
|
<table>
|
||||||
<th>UID</th>
|
<tr>
|
||||||
<th>昵称</th>
|
<th>UID</th>
|
||||||
<th>OPEN_ID</th>
|
<th>昵称</th>
|
||||||
<th>性别</th>
|
<th>OPEN_ID</th>
|
||||||
<th>地区</th>
|
<th>性别</th>
|
||||||
<th>推荐者</th>
|
<th>地区</th>
|
||||||
<th>状态</th>
|
<th>推荐者</th>
|
||||||
<th>积分</th>
|
<th>状态</th>
|
||||||
<th>注册时间</th>
|
<th>积分</th>
|
||||||
<th>操作</th>
|
<th>注册时间</th>
|
||||||
</tr>
|
<th>操作</th>
|
||||||
<tr v-for="u in userList" :key="u.id">
|
</tr>
|
||||||
<td>{{ u.id }}</td>
|
<tr v-for="u in userList" :key="u.id">
|
||||||
<td>{{ u.nickname }}</td>
|
<td>{{ u.id }}</td>
|
||||||
<td>{{ u.openId }}</td>
|
<td>{{ u.nickname }}</td>
|
||||||
<td>{{ GenderEnum[u.gender] || '未知' }}</td>
|
<td>{{ u.openId }}</td>
|
||||||
<td>{{ u.province + '-' + u.city }}</td>
|
<td>{{ GenderEnum[u.gender] || '未知' }}</td>
|
||||||
<td>{{ u.parent?.nickname || '-' }}</td>
|
<td>{{ u.province + '-' + u.city }}</td>
|
||||||
<td>{{ StatusEnum[u.status] || '未知' }}</td>
|
<td>{{ u.parent?.nickname || '-' }}</td>
|
||||||
<td>{{ u.pointInfo?.totalPoint }}</td>
|
<td>{{ StatusEnum[u.status] || '未知' }}</td>
|
||||||
<td>{{ u.firstLoginTime }}</td>
|
<td>{{ u.pointInfo?.totalPoint }}</td>
|
||||||
<td>
|
<td>{{ u.firstLoginTime }}</td>
|
||||||
<span @click="editUser(u)">编辑</span>
|
<td>
|
||||||
<span>禁用</span>
|
<span @click="editUser(u)">编辑</span>
|
||||||
<span @click="removeUser(u.id)">删除</span>
|
<span>禁用</span>
|
||||||
</td>
|
<span @click="removeUser(u.id)">删除</span>
|
||||||
</tr>
|
</td>
|
||||||
</table>
|
</tr>
|
||||||
|
</table>
|
||||||
|
<Pager :total="userTotalCount" show-refresh @refresh="loadUserList" @page-change="onPageChange"/>
|
||||||
|
</div>
|
||||||
<Modal v-model="modalVisible">
|
<Modal v-model="modalVisible">
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
@ -60,6 +63,7 @@ import {onMounted, reactive, ref} from "vue";
|
|||||||
import http, {DataListModel} from "../../util/http";
|
import http, {DataListModel} from "../../util/http";
|
||||||
import message from "../../components/message";
|
import message from "../../components/message";
|
||||||
import Modal from "../../components/modal/modal.vue";
|
import Modal from "../../components/modal/modal.vue";
|
||||||
|
import Pager from "../../components/pager/Pager.vue";
|
||||||
//
|
//
|
||||||
const GenderEnum = {
|
const GenderEnum = {
|
||||||
1: '男', 2: '女'
|
1: '男', 2: '女'
|
||||||
@ -88,6 +92,11 @@ const editUserData = reactive({
|
|||||||
});
|
});
|
||||||
const userTotalCount = ref(0)
|
const userTotalCount = ref(0)
|
||||||
|
|
||||||
|
function onPageChange(currentPage: number) {
|
||||||
|
param.page = currentPage;
|
||||||
|
loadUserList();
|
||||||
|
}
|
||||||
|
|
||||||
function loadUserList() {
|
function loadUserList() {
|
||||||
http.post<DataListModel<UserInfoModel>>('/admin/user/list', param).then(res => {
|
http.post<DataListModel<UserInfoModel>>('/admin/user/list', param).then(res => {
|
||||||
userList.value = res.items
|
userList.value = res.items
|
||||||
|
@ -12,6 +12,15 @@
|
|||||||
"**/*.js"
|
"**/*.js"
|
||||||
],
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"jsx": "preserve"
|
"jsx": "preserve",
|
||||||
|
"types": [
|
||||||
|
"unplugin-vue-define-options/macros-global"
|
||||||
|
],
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"es5",
|
||||||
|
"scripthost",
|
||||||
|
"es2015.collection"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,14 +1,17 @@
|
|||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
import vueJsxPlugin from "@vitejs/plugin-vue-jsx";
|
import vueJsxPlugin from "@vitejs/plugin-vue-jsx";
|
||||||
|
import DefineOptions from 'unplugin-vue-define-options/vite'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
hmr: true,
|
||||||
// 开发服务信息
|
// 开发服务信息
|
||||||
server: {
|
server: {
|
||||||
host:'::'
|
host: '::'
|
||||||
},
|
},
|
||||||
// 必须配置vue插件
|
// 必须配置vue插件
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
|
DefineOptions(),
|
||||||
vueJsxPlugin(), // 如果需要使用jsx或者tsx
|
vueJsxPlugin(), // 如果需要使用jsx或者tsx
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -200,7 +200,7 @@
|
|||||||
chalk "^2.0.0"
|
chalk "^2.0.0"
|
||||||
js-tokens "^4.0.0"
|
js-tokens "^4.0.0"
|
||||||
|
|
||||||
"@babel/parser@^7.16.4", "@babel/parser@^7.18.10", "@babel/parser@^7.20.5":
|
"@babel/parser@^7.16.4", "@babel/parser@^7.18.10", "@babel/parser@^7.20.0", "@babel/parser@^7.20.5":
|
||||||
version "7.20.5"
|
version "7.20.5"
|
||||||
resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.20.5.tgz#7f3c7335fe417665d929f34ae5dceae4c04015e8"
|
resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.20.5.tgz#7f3c7335fe417665d929f34ae5dceae4c04015e8"
|
||||||
integrity sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==
|
integrity sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==
|
||||||
@ -253,7 +253,7 @@
|
|||||||
debug "^4.1.0"
|
debug "^4.1.0"
|
||||||
globals "^11.1.0"
|
globals "^11.1.0"
|
||||||
|
|
||||||
"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5":
|
"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5":
|
||||||
version "7.20.5"
|
version "7.20.5"
|
||||||
resolved "https://registry.npmmirror.com/@babel/types/-/types-7.20.5.tgz#e206ae370b5393d94dfd1d04cd687cace53efa84"
|
resolved "https://registry.npmmirror.com/@babel/types/-/types-7.20.5.tgz#e206ae370b5393d94dfd1d04cd687cace53efa84"
|
||||||
integrity sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==
|
integrity sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==
|
||||||
@ -312,6 +312,14 @@
|
|||||||
"@jridgewell/resolve-uri" "3.1.0"
|
"@jridgewell/resolve-uri" "3.1.0"
|
||||||
"@jridgewell/sourcemap-codec" "1.4.14"
|
"@jridgewell/sourcemap-codec" "1.4.14"
|
||||||
|
|
||||||
|
"@rollup/pluginutils@^4.2.1":
|
||||||
|
version "4.2.1"
|
||||||
|
resolved "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
|
||||||
|
integrity sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==
|
||||||
|
dependencies:
|
||||||
|
estree-walker "^2.0.1"
|
||||||
|
picomatch "^2.2.2"
|
||||||
|
|
||||||
"@types/node@^18.11.10":
|
"@types/node@^18.11.10":
|
||||||
version "18.11.10"
|
version "18.11.10"
|
||||||
resolved "https://registry.npmmirror.com/@types/node/-/node-18.11.10.tgz#4c64759f3c2343b7e6c4b9caf761c7a3a05cee34"
|
resolved "https://registry.npmmirror.com/@types/node/-/node-18.11.10.tgz#4c64759f3c2343b7e6c4b9caf761c7a3a05cee34"
|
||||||
@ -376,6 +384,15 @@
|
|||||||
"@volar/typescript" "1.0.11"
|
"@volar/typescript" "1.0.11"
|
||||||
"@volar/vue-language-core" "1.0.11"
|
"@volar/vue-language-core" "1.0.11"
|
||||||
|
|
||||||
|
"@vue-macros/common@~0.13.4":
|
||||||
|
version "0.13.4"
|
||||||
|
resolved "https://registry.npmmirror.com/@vue-macros/common/-/common-0.13.4.tgz#f1a12c63aad18ad0020101bf386f5e9c95d444ba"
|
||||||
|
integrity sha512-mQooO33XcY4kQyKBrbGfdIPPsYhpcfmH75SQnXx2vNsNLSNvhLuDaIIV0fhMJ0HV5Z02V9Ka1gx7v1g5bk9Q0A==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.20.2"
|
||||||
|
"@vue/compiler-sfc" "^3.2.45"
|
||||||
|
magic-string "^0.26.7"
|
||||||
|
|
||||||
"@vue/babel-helper-vue-transform-on@^1.0.2":
|
"@vue/babel-helper-vue-transform-on@^1.0.2":
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.npmmirror.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.0.2.tgz#9b9c691cd06fc855221a2475c3cc831d774bc7dc"
|
resolved "https://registry.npmmirror.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.0.2.tgz#9b9c691cd06fc855221a2475c3cc831d774bc7dc"
|
||||||
@ -491,6 +508,11 @@
|
|||||||
resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.2.45.tgz#a3fffa7489eafff38d984e23d0236e230c818bc2"
|
resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.2.45.tgz#a3fffa7489eafff38d984e23d0236e230c818bc2"
|
||||||
integrity sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==
|
integrity sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==
|
||||||
|
|
||||||
|
acorn@^8.8.1:
|
||||||
|
version "8.8.1"
|
||||||
|
resolved "https://registry.npmmirror.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73"
|
||||||
|
integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==
|
||||||
|
|
||||||
ansi-styles@^3.2.1:
|
ansi-styles@^3.2.1:
|
||||||
version "3.2.1"
|
version "3.2.1"
|
||||||
resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
|
resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
|
||||||
@ -498,11 +520,32 @@ ansi-styles@^3.2.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
color-convert "^1.9.0"
|
color-convert "^1.9.0"
|
||||||
|
|
||||||
|
anymatch@~3.1.2:
|
||||||
|
version "3.1.3"
|
||||||
|
resolved "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
|
||||||
|
integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
|
||||||
|
dependencies:
|
||||||
|
normalize-path "^3.0.0"
|
||||||
|
picomatch "^2.0.4"
|
||||||
|
|
||||||
|
ast-walker-scope@^0.3.0:
|
||||||
|
version "0.3.0"
|
||||||
|
resolved "https://registry.npmmirror.com/ast-walker-scope/-/ast-walker-scope-0.3.0.tgz#955b00af19946e76d39ba86d3046b9bc2b7312d9"
|
||||||
|
integrity sha512-bsOBv3jB+1kGaxwPHhkLiagS+75KfzEqtkNWvATgMGtXM6kJZG3PlG4fYQFMiHeLpoAkwc6G61w07+hEXx39aA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/parser" "^7.20.0"
|
||||||
|
"@babel/types" "^7.20.0"
|
||||||
|
|
||||||
balanced-match@^1.0.0:
|
balanced-match@^1.0.0:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||||
|
|
||||||
|
binary-extensions@^2.0.0:
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
|
||||||
|
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
|
||||||
|
|
||||||
brace-expansion@^2.0.1:
|
brace-expansion@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
|
resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
|
||||||
@ -510,6 +553,13 @@ brace-expansion@^2.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
balanced-match "^1.0.0"
|
balanced-match "^1.0.0"
|
||||||
|
|
||||||
|
braces@~3.0.2:
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
|
||||||
|
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
|
||||||
|
dependencies:
|
||||||
|
fill-range "^7.0.1"
|
||||||
|
|
||||||
browserslist@^4.21.3:
|
browserslist@^4.21.3:
|
||||||
version "4.21.4"
|
version "4.21.4"
|
||||||
resolved "https://registry.npmmirror.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987"
|
resolved "https://registry.npmmirror.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987"
|
||||||
@ -539,6 +589,21 @@ chalk@^2.0.0:
|
|||||||
escape-string-regexp "^1.0.5"
|
escape-string-regexp "^1.0.5"
|
||||||
supports-color "^5.3.0"
|
supports-color "^5.3.0"
|
||||||
|
|
||||||
|
chokidar@^3.5.3:
|
||||||
|
version "3.5.3"
|
||||||
|
resolved "https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
|
||||||
|
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
|
||||||
|
dependencies:
|
||||||
|
anymatch "~3.1.2"
|
||||||
|
braces "~3.0.2"
|
||||||
|
glob-parent "~5.1.2"
|
||||||
|
is-binary-path "~2.1.0"
|
||||||
|
is-glob "~4.0.1"
|
||||||
|
normalize-path "~3.0.0"
|
||||||
|
readdirp "~3.6.0"
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
color-convert@^1.9.0:
|
color-convert@^1.9.0:
|
||||||
version "1.9.3"
|
version "1.9.3"
|
||||||
resolved "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
|
resolved "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
|
||||||
@ -742,11 +807,18 @@ escape-string-regexp@^1.0.5:
|
|||||||
resolved "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
resolved "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||||
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
|
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
|
||||||
|
|
||||||
estree-walker@^2.0.2:
|
estree-walker@^2.0.1, estree-walker@^2.0.2:
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
resolved "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
|
resolved "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
|
||||||
integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
|
integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
|
||||||
|
|
||||||
|
fill-range@^7.0.1:
|
||||||
|
version "7.0.1"
|
||||||
|
resolved "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
|
||||||
|
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
|
||||||
|
dependencies:
|
||||||
|
to-regex-range "^5.0.1"
|
||||||
|
|
||||||
fsevents@~2.3.2:
|
fsevents@~2.3.2:
|
||||||
version "2.3.2"
|
version "2.3.2"
|
||||||
resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
||||||
@ -762,6 +834,13 @@ gensync@^1.0.0-beta.2:
|
|||||||
resolved "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
resolved "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
||||||
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
|
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
|
||||||
|
|
||||||
|
glob-parent@~5.1.2:
|
||||||
|
version "5.1.2"
|
||||||
|
resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
|
||||||
|
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
|
||||||
|
dependencies:
|
||||||
|
is-glob "^4.0.1"
|
||||||
|
|
||||||
globals@^11.1.0:
|
globals@^11.1.0:
|
||||||
version "11.12.0"
|
version "11.12.0"
|
||||||
resolved "https://registry.npmmirror.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
|
resolved "https://registry.npmmirror.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
|
||||||
@ -806,6 +885,13 @@ image-size@~0.5.0:
|
|||||||
resolved "https://registry.npmmirror.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
|
resolved "https://registry.npmmirror.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
|
||||||
integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==
|
integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==
|
||||||
|
|
||||||
|
is-binary-path@~2.1.0:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
|
||||||
|
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
|
||||||
|
dependencies:
|
||||||
|
binary-extensions "^2.0.0"
|
||||||
|
|
||||||
is-core-module@^2.9.0:
|
is-core-module@^2.9.0:
|
||||||
version "2.11.0"
|
version "2.11.0"
|
||||||
resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144"
|
resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144"
|
||||||
@ -813,6 +899,23 @@ is-core-module@^2.9.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
has "^1.0.3"
|
has "^1.0.3"
|
||||||
|
|
||||||
|
is-extglob@^2.1.1:
|
||||||
|
version "2.1.1"
|
||||||
|
resolved "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||||
|
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
|
||||||
|
|
||||||
|
is-glob@^4.0.1, is-glob@~4.0.1:
|
||||||
|
version "4.0.3"
|
||||||
|
resolved "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
|
||||||
|
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
|
||||||
|
dependencies:
|
||||||
|
is-extglob "^2.1.1"
|
||||||
|
|
||||||
|
is-number@^7.0.0:
|
||||||
|
version "7.0.0"
|
||||||
|
resolved "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
|
||||||
|
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
||||||
|
|
||||||
is-what@^3.14.1:
|
is-what@^3.14.1:
|
||||||
version "3.14.1"
|
version "3.14.1"
|
||||||
resolved "https://registry.npmmirror.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1"
|
resolved "https://registry.npmmirror.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1"
|
||||||
@ -857,6 +960,13 @@ magic-string@^0.25.7:
|
|||||||
dependencies:
|
dependencies:
|
||||||
sourcemap-codec "^1.4.8"
|
sourcemap-codec "^1.4.8"
|
||||||
|
|
||||||
|
magic-string@^0.26.7:
|
||||||
|
version "0.26.7"
|
||||||
|
resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.26.7.tgz#caf7daf61b34e9982f8228c4527474dac8981d6f"
|
||||||
|
integrity sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==
|
||||||
|
dependencies:
|
||||||
|
sourcemap-codec "^1.4.8"
|
||||||
|
|
||||||
make-dir@^2.1.0:
|
make-dir@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.npmmirror.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
|
resolved "https://registry.npmmirror.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
|
||||||
@ -911,6 +1021,11 @@ node-releases@^2.0.6:
|
|||||||
resolved "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
|
resolved "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
|
||||||
integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
|
integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
|
||||||
|
|
||||||
|
normalize-path@^3.0.0, normalize-path@~3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||||
|
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
|
||||||
|
|
||||||
parse-node-version@^1.0.1:
|
parse-node-version@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.npmmirror.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b"
|
resolved "https://registry.npmmirror.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b"
|
||||||
@ -926,6 +1041,11 @@ picocolors@^1.0.0:
|
|||||||
resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
|
||||||
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
|
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
|
||||||
|
|
||||||
|
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2:
|
||||||
|
version "2.3.1"
|
||||||
|
resolved "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
|
||||||
|
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||||
|
|
||||||
pify@^4.0.1:
|
pify@^4.0.1:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.npmmirror.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
|
resolved "https://registry.npmmirror.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
|
||||||
@ -953,6 +1073,13 @@ prr@~1.0.1:
|
|||||||
resolved "https://registry.npmmirror.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
|
resolved "https://registry.npmmirror.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
|
||||||
integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==
|
integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==
|
||||||
|
|
||||||
|
readdirp@~3.6.0:
|
||||||
|
version "3.6.0"
|
||||||
|
resolved "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
|
||||||
|
integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
|
||||||
|
dependencies:
|
||||||
|
picomatch "^2.2.1"
|
||||||
|
|
||||||
resolve@^1.22.1:
|
resolve@^1.22.1:
|
||||||
version "1.22.1"
|
version "1.22.1"
|
||||||
resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
|
resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
|
||||||
@ -1026,6 +1153,13 @@ to-fast-properties@^2.0.0:
|
|||||||
resolved "https://registry.npmmirror.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
resolved "https://registry.npmmirror.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
||||||
integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
|
integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
|
||||||
|
|
||||||
|
to-regex-range@^5.0.1:
|
||||||
|
version "5.0.1"
|
||||||
|
resolved "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
|
||||||
|
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
|
||||||
|
dependencies:
|
||||||
|
is-number "^7.0.0"
|
||||||
|
|
||||||
tslib@^2.3.0:
|
tslib@^2.3.0:
|
||||||
version "2.4.1"
|
version "2.4.1"
|
||||||
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e"
|
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e"
|
||||||
@ -1036,6 +1170,26 @@ typescript@^4.9.3:
|
|||||||
resolved "https://registry.npmmirror.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db"
|
resolved "https://registry.npmmirror.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db"
|
||||||
integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==
|
integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==
|
||||||
|
|
||||||
|
unplugin-vue-define-options@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.npmmirror.com/unplugin-vue-define-options/-/unplugin-vue-define-options-1.0.0.tgz#0aabe28748d5b445e68b6d44bc1170e3d01622a9"
|
||||||
|
integrity sha512-j90zM7NhZXBL5uMlHKzSOjvU98lFcIErdgAhj7bEEdvZarkwOkEUgMFsZDwStN9FEcMAiS/BTvcyGfItu3ry/g==
|
||||||
|
dependencies:
|
||||||
|
"@rollup/pluginutils" "^4.2.1"
|
||||||
|
"@vue-macros/common" "~0.13.4"
|
||||||
|
ast-walker-scope "^0.3.0"
|
||||||
|
unplugin "^1.0.0"
|
||||||
|
|
||||||
|
unplugin@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.npmmirror.com/unplugin/-/unplugin-1.0.0.tgz#8d12e0d116bf56313d42755094fc370e9c18da86"
|
||||||
|
integrity sha512-H5UnBUxfhTXBXGo2AwKsl0UaLSHzSNDZNehPQSgdhVfO/t+XAS1Yoj3vmLrrlBrS9ZwtH5tejbX/TCp5DcyCKg==
|
||||||
|
dependencies:
|
||||||
|
acorn "^8.8.1"
|
||||||
|
chokidar "^3.5.3"
|
||||||
|
webpack-sources "^3.2.3"
|
||||||
|
webpack-virtual-modules "^0.4.6"
|
||||||
|
|
||||||
update-browserslist-db@^1.0.9:
|
update-browserslist-db@^1.0.9:
|
||||||
version "1.0.10"
|
version "1.0.10"
|
||||||
resolved "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3"
|
resolved "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3"
|
||||||
@ -1094,3 +1248,13 @@ vue@^3.2.45:
|
|||||||
"@vue/runtime-dom" "3.2.45"
|
"@vue/runtime-dom" "3.2.45"
|
||||||
"@vue/server-renderer" "3.2.45"
|
"@vue/server-renderer" "3.2.45"
|
||||||
"@vue/shared" "3.2.45"
|
"@vue/shared" "3.2.45"
|
||||||
|
|
||||||
|
webpack-sources@^3.2.3:
|
||||||
|
version "3.2.3"
|
||||||
|
resolved "https://registry.npmmirror.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
|
||||||
|
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
|
||||||
|
|
||||||
|
webpack-virtual-modules@^0.4.6:
|
||||||
|
version "0.4.6"
|
||||||
|
resolved "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.4.6.tgz#3e4008230731f1db078d9cb6f68baf8571182b45"
|
||||||
|
integrity sha512-5tyDlKLqPfMqjT3Q9TAqf2YqjwmnUleZwzJi1A5qXnlBCdj2AtOJ6wAWdglTIDOPgOiOrXeBeFcsQ8+aGQ6QbA==
|
||||||
|
@ -11,7 +11,9 @@ public class ApplicationConfig implements WebMvcConfigurer {
|
|||||||
// 跨域 目前小程序不需要,暂时不用考虑
|
// 跨域 目前小程序不需要,暂时不用考虑
|
||||||
@Override
|
@Override
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
registry.addMapping("/**").allowedOrigins("*");
|
registry.addMapping("/**")
|
||||||
|
.allowedOrigins("*")
|
||||||
|
.allowedMethods("GET", "POST", "PUT", "DELETE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
package me.xiaoyan.point.api.controller;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import me.xiaoyan.point.api.pojo.dto.FileUploadResult;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("file")
|
||||||
|
public class FileController {
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
@PostMapping("upload")
|
||||||
|
public FileUploadResult upload(MultipartFile multipartFile) {
|
||||||
|
Thread.sleep(1);
|
||||||
|
String url = "https://m.360buyimg.com/mobilecms/s750x750_jfs/t1/211852/28/15135/312413/6235a37fEc6496443/de07faa29ece45ee.jpg";
|
||||||
|
return new FileUploadResult(url, "");
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,21 @@
|
|||||||
package me.xiaoyan.point.api.controller;
|
package me.xiaoyan.point.api.controller;
|
||||||
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import me.xiaoyan.point.api.error.BizException;
|
import me.xiaoyan.point.api.error.BizException;
|
||||||
import me.xiaoyan.point.api.pojo.OrderInfo;
|
import me.xiaoyan.point.api.pojo.OrderInfo;
|
||||||
|
import me.xiaoyan.point.api.pojo.UserInfo;
|
||||||
import me.xiaoyan.point.api.pojo.vo.CreateOrderData;
|
import me.xiaoyan.point.api.pojo.vo.CreateOrderData;
|
||||||
|
import me.xiaoyan.point.api.pojo.vo.OrderQueryParam;
|
||||||
|
import me.xiaoyan.point.api.pojo.vo.PageDataResult;
|
||||||
import me.xiaoyan.point.api.service.GoodsService;
|
import me.xiaoyan.point.api.service.GoodsService;
|
||||||
import me.xiaoyan.point.api.service.OrderInfoService;
|
import me.xiaoyan.point.api.service.OrderInfoService;
|
||||||
|
import me.xiaoyan.point.api.util.OrderStatus;
|
||||||
|
import me.xiaoyan.point.api.util.QueryWrapperUtil;
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
@ -47,9 +55,9 @@ public class ShopOrderInfoController {
|
|||||||
//TODO 应该定时更新缓存数据
|
//TODO 应该定时更新缓存数据
|
||||||
goodsService.queryAllGoodsIdAndStock().forEach(g -> {
|
goodsService.queryAllGoodsIdAndStock().forEach(g -> {
|
||||||
log.info("缓存 id:{} stock:{} ", g.getId(), g.getStock());
|
log.info("缓存 id:{} stock:{} ", g.getId(), g.getStock());
|
||||||
if(g.getStock() == 0){
|
if (g.getStock() == 0) {
|
||||||
// 原本就没有库存
|
// 原本就没有库存
|
||||||
stockOutMap.put(g.getId(),true);
|
stockOutMap.put(g.getId(), true);
|
||||||
}
|
}
|
||||||
// 缓存库存
|
// 缓存库存
|
||||||
stringRedisTemplate.opsForValue().set(cacheKey(g.getId()), g.getStock().toString());
|
stringRedisTemplate.opsForValue().set(cacheKey(g.getId()), g.getStock().toString());
|
||||||
@ -64,7 +72,7 @@ public class ShopOrderInfoController {
|
|||||||
int uid = StpUtil.getLoginIdAsInt();
|
int uid = StpUtil.getLoginIdAsInt();
|
||||||
// 如果限制用户只能购买的数量,可以添加一个map记录用户的请求数
|
// 如果限制用户只能购买的数量,可以添加一个map记录用户的请求数
|
||||||
int size = stockOutMap.size();
|
int size = stockOutMap.size();
|
||||||
Long buyId = (long)data.getGoodsId();
|
Long buyId = (long) data.getGoodsId();
|
||||||
//1.内存判断
|
//1.内存判断
|
||||||
if (size > 0 && stockOutMap.containsKey(buyId) && stockOutMap.get(buyId)) {
|
if (size > 0 && stockOutMap.containsKey(buyId) && stockOutMap.get(buyId)) {
|
||||||
throw BizException.create("库存不足");
|
throw BizException.create("库存不足");
|
||||||
@ -74,22 +82,59 @@ public class ShopOrderInfoController {
|
|||||||
if (count < 0) {
|
if (count < 0) {
|
||||||
log.info("stock count ===>" + count);
|
log.info("stock count ===>" + count);
|
||||||
// 对缓存进行库存 还原
|
// 对缓存进行库存 还原
|
||||||
stringRedisTemplate.opsForValue().increment(cacheKey(buyId),data.getBuyCount()); //
|
stringRedisTemplate.opsForValue().increment(cacheKey(buyId), data.getBuyCount()); //
|
||||||
throw BizException.create("库存不足");
|
throw BizException.create("库存不足");
|
||||||
}
|
}
|
||||||
if(count == 0){
|
if (count == 0) {
|
||||||
// 此时库存没有了 , 保存到已买完的对象
|
// 此时库存没有了 , 保存到已买完的对象
|
||||||
stockOutMap.put(buyId,true);
|
stockOutMap.put(buyId, true);
|
||||||
}
|
}
|
||||||
//3.数据库
|
//3.数据库
|
||||||
try{
|
try {
|
||||||
return orderInfoService.create(uid, data);
|
return orderInfoService.create(uid, data);
|
||||||
}catch (BizException e){
|
} catch (BizException e) {
|
||||||
//下单失败 对缓存进行库存 还原
|
//下单失败 对缓存进行库存 还原
|
||||||
stringRedisTemplate.opsForValue().increment(cacheKey(data.getGoodsId()),data.getBuyCount()); //
|
stringRedisTemplate.opsForValue().increment(cacheKey(data.getGoodsId()), data.getBuyCount()); //
|
||||||
stockOutMap.put((long)data.getGoodsId(),false);
|
stockOutMap.put((long) data.getGoodsId(), false);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 只能查询自己关联的订单信息
|
||||||
|
@PostMapping("/query")
|
||||||
|
public Page<OrderInfo> query(@RequestBody OrderQueryParam param) {
|
||||||
|
param.setUid(StpUtil.getLoginIdAsInt());
|
||||||
|
return orderInfoService.queryByPage(param, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public OrderInfo get(@PathVariable("id") String id) {
|
||||||
|
return orderInfoService.getOneByIdAndUid(id, StpUtil.getLoginIdAsInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean updateStatus(String id, int status) {
|
||||||
|
if (!StringUtils.hasText(id)) throw BizException.paramError();
|
||||||
|
QueryWrapper<OrderInfo> q = QueryWrapperUtil.builder()
|
||||||
|
.eq("id", id)
|
||||||
|
.eq("uid", StpUtil.getLoginIdAsInt())
|
||||||
|
.build();
|
||||||
|
return orderInfoService.update(
|
||||||
|
OrderInfo.builder()
|
||||||
|
.status(status)
|
||||||
|
.build(),
|
||||||
|
q
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}/cancel")
|
||||||
|
public boolean cancelOrder(@PathVariable("id") String id) {
|
||||||
|
return updateStatus(id, OrderStatus.CANCELED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}/delete")
|
||||||
|
public boolean deleteOrder(@PathVariable("id") String id) {
|
||||||
|
return updateStatus(id, OrderStatus.DELETE);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
package me.xiaoyan.point.api.controller.admin;
|
package me.xiaoyan.point.api.controller.admin;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import me.xiaoyan.point.api.error.BizException;
|
||||||
|
import me.xiaoyan.point.api.pojo.Goods;
|
||||||
import me.xiaoyan.point.api.pojo.vo.GoodsQueryParam;
|
import me.xiaoyan.point.api.pojo.vo.GoodsQueryParam;
|
||||||
import me.xiaoyan.point.api.pojo.vo.PageDataResult;
|
import me.xiaoyan.point.api.pojo.vo.PageDataResult;
|
||||||
import me.xiaoyan.point.api.pojo.vo.PageParam;
|
import me.xiaoyan.point.api.pojo.vo.PageParam;
|
||||||
import me.xiaoyan.point.api.service.GoodsService;
|
import me.xiaoyan.point.api.service.GoodsService;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import me.xiaoyan.point.api.util.DataStatus;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.apache.ibatis.annotations.Delete;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
@ -22,4 +23,43 @@ public class GoodsAdminController {
|
|||||||
public PageDataResult list(@RequestBody GoodsQueryParam param) {
|
public PageDataResult list(@RequestBody GoodsQueryParam param) {
|
||||||
return PageDataResult.convert(goodsService.queryByPage(param));
|
return PageDataResult.convert(goodsService.queryByPage(param));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增
|
||||||
|
@PostMapping
|
||||||
|
public Goods create(@RequestBody Goods goods) {
|
||||||
|
if (!goodsService.save(goods)) {
|
||||||
|
throw BizException.saveFail();
|
||||||
|
}
|
||||||
|
return goods;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改
|
||||||
|
@PutMapping("/{id}")
|
||||||
|
public Goods update(@RequestBody Goods goods, @PathVariable("id") long id) {
|
||||||
|
goods.setId(id);
|
||||||
|
if (!goodsService.updateById(goods)) {
|
||||||
|
throw BizException.saveFail();
|
||||||
|
}
|
||||||
|
return goods;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public Goods get(@PathVariable("id") long id) {
|
||||||
|
return goodsService.getById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public boolean remove(@PathVariable("id") long id) {
|
||||||
|
if (id < 1) throw BizException.paramError();
|
||||||
|
// 只是逻辑删除 -> 将状态更新未删除即可
|
||||||
|
|
||||||
|
return goodsService.updateById(
|
||||||
|
Goods.builder()
|
||||||
|
.id(id)
|
||||||
|
.status(DataStatus.DELETE) // 状态设置为删除
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,66 @@
|
|||||||
|
package me.xiaoyan.point.api.controller.admin;
|
||||||
|
|
||||||
|
import me.xiaoyan.point.api.error.BizException;
|
||||||
|
import me.xiaoyan.point.api.pojo.OrderInfo;
|
||||||
|
import me.xiaoyan.point.api.pojo.vo.OrderQueryParam;
|
||||||
|
import me.xiaoyan.point.api.pojo.vo.PageDataResult;
|
||||||
|
import me.xiaoyan.point.api.service.OrderInfoService;
|
||||||
|
import me.xiaoyan.point.api.util.DataStatus;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/admin/order")
|
||||||
|
public class OrderAdminController {
|
||||||
|
@Resource
|
||||||
|
private OrderInfoService orderInfoService;
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/list")
|
||||||
|
public PageDataResult list(@RequestBody OrderQueryParam param) {
|
||||||
|
return PageDataResult.convert(orderInfoService.queryByPage(param,false,true));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改
|
||||||
|
@PutMapping("/{id}")
|
||||||
|
public OrderInfo update(@RequestBody OrderInfo info, @PathVariable("id") String id) {
|
||||||
|
info.setId(id);
|
||||||
|
if (!orderInfoService.updateById(info)) {
|
||||||
|
throw BizException.saveFail();
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public OrderInfo get(@PathVariable("id") String id) {
|
||||||
|
return orderInfoService.getById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public boolean remove(@PathVariable("id") String id) {
|
||||||
|
if (!StringUtils.hasText(id)) throw BizException.paramError();
|
||||||
|
// 只是逻辑删除 -> 将状态更新未删除即可
|
||||||
|
|
||||||
|
return orderInfoService.updateById(
|
||||||
|
OrderInfo.builder()
|
||||||
|
.id(id)
|
||||||
|
.status(DataStatus.DELETE) // 状态设置为删除
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}/status")
|
||||||
|
public boolean setStatus(@PathVariable("id") String id, int status) {
|
||||||
|
if (!StringUtils.hasText(id)) throw BizException.paramError();
|
||||||
|
return orderInfoService.updateById(
|
||||||
|
OrderInfo.builder()
|
||||||
|
.id(id)
|
||||||
|
.status(status)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -40,6 +40,12 @@ public class UserAdminController {
|
|||||||
userStoreMap.put("test", UserAdminInfo.create(2, "test", "123123"));
|
userStoreMap.put("test", UserAdminInfo.create(2, "test", "123123"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public UserInfo update(@RequestBody UserInfo userInfo) {
|
||||||
|
if (!userInfoService.updateById(userInfo)) throw BizException.saveFail();
|
||||||
|
return userInfo;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户登录
|
* 用户登录
|
||||||
* @status released
|
* @status released
|
||||||
@ -50,7 +56,7 @@ public class UserAdminController {
|
|||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@PostMapping("login")
|
@PostMapping("login")
|
||||||
public UserAdminInfo login(@Validated @RequestBody UserAdminInfo user) {
|
public UserAdminInfo login(@Validated @RequestBody UserAdminInfo user) {
|
||||||
Thread.sleep(1);
|
Thread.sleep(2000);
|
||||||
// 判断是否存在账号
|
// 判断是否存在账号
|
||||||
if (!userStoreMap.containsKey(user.getAccount())) {
|
if (!userStoreMap.containsKey(user.getAccount())) {
|
||||||
throw BizException.create("账号不存在");
|
throw BizException.create("账号不存在");
|
||||||
|
@ -17,7 +17,20 @@ public class BizException extends RuntimeException {
|
|||||||
public static BizException create(String message) {
|
public static BizException create(String message) {
|
||||||
return new BizException(-1, message);
|
return new BizException(-1, message);
|
||||||
}
|
}
|
||||||
public static BizException create(int code,String message) {
|
|
||||||
|
public static BizException create(int code, String message) {
|
||||||
return new BizException(code, message);
|
return new BizException(code, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BizException saveFail() {
|
||||||
|
return create(1022, "保存失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BizException paramError(String message) {
|
||||||
|
return create(1201, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BizException paramError() {
|
||||||
|
return paramError("请求参数不正确");
|
||||||
|
}
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -83,21 +84,25 @@ public class Goods implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* 上架时间
|
* 上架时间
|
||||||
*/
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date onlineTime;
|
private Date onlineTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下架时间
|
* 下架时间
|
||||||
*/
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date offlineTime;
|
private Date offlineTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private Date updateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,9 +2,11 @@ package me.xiaoyan.point.api.pojo;
|
|||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -24,13 +26,14 @@ import java.io.Serializable;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@Builder
|
@Builder
|
||||||
@TableName(value ="order_info")
|
@TableName(value = "order_info")
|
||||||
public class OrderInfo {
|
public class OrderInfo {
|
||||||
@TableId
|
@TableId
|
||||||
//订单编号
|
//订单编号
|
||||||
private String id;
|
private String id;
|
||||||
//商品编号
|
//商品编号
|
||||||
private Long gid;
|
private Long gid;
|
||||||
|
private String orderTitle;
|
||||||
//价格
|
//价格
|
||||||
private Integer price;
|
private Integer price;
|
||||||
//购买数量
|
//购买数量
|
||||||
@ -39,12 +42,17 @@ public class OrderInfo {
|
|||||||
private Integer uid;
|
private Integer uid;
|
||||||
//订单数据
|
//订单数据
|
||||||
private String data;
|
private String data;
|
||||||
|
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
|
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private Date updateTime;
|
||||||
//订单状态(0:已删除 1:已取消 2:待确认 3:已完成)
|
//订单状态(0:已删除 1:已取消 2:待确认 3:已完成)
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
@TableField(exist = false)
|
||||||
|
private UserInfo owner;
|
||||||
|
@TableField(exist = false)
|
||||||
|
private Goods goods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package me.xiaoyan.point.api.pojo;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -22,6 +23,7 @@ public class Point implements Serializable {
|
|||||||
private Integer totalPoint;
|
private Integer totalPoint;
|
||||||
private Integer validPoint;
|
private Integer validPoint;
|
||||||
private Integer expirePoint;
|
private Integer expirePoint;
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date expireTime;
|
private Date expireTime;
|
||||||
private Date updateTime;
|
private Date updateTime;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package me.xiaoyan.point.api.pojo;
|
|||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -25,6 +26,8 @@ public class PointRecord implements Serializable {
|
|||||||
private Integer point;
|
private Integer point;
|
||||||
private Integer currentTotalPoint;
|
private Integer currentTotalPoint;
|
||||||
private String reason;
|
private String reason;
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date validTime;
|
private Date validTime;
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date expireTime;
|
private Date expireTime;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package me.xiaoyan.point.api.pojo;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -22,5 +23,7 @@ public class SignRecord implements Serializable {
|
|||||||
private Integer uid;
|
private Integer uid;
|
||||||
private Integer point;
|
private Integer point;
|
||||||
private String ip;
|
private String ip;
|
||||||
|
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,14 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@ -24,6 +26,7 @@ public class UserInfo implements Serializable {
|
|||||||
* 用户id
|
* 用户id
|
||||||
*/
|
*/
|
||||||
@TableId(type = IdType.AUTO)
|
@TableId(type = IdType.AUTO)
|
||||||
|
@NotNull
|
||||||
private Integer id;
|
private Integer id;
|
||||||
/**
|
/**
|
||||||
* 微信openid
|
* 微信openid
|
||||||
@ -56,6 +59,7 @@ public class UserInfo implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* 第一次登录时间
|
* 第一次登录时间
|
||||||
*/
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date firstLoginTime;
|
private Date firstLoginTime;
|
||||||
private Date updateTime;
|
private Date updateTime;
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package me.xiaoyan.point.api.pojo.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class FileUploadResult implements Serializable {
|
||||||
|
private String url;
|
||||||
|
private String name;
|
||||||
|
}
|
@ -2,7 +2,8 @@ package me.xiaoyan.point.api.pojo.dto;
|
|||||||
|
|
||||||
public class OrderStatus {
|
public class OrderStatus {
|
||||||
public static final int DELETE = 0;
|
public static final int DELETE = 0;
|
||||||
public static final int CANCEL = 1;
|
public static final int NOT_CONFIRM = 1;
|
||||||
public static final int CONFIRM = 2;
|
public static final int CONFIRM = 2;
|
||||||
public static final int DONE = 3;
|
public static final int CANCEL = 3;
|
||||||
|
public static final int FINISH = 4;
|
||||||
}
|
}
|
||||||
|
@ -5,5 +5,5 @@ import lombok.Data;
|
|||||||
@Data
|
@Data
|
||||||
public class GoodsQueryParam extends PageParam {
|
public class GoodsQueryParam extends PageParam {
|
||||||
private String title;
|
private String title;
|
||||||
private int category;
|
private Integer category;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package me.xiaoyan.point.api.pojo.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class OrderQueryParam extends PageParam {
|
||||||
|
private String id;
|
||||||
|
private String title;
|
||||||
|
private String createTimeStart;
|
||||||
|
private String createTimeEnd;
|
||||||
|
private int uid;
|
||||||
|
private Integer status;
|
||||||
|
}
|
@ -13,10 +13,10 @@ import lombok.experimental.Accessors;
|
|||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
@Builder
|
@Builder
|
||||||
public class PageParam {
|
public class PageParam {
|
||||||
private Integer page;
|
private Integer page = 1;
|
||||||
private Integer pageSize = 20;
|
private Integer pageSize = 20;
|
||||||
|
|
||||||
public Page getPage(){
|
public Page getPage() {
|
||||||
return new Page().setCurrent(page).setSize(pageSize);
|
return new Page().setCurrent(page).setSize(pageSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,4 +25,5 @@ public interface GoodsService extends IService<Goods> {
|
|||||||
boolean deductStock(int id,int count);
|
boolean deductStock(int id,int count);
|
||||||
|
|
||||||
List<Goods> queryAllGoodsIdAndStock();
|
List<Goods> queryAllGoodsIdAndStock();
|
||||||
|
Goods queryByTitle(String title);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package me.xiaoyan.point.api.service;
|
package me.xiaoyan.point.api.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import me.xiaoyan.point.api.pojo.OrderInfo;
|
import me.xiaoyan.point.api.pojo.OrderInfo;
|
||||||
import me.xiaoyan.point.api.pojo.vo.CreateOrderData;
|
import me.xiaoyan.point.api.pojo.vo.CreateOrderData;
|
||||||
|
import me.xiaoyan.point.api.pojo.vo.OrderQueryParam;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 订单表(OrderInfo)表服务接口
|
* 订单表(OrderInfo)表服务接口
|
||||||
@ -13,5 +15,9 @@ import me.xiaoyan.point.api.pojo.vo.CreateOrderData;
|
|||||||
public interface OrderInfoService extends IService<OrderInfo> {
|
public interface OrderInfoService extends IService<OrderInfo> {
|
||||||
|
|
||||||
OrderInfo create(int uid, CreateOrderData data);
|
OrderInfo create(int uid, CreateOrderData data);
|
||||||
|
|
||||||
|
Page queryByPage(OrderQueryParam param,boolean queryGoods,boolean queryUser);
|
||||||
|
|
||||||
|
OrderInfo getOneByIdAndUid(String id, int uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import me.xiaoyan.point.api.pojo.Goods;
|
|||||||
import me.xiaoyan.point.api.pojo.vo.GoodsQueryParam;
|
import me.xiaoyan.point.api.pojo.vo.GoodsQueryParam;
|
||||||
import me.xiaoyan.point.api.service.GoodsService;
|
import me.xiaoyan.point.api.service.GoodsService;
|
||||||
import me.xiaoyan.point.api.mapper.GoodsMapper;
|
import me.xiaoyan.point.api.mapper.GoodsMapper;
|
||||||
|
import me.xiaoyan.point.api.util.DataStatus;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
@ -31,9 +32,15 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods>
|
|||||||
if (StringUtils.hasText(param.getTitle())) {
|
if (StringUtils.hasText(param.getTitle())) {
|
||||||
q.eq("title", param.getTitle().trim());
|
q.eq("title", param.getTitle().trim());
|
||||||
}
|
}
|
||||||
|
if (param.getCategory() != null) {
|
||||||
|
q.eq("category", param.getCategory());
|
||||||
|
}
|
||||||
|
// 不查询删除状态数据
|
||||||
|
q.ne("status", DataStatus.DELETE);
|
||||||
return getBaseMapper().selectPage(param.getPage(), q);
|
return getBaseMapper().selectPage(param.getPage(), q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean deductStock(int id, int count) {
|
public boolean deductStock(int id, int count) {
|
||||||
return getBaseMapper().deductCount(id, count) == 1;
|
return getBaseMapper().deductCount(id, count) == 1;
|
||||||
@ -43,6 +50,16 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods>
|
|||||||
public List<Goods> queryAllGoodsIdAndStock() {
|
public List<Goods> queryAllGoodsIdAndStock() {
|
||||||
return getBaseMapper().queryAllGoodsIdAndStock();
|
return getBaseMapper().queryAllGoodsIdAndStock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Goods queryByTitle(String title) {
|
||||||
|
if (!StringUtils.hasText(title)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
QueryWrapper q = new QueryWrapper();
|
||||||
|
q.eq("title", title);
|
||||||
|
return getOne(q);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package me.xiaoyan.point.api.service.impl;
|
package me.xiaoyan.point.api.service.impl;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import me.xiaoyan.point.api.error.BizException;
|
import me.xiaoyan.point.api.error.BizException;
|
||||||
import me.xiaoyan.point.api.mapper.OrderInfoMapper;
|
import me.xiaoyan.point.api.mapper.OrderInfoMapper;
|
||||||
@ -9,8 +10,11 @@ import me.xiaoyan.point.api.pojo.OrderInfo;
|
|||||||
import me.xiaoyan.point.api.pojo.UserInfo;
|
import me.xiaoyan.point.api.pojo.UserInfo;
|
||||||
import me.xiaoyan.point.api.pojo.dto.OrderStatus;
|
import me.xiaoyan.point.api.pojo.dto.OrderStatus;
|
||||||
import me.xiaoyan.point.api.pojo.vo.CreateOrderData;
|
import me.xiaoyan.point.api.pojo.vo.CreateOrderData;
|
||||||
|
import me.xiaoyan.point.api.pojo.vo.OrderQueryParam;
|
||||||
import me.xiaoyan.point.api.service.*;
|
import me.xiaoyan.point.api.service.*;
|
||||||
|
import me.xiaoyan.point.api.util.DataStatus;
|
||||||
import me.xiaoyan.point.api.util.OrderIdGenerator;
|
import me.xiaoyan.point.api.util.OrderIdGenerator;
|
||||||
|
import me.xiaoyan.point.api.util.QueryWrapperUtil;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@ -68,9 +72,11 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
|
|||||||
.id(OrderIdGenerator.next())
|
.id(OrderIdGenerator.next())
|
||||||
.gid((long) data.getGoodsId())
|
.gid((long) data.getGoodsId())
|
||||||
.uid(uid)
|
.uid(uid)
|
||||||
|
.orderTitle(goods.getTitle())
|
||||||
.count(data.getBuyCount())
|
.count(data.getBuyCount())
|
||||||
.price(goods.getPrice())
|
.price(goods.getPrice())
|
||||||
.status(OrderStatus.CONFIRM)
|
// 默认为待确认
|
||||||
|
.status(OrderStatus.NOT_CONFIRM)
|
||||||
.build();
|
.build();
|
||||||
if (save(orderInfo)) {
|
if (save(orderInfo)) {
|
||||||
return orderInfo;
|
return orderInfo;
|
||||||
@ -78,6 +84,47 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
|
|||||||
throw BizException.create("创建订单失败");
|
throw BizException.create("创建订单失败");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page queryByPage(OrderQueryParam param, boolean queryGoods, boolean queryUser) {
|
||||||
|
|
||||||
|
final QueryWrapper q = QueryWrapperUtil.builder()
|
||||||
|
.eq("id", param.getId())
|
||||||
|
.eq("order_title", param.getTitle())
|
||||||
|
.ge("create_time", param.getCreateTimeStart())
|
||||||
|
.le("create_time", param.getCreateTimeEnd())
|
||||||
|
.ne("status", DataStatus.DELETE)
|
||||||
|
.build();
|
||||||
|
// 根据状态筛选
|
||||||
|
if (param.getStatus() != null && param.getStatus() > 0) {
|
||||||
|
q.eq("status", param.getStatus());
|
||||||
|
}
|
||||||
|
q.orderByDesc("create_time");
|
||||||
|
final Page<OrderInfo> page = getBaseMapper().selectPage(param.getPage(), q);
|
||||||
|
page.getRecords().forEach(o -> {
|
||||||
|
if (queryUser) {
|
||||||
|
// 查询订单的归属用户
|
||||||
|
o.setOwner(userInfoService.getById(o.getUid()));
|
||||||
|
}
|
||||||
|
if (queryGoods) {
|
||||||
|
// 查询订单商品信息
|
||||||
|
o.setGoods(goodsService.getById(o.getGid()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OrderInfo getOneByIdAndUid(String id, int uid) {
|
||||||
|
QueryWrapper q = new QueryWrapper();
|
||||||
|
q.eq("uid", uid);
|
||||||
|
q.eq("id", id);
|
||||||
|
final OrderInfo o = getOne(q);
|
||||||
|
if(null != o){
|
||||||
|
o.setGoods(goodsService.getById(o.getGid()));
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
public long buyHistoryCount(int uid, int gid) {
|
public long buyHistoryCount(int uid, int gid) {
|
||||||
QueryWrapper q = new QueryWrapper();
|
QueryWrapper q = new QueryWrapper();
|
||||||
q.eq("uid", uid);
|
q.eq("uid", uid);
|
||||||
|
@ -2,6 +2,7 @@ package me.xiaoyan.point.api.util;
|
|||||||
|
|
||||||
public class DataStatus {
|
public class DataStatus {
|
||||||
public static final int NORMAL = 1;
|
public static final int NORMAL = 1;
|
||||||
|
public static final int DISABLED = 2;
|
||||||
public static final int DELETE = 0;
|
public static final int DELETE = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package me.xiaoyan.point.api.util;
|
||||||
|
|
||||||
|
public class OrderStatus {
|
||||||
|
public static final int NOT_CONFIRM = 1;
|
||||||
|
public static final int CONFIRMED = 2;
|
||||||
|
public static final int CANCELED = 3;
|
||||||
|
public static final int FINISH = 4;
|
||||||
|
public static final int DELETE = 0;
|
||||||
|
}
|
@ -24,12 +24,30 @@ public class QueryWrapperUtil {
|
|||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
public QueryWrapperUtil eq(String column, int value) {
|
||||||
|
q.eq(column, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public QueryWrapperUtil ne(String column, Object value) {
|
public QueryWrapperUtil ne(String column, Object value) {
|
||||||
q.ne(column, value);
|
q.ne(column, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public QueryWrapperUtil le(String column, String value) {
|
||||||
|
if (StringUtils.hasText(value)) {
|
||||||
|
q.le(column, value);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueryWrapperUtil ge(String column, String value) {
|
||||||
|
if (StringUtils.hasText(value)) {
|
||||||
|
q.ge(column, value);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public QueryWrapper build() {
|
public QueryWrapper build() {
|
||||||
return this.q;
|
return this.q;
|
||||||
}
|
}
|
||||||
|
@ -48,25 +48,25 @@ create table sign_record
|
|||||||
create_time datetime default current_timestamp
|
create_time datetime default current_timestamp
|
||||||
) engine = innodb
|
) engine = innodb
|
||||||
collate = 'utf8mb4_general_ci' comment '打卡记录表';
|
collate = 'utf8mb4_general_ci' comment '打卡记录表';
|
||||||
drop table if exists goods;
|
drop table if exists goods;
|
||||||
create table goods
|
create table goods
|
||||||
(
|
(
|
||||||
id bigint(15) primary key auto_increment,
|
id bigint(15) primary key auto_increment,
|
||||||
category tinyint(2) null default 1 comment '商品类别(1:普通 2:精选 3:秒杀 4:抽奖)',
|
category tinyint(2) null default 1 comment '商品类别(1:普通 2:精选 3:秒杀 4:抽奖)',
|
||||||
type tinyint(2) null default 1 comment '商品类型(1:实物 2:虚拟)',
|
type tinyint(2) null default 1 comment '商品类型(1:实物 2:虚拟)',
|
||||||
title varchar(50) not null,
|
title varchar(50) not null,
|
||||||
origin_price int(10) unsigned comment '原价' default 0,
|
origin_price int(10) unsigned comment '原价' default 0,
|
||||||
price int(10) unsigned not null comment '价格',
|
price int(10) unsigned not null comment '价格',
|
||||||
stock int(10) unsigned not null comment '库存数量',
|
stock int(10) unsigned not null comment '库存数量',
|
||||||
limit_count int(10) unsigned null default 1 comment '购买最大数量(0表示不限制)',
|
limit_count int(10) unsigned null default 1 comment '购买最大数量(0表示不限制)',
|
||||||
cover varchar(200) not null comment '商品图',
|
cover varchar(200) not null comment '商品图',
|
||||||
description text not null comment '描述',
|
description text not null comment '描述',
|
||||||
notice varchar(500) null comment '提示',
|
notice varchar(500) null comment '提示',
|
||||||
online_time datetime not null comment '上架时间',
|
online_time datetime not null comment '上架时间',
|
||||||
offline_time datetime not null comment '下架时间',
|
offline_time datetime not null comment '下架时间',
|
||||||
create_time datetime default current_timestamp,
|
create_time datetime default current_timestamp,
|
||||||
update_time datetime null on update current_timestamp,
|
update_time datetime null on update current_timestamp,
|
||||||
status tinyint(2) default 1,
|
status tinyint(2) default 1,
|
||||||
index ix_title (title)
|
index ix_title (title)
|
||||||
) engine = innodb
|
) engine = innodb
|
||||||
collate = 'utf8mb4_general_ci' comment '商品表';
|
collate = 'utf8mb4_general_ci' comment '商品表';
|
||||||
@ -75,6 +75,7 @@ create table order_info
|
|||||||
(
|
(
|
||||||
id varchar(50) not null comment '订单编号',
|
id varchar(50) not null comment '订单编号',
|
||||||
gid bigint(15) not null comment '商品编号',
|
gid bigint(15) not null comment '商品编号',
|
||||||
|
order_title varchar(50) null comment '订单名称',
|
||||||
price int(10) not null comment '价格',
|
price int(10) not null comment '价格',
|
||||||
uid int(10) not null comment '用户编号',
|
uid int(10) not null comment '用户编号',
|
||||||
data json null comment '订单数据',
|
data json null comment '订单数据',
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
and stock > 0
|
and stock > 0
|
||||||
and category = #{category}
|
and category = #{category}
|
||||||
and status != 0
|
and status != 0
|
||||||
|
order by online_time desc,id desc
|
||||||
</select>
|
</select>
|
||||||
<select id="queryAllGoodsIdAndStock" resultType="me.xiaoyan.point.api.pojo.Goods">
|
<select id="queryAllGoodsIdAndStock" resultType="me.xiaoyan.point.api.pojo.Goods">
|
||||||
select id,stock
|
select id,stock
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
<mapper namespace="me.xiaoyan.point.api.mapper.OrderInfoMapper">
|
<mapper namespace="me.xiaoyan.point.api.mapper.OrderInfoMapper">
|
||||||
|
<resultMap id="orderInfoMap" type="me.xiaoyan.point.api.pojo.OrderInfo">
|
||||||
|
<association property="owner"/>
|
||||||
|
</resultMap>
|
||||||
|
<select id="selectByPage" resultMap="orderInfoMap"></select>
|
||||||
</mapper>
|
</mapper>
|
Loading…
x
Reference in New Issue
Block a user