feat(custom): i

This commit is contained in:
2023-09-06 03:48:46 +08:00
parent 3b3cb7ba34
commit a9707c6d94
51 changed files with 2273 additions and 87 deletions

10
.env
View File

@@ -1,3 +1,9 @@
VITE_TITLE = 'Vue Naive Admin'
VITE_TITLE = '捷兑通 - 平台端'
VITE_PORT = 3100
VITE_PORT = 4000
VITE_WS_URL = 'www.wanzhuanyongcheng.cn/admin/data'
VITE_WS1_URL = 'www.jdt168.com/dice/home'
VITE_GAME_API = 'https://www.jdt168.com'

View File

@@ -2,10 +2,10 @@
VITE_PUBLIC_PATH = '/'
# 是否启用MOCK
VITE_USE_MOCK = true
VITE_USE_MOCK = false
# 是否启用MOCK
# 是否启用代理
VITE_USE_PROXY = true
# base api
VITE_BASE_API = '/api'
VITE_BASE_API = '/admin'

View File

@@ -1,11 +1,13 @@
# 资源公共路径,需要以 /开头和结尾
VITE_PUBLIC_PATH = '/'
VITE_PUBLIC_PATH = '/static/admin'
# 是否启用MOCK
VITE_USE_MOCK = true
VITE_USE_MOCK = false
# base api
VITE_BASE_API = '/api'
VITE_BASE_API = 'https://www.wanzhuanyongcheng.cn/admin'
# VITE_GAME_API = 'http://www.wanzhuanyongcheng.cn/admin'
# 是否启用压缩
VITE_USE_COMPRESS = true

View File

@@ -6,28 +6,28 @@ export const PROXY_CONFIG = {
* @请求路径 http://localhost:3100/api/user
* @转发路径 http://localhost:8080/user
*/
'/api': {
target: 'http://localhost:8080',
'/admin': {
target: 'https://www.wanzhuanyongcheng.cn',
changeOrigin: true,
rewrite: (path) => path.replace(new RegExp('^/api'), ''),
// rewrite: (path) => path.replace(new RegExp('^/api'), ''),
},
/**
* @desc 不替换匹配值
* @请求路径 http://localhost:3100/api/v2/user
* @转发路径 http://localhost:8080/api/v2/user
*/
'/api/v2': {
target: 'http://localhost:8080',
changeOrigin: true,
},
// '/api/v2': {
// target: 'http://localhost:8080',
// changeOrigin: true,
// },
/**
* @desc 替换部分匹配值
* @请求路径 http://localhost:3100/api/v3/user
* @转发路径 http://localhost:8080/user
*/
'/api/v3': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(new RegExp('^/api'), ''),
},
// '/api/v3': {
// target: 'http://localhost:8080',
// changeOrigin: true,
// rewrite: (path) => path.replace(new RegExp('^/api'), ''),
// },
}

View File

@@ -8,7 +8,7 @@
},
"naiveThemeOverrides": {
"common": {
"primaryColor": "#316C72FF",
"primaryColor": "#409EFFE3",
"primaryColorHover": "#316C72E3",
"primaryColorPressed": "#2B4C59FF",
"primaryColorSuppl": "#316C72E3",

67
src/components/Upload.vue Normal file
View File

@@ -0,0 +1,67 @@
<template>
<n-upload
v-model:file-list="List"
action="/admin/upload"
:headers="headers"
:max="max"
list-type="image-card"
@before-upload="beforeUpload"
@finish="handleFinish"
@error="handleError"
>
点击上传
</n-upload>
</template>
<script setup>
import { getToken } from '@/utils'
const token = getToken()
const prop = defineProps({
list: {
type: Array,
default: () => [],
},
max: {
type: Number,
default: 1,
},
})
const emit = defineEmits(['update:list'])
const headers = ref({
Authorization: `Bearer ${token}`,
})
const List = computed({
get() {
return prop.list
},
set(val) {
emit('update:list', val)
},
})
const handleFinish = ({ file, event }) => {
const res = JSON.parse(event.target.response)
file.url = res.data.data
return file
}
const handleError = () => {
$message.error('上传失败')
}
// 图片上传限制
const beforeUpload = (data) => {
if (!(data.file.file?.type === 'image/png' || data.file.file?.type === 'image/jpeg')) {
$message.error('只能上传png或jpg格式的图片文件,请重新上传')
return false
}
return true
}
</script>
<style lang="scss" scoped></style>

View File

@@ -2,7 +2,7 @@
<transition name="fade-slide" mode="out-in" appear>
<section class="cus-scroll-y wh-full flex-col bg-[#f5f6fb] p-15 dark:bg-hex-121212">
<slot />
<AppFooter v-if="showFooter" mt-15 />
<!-- <AppFooter v-if="showFooter" mt-15 /> -->
<n-back-top :bottom="20" />
</section>
</transition>

43
src/hooks/useScript.js Normal file
View File

@@ -0,0 +1,43 @@
import { onMounted, onUnmounted, ref } from 'vue'
export function useScript(opts) {
const isLoading = ref(false)
const error = ref(false)
const success = ref(false)
let script
const promise = new Promise((resolve, reject) => {
onMounted(() => {
script = document.createElement('script')
script.type = 'text/javascript'
script.charset = 'utf-8'
script.onload = function () {
isLoading.value = false
success.value = true
error.value = false
resolve('')
}
script.onerror = function (err) {
isLoading.value = false
success.value = false
error.value = true
reject(err)
}
script.src = opts.src
document.head.appendChild(script)
})
})
onUnmounted(() => {
script && script.remove()
})
return {
isLoading,
error,
success,
toPromise: () => promise,
}
}

View File

@@ -4,9 +4,9 @@
<BreadCrumb ml-15 hidden sm:block />
</div>
<div ml-auto flex items-center>
<MessageNotification />
<!-- <MessageNotification /> -->
<ThemeMode />
<GithubSite />
<!-- <GithubSite /> -->
<FullScreen />
<UserAvatar />
</div>
@@ -17,7 +17,7 @@ import BreadCrumb from './components/BreadCrumb.vue'
import MenuCollapse from './components/MenuCollapse.vue'
import FullScreen from './components/FullScreen.vue'
import UserAvatar from './components/UserAvatar.vue'
import GithubSite from './components/GithubSite.vue'
// import GithubSite from './components/GithubSite.vue'
import ThemeMode from './components/ThemeMode.vue'
import MessageNotification from './components/MessageNotification.vue'
// import MessageNotification from './components/MessageNotification.vue'
</script>

View File

@@ -1,4 +1,4 @@
import { getToken, refreshAccessToken, isNullOrWhitespace } from '@/utils'
import { getToken, isNullOrWhitespace } from '@/utils'
const WHITE_LIST = ['/login', '/404']
export function createPermissionGuard(router) {
@@ -14,7 +14,7 @@ export function createPermissionGuard(router) {
/** 有token的情况 */
if (to.path === '/login') return { path: '/' }
refreshAccessToken()
// refreshAccessToken()
return true
})
}

View File

@@ -4,7 +4,7 @@ import { basicRoutes, EMPTY_ROUTE, NOT_FOUND_ROUTE } from './routes'
import { getToken, isNullOrWhitespace } from '@/utils'
import { useUserStore, usePermissionStore } from '@/store'
const isHash = import.meta.env.VITE_USE_HASH === 'true'
const isHash = true
export const router = createRouter({
history: isHash ? createWebHashHistory('/') : createWebHistory('/'),
routes: basicRoutes,

View File

@@ -1,4 +1,4 @@
const Layout = () => import('@/layout/index.vue')
// const Layout = () => import('@/layout/index.vue')
export const basicRoutes = [
{
@@ -18,42 +18,42 @@ export const basicRoutes = [
},
},
{
name: 'ExternalLink',
path: '/external-link',
component: Layout,
meta: {
title: '外部链接',
icon: 'mdi:link-variant',
order: 4,
},
children: [
{
name: 'LinkGithubSrc',
path: 'https://github.com/zclzone/vue-naive-admin',
meta: {
title: '源码 - github',
icon: 'mdi:github',
},
},
{
name: 'LinkGiteeSrc',
path: 'https://gitee.com/zclzone/vue-naive-admin',
meta: {
title: '源码 - gitee',
icon: 'simple-icons:gitee',
},
},
{
name: 'LinkDocs',
path: 'https://zclzone.github.io/vue-naive-admin-docs',
meta: {
title: '文档 - vuepress',
icon: 'mdi:vuejs',
},
},
],
},
// {
// name: 'ExternalLink',
// path: '/external-link',
// component: Layout,
// meta: {
// title: '外部链接',
// icon: 'mdi:link-variant',
// order: 4,
// },
// children: [
// {
// name: 'LinkGithubSrc',
// path: 'https://github.com/zclzone/vue-naive-admin',
// meta: {
// title: '源码 - github',
// icon: 'mdi:github',
// },
// },
// {
// name: 'LinkGiteeSrc',
// path: 'https://gitee.com/zclzone/vue-naive-admin',
// meta: {
// title: '源码 - gitee',
// icon: 'simple-icons:gitee',
// },
// },
// {
// name: 'LinkDocs',
// path: 'https://zclzone.github.io/vue-naive-admin-docs',
// meta: {
// title: '文档 - vuepress',
// icon: 'mdi:vuejs',
// },
// },
// ],
// },
]
export const NOT_FOUND_ROUTE = {

View File

@@ -2,7 +2,7 @@ import { defineStore } from 'pinia'
import { resetRouter } from '@/router'
import { useTagsStore, usePermissionStore } from '@/store'
import { removeToken, toLogin } from '@/utils'
import api from '@/api'
// import api from '@/api'
export const useUserStore = defineStore('user', {
state() {
@@ -26,14 +26,14 @@ export const useUserStore = defineStore('user', {
},
actions: {
async getUserInfo() {
try {
const res = await api.getUser()
const { id, name, avatar, role } = res.data
this.userInfo = { id, name, avatar, role }
return Promise.resolve(res.data)
} catch (error) {
return Promise.reject(error)
}
// try {
// const res = await api.getUser()
// const { id, name, avatar, role } = res.data
// this.userInfo = { id, name, avatar, role }
// return Promise.resolve(res.data)
// } catch (error) {
// return Promise.reject(error)
// }
},
async logout() {
const { resetTags } = useTagsStore()

View File

@@ -14,6 +14,4 @@ export function createAxios(options = {}) {
return service
}
export const request = createAxios({
baseURL: import.meta.env.VITE_BASE_API,
})
export const request = createAxios({})

View File

@@ -2,6 +2,11 @@ import { getToken } from '@/utils'
import { resolveResError } from './helpers'
export function reqResolve(config) {
if (config.url.includes('/dice')) {
config.baseURL = import.meta.env.VITE_GAME_API
} else {
config.baseURL = import.meta.env.VITE_BASE_API
}
// 处理不需要token的请求
if (config.noNeedToken) {
return config
@@ -28,7 +33,7 @@ export function reqReject(error) {
export function resResolve(response) {
// TODO: 处理不同的 response.headers
const { data, status, config, statusText } = response
if (data?.code !== 0) {
if (data?.code !== 200) {
const code = data?.code ?? status
/** 根据code处理对应的操作并返回处理后的message */

View File

@@ -0,0 +1,7 @@
import { request } from '@/utils'
export default {
getList: (data) => request.post('/store', data),
addMer: (data) => request.post('/store/edit', data),
getMerType: () => request.post('/store/getOther'),
}

View File

@@ -0,0 +1,434 @@
<template>
<CommonPage show-footer :title="$route.title">
<!-- {{ formValue }} -->
<n-button type="primary" @click="handleAdd(1)">新增商户</n-button>
<n-grid class="mb-10" x-gap="12" cols="6" collapsed>
<n-gi>
<div class="flex items-center">
<div class="w-150">商户名称</div>
<n-input v-model:value="QuryVal.StoreName" type="text" placeholder="请输入商户名称" />
</div>
</n-gi>
<n-gi>
<div class="flex items-center">
<div class="w-150">商户状态</div>
<n-select
v-model:value="QuryVal.Status"
placeholder="请选择商户状态"
clearable
:options="[
{
label: '正常',
value: 1,
},
{
label: '禁用',
value: 2,
},
]"
/>
</div>
</n-gi>
<n-gi>
<n-button type="primary" @click="getList">查询</n-button>
<n-button class="ml10" @click="clearQuryVal">重置</n-button>
</n-gi>
</n-grid>
<n-data-table
:loading="loading"
:columns="columns"
:data="data"
:pagination="pagination"
:bordered="false"
/>
<n-drawer v-model:show="showModal" :width="502" placement="right">
<n-drawer-content :title="drawerTitle" closable>
<n-form
ref="formRef"
label-placement="left"
label-align="left"
label-width="120px"
:model="formValue"
:rules="rules"
size="medium"
>
<!-- <n-form-item label="商户头像:" path="img">
<n-upload
v-model:file-list="formValue.img"
action="https://www.mocky.io/v2/5e4bafc63100007100d8b70f"
list-type="image-card"
>
点击上传
</n-upload>
</n-form-item> -->
<n-form-item label="商户名称:" path="name">
<n-input v-model:value="formValue.name" placeholder="请输入商户名称" />
</n-form-item>
<n-form-item label="负责人姓名:" path="username">
<n-input v-model:value="formValue.username" placeholder="请输入负责人姓名" />
</n-form-item>
<n-form-item label="商户手机号:" path="phone">
<n-input v-model:value="formValue.phone" placeholder="请输入商户手机号" />
</n-form-item>
<n-form-item label="商户座机:" path="mobile">
<n-input v-model:value="formValue.mobile" placeholder="请输入商户座机" />
</n-form-item>
<n-form-item label="商户地址:" path="address">
<n-input v-model:value="formValue.address" placeholder="请输入商户地址" />
</n-form-item>
<n-form-item label="经营类目:" path="classId">
<n-select
v-model:value="formValue.classId"
label-field="name"
value-field="ID"
clearable
placeholder="请选择经营类目"
:options="classOptions"
/>
</n-form-item>
<!-- <n-form-item label="商户经纬度:" path="local">
<n-input v-model:value="formValue.local" placeholder="请输入商户地址" />
<div ref="wrapRef" class="h-300 w-300"></div>
</n-form-item> -->
<n-form-item label="商户密码:" path="password">
<n-input v-model:value="formValue.password" placeholder="请输入商户密码" />
</n-form-item>
<n-form-item label="商户类型:" path="bType">
<n-select
v-model:value="formValue.bType"
label-field="name"
value-field="ID"
placeholder="请选择商户类型"
clearable
:options="typeOptions"
/>
</n-form-item>
<n-form-item label="手续费收取类型:" path="scaleType">
<n-select
v-model:value="formValue.scaleType"
placeholder="请选择手续费收取类型"
clearable
:options="[
{
label: '百分比',
value: 1,
},
{
label: '数值',
value: 2,
},
]"
/>
</n-form-item>
<n-form-item label="手续费比例:" path="scale">
<n-input-number v-model:value="formValue.scale" placeholder="请输入手续费比例" />
</n-form-item>
<n-form-item label="商户状态:" path="status">
<n-switch v-model:value="formValue.status" :checked-value="1" :unchecked-value="2" />
</n-form-item>
<n-form-item>
<n-button
class="m-auto w-200"
attr-type="button"
type="primary"
@click="handleValidateClick"
>
提交
</n-button>
<n-button class="m-auto w-200" @click="handleClearValidateClick">重置</n-button>
</n-form-item>
</n-form>
</n-drawer-content>
</n-drawer>
</CommonPage>
</template>
<script setup>
import { onMounted, ref, h, unref, nextTick } from 'vue'
import { NButton } from 'naive-ui'
import api from './api'
import { useScript } from '@/hooks/useScript'
const columns = ref([
{
title: '商户名称',
align: 'center',
key: 'name',
},
{
title: '商户类型',
align: 'center',
key: 'type',
render(row) {
return h('span', row.bType === 1 ? '供应商' : '兑换商')
},
},
{
title: '状态',
align: 'center',
key: 'status',
render(row) {
return h('span', row.status === 1 ? '正常' : '禁用')
},
},
{
title: '操作',
align: 'center',
slot: 'action',
render(row) {
return [
h(
NButton,
{
type: 'primary',
size: 'small',
onClick: () => {
formValue.value = row
handleAdd(2)
},
},
() => '编辑'
),
]
},
},
])
const data = ref([])
const loading = ref(false)
const showModal = ref(false)
const formRef = ref(null)
const drawerTitle = ref('')
const pagination = ref({
current: 1,
pageSize: 10,
total: 0,
onChange: (page) => {
pagination.value.page = page
getList()
},
onUpdatePageSize: (pageSize) => {
pagination.value.pageSize = pageSize
pagination.value.page = 1
getList()
},
})
const QuryVal = ref({
StoreName: '',
Status: null,
})
// const defaultValueRef = () => ({
// name: '',
// username: '',
// phone: '',
// mobile: '',
// address: '',
// classId: null,
// local: '',
// password: '',
// bType: null,
// scaleType: null,
// scale: null,
// status: 2,
// })
let formValue = ref({
name: '',
username: '',
phone: '',
mobile: '',
address: '',
classId: null,
local: '',
password: '',
bType: null,
scaleType: null,
scale: null,
status: 2,
})
const rules = {
name: {
required: true,
message: '请输入商户名称',
trigger: 'blur',
},
username: {
required: true,
message: '请输入负责人姓名',
trigger: 'blur',
},
phone: {
required: true,
message: '请输入商户手机号',
trigger: 'blur',
},
mobile: {
required: true,
message: '请输入商户座机',
trigger: 'blur',
},
address: {
required: true,
message: '请输入商户地址',
trigger: 'blur',
},
local: {
required: true,
message: '请搜索商户经纬度',
trigger: 'blur',
},
classId: {
required: true,
type: 'number',
message: '请选择经营类目',
trigger: 'change',
},
// password: {
// required: true,
// message: '请输入商户密码',
// trigger: 'blur',
// },
bType: {
required: true,
type: 'number',
message: '请选择商户类型',
trigger: 'change',
},
scaleType: {
required: true,
type: 'number',
message: '请选择手续费收取类型',
trigger: 'change',
},
scale: {
required: true,
type: 'number',
message: '请输入手续费比例',
trigger: 'blur',
},
status: {
type: 'number',
message: '请选择商户状态',
trigger: 'change',
},
}
const wrapRef = ref(null)
const MapUrl =
'https://map.qq.com/api/gljs?v=1.exp&key=S3GBZ-WR26O-IXNW2-SXBOD-LZXV6-WAFNO&callback=initMap'
const { toPromise } = useScript({ src: MapUrl })
onMounted(() => {
initMap()
getList()
getMertype()
})
const initMap = async () => {
await toPromise()
await nextTick()
const wrapEl = unref(wrapRef.value)
if (!wrapEl) return
const TMap = window?.TMap
const center = new TMap.Map.LatLng(39.984104, 116.307503)
const map = new TMap.Map.Map(wrapEl, {
rotation: 20, //设置地图旋转角度
pitch: 30, //设置俯仰角度0~45
zoom: 12, //设置地图缩放级别
center: center, //设置地图中心点坐标
})
console.log(map)
}
const getList = async () => {
loading.value = true
const res = await api.getList({
...QuryVal.value,
PageNum: pagination.value.current,
PageSize: pagination.value.pageSize,
})
data.value = res.data.data
loading.value = false
}
const classOptions = ref([])
const typeOptions = ref([])
const getMertype = async () => {
const res = await api.getMerType()
classOptions.value = res.data.class
typeOptions.value = res.data.type
}
const clearQuryVal = () => {
QuryVal.value = {
StoreName: '',
Status: '',
}
getList()
}
const handleAdd = (e) => {
drawerTitle.value = e === 1 ? '新增商户' : '编辑商户'
showModal.value = true
}
// const onPositiveClick = () => {
// showModal.value = false
// }
// const onNegativeClick = () => {
// showModal.value = false
// }
const handleValidateClick = (e) => {
e.preventDefault()
formRef.value?.validate(async (errors) => {
if (!errors) {
try {
await api.addMer(formValue.value)
$message.success('成功')
handleClearValidateClick()
getMertype()
getList()
showModal.value = false
} catch (error) {
$message.error(error.msg)
}
} else {
$message.error('Invalid')
}
})
}
const handleClearValidateClick = () => {
formRef.value?.restoreValidation()
formValue.value = {
name: '',
username: '',
phone: '',
mobile: '',
address: '',
classId: null,
local: '',
password: '',
bType: null,
scaleType: null,
scale: null,
status: 2,
}
}
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,6 @@
import { request } from '@/utils'
export default {
getMerType: (data) => request.post('/typesof', data),
addMerType: (data) => request.post('/typesof/edit', data),
}

View File

@@ -0,0 +1,182 @@
<template>
<CommonPage show-footer :title="$route.title">
<n-button type="primary" @click="handleAdd(1)">新增商户类型</n-button>
<!-- {{ formValue }} -->
<n-data-table
:loading="loading"
:columns="columns"
:data="data"
:pagination="pagination"
:bordered="false"
/>
<n-modal v-model:show="showModal">
<n-card
style="width: 400px"
:title="modelTitle"
:bordered="false"
size="huge"
role="dialog"
aria-modal="true"
>
<n-form ref="formRef" label-placement="left" :model="formValue" :rules="rules">
<n-form-item label="商户类型:" path="name">
<n-input v-model:value="formValue.name" placeholder="请输入商户类型" />
</n-form-item>
<n-form-item label="商户状态:" path="status">
<n-switch v-model:value="formValue.status" :checked-value="1" :unchecked-value="2" />
</n-form-item>
<n-form-item>
<div class="m-auto">
<n-button
class="m-auto"
type="primary"
attr-type="button"
@click="handleValidateClick"
>
提交
</n-button>
<n-button class="ml-10" @click="clear">取消</n-button>
</div>
</n-form-item>
</n-form>
</n-card>
</n-modal>
</CommonPage>
</template>
<script setup>
import { onMounted, h } from 'vue'
import api from './api'
import { NButton } from 'naive-ui'
const loading = ref(false)
const columns = ref([
{
title: 'ID',
align: 'center',
key: 'ID',
},
{
title: '商户类型',
align: 'center',
key: 'name',
},
{
title: '状态',
align: 'center',
slot: 'status',
render(row) {
return h('span', row.status === 1 ? '正常' : '禁用')
},
},
{
title: '操作',
align: 'center',
slot: 'action',
render(row) {
return [
h(
NButton,
{
type: 'primary',
size: 'small',
onClick: () => {
formValue.value = row
handleAdd(2)
},
},
() => '编辑'
),
]
},
},
])
const data = ref([])
const formRef = ref(null)
const rules = {
name: {
required: true,
message: '请输入商户分类名称',
},
}
const formValue = ref({
name: '',
status: 1,
})
const showModal = ref(false)
const pagination = ref({
current: 1,
pageSize: 10,
total: 0,
onChange: (page) => {
pagination.value.page = page
getList()
},
onUpdatePageSize: (pageSize) => {
pagination.value.pageSize = pageSize
pagination.value.page = 1
getList()
},
})
onMounted(() => {
getList()
})
const getList = async () => {
loading.value = true
try {
const res = await api.getMerType({
pageNum: pagination.value.current,
pageSize: pagination.value.pageSize,
})
console.log(res)
data.value = res.data.data
} catch (error) {
$message.error(error.msg)
}
loading.value = false
}
const modelTitle = ref('')
const handleAdd = (e) => {
modelTitle.value = e === 1 ? '新增商户类型' : '编辑商户类型'
showModal.value = true
}
const clear = () => {
formValue.value = {
name: '',
status: 1,
}
showModal.value = false
}
const handleValidateClick = async (e) => {
e.preventDefault()
formRef.value?.validate(async (errors) => {
if (!errors) {
try {
await api.addMerType(formValue.value)
$message.success('成功')
clear()
getList()
} catch (error) {
$message.error(error.msg)
}
} else {
$message.error('Invalid')
}
})
}
</script>
<style lang="scss" scoped></style>

View File

View File

@@ -0,0 +1,7 @@
<template>
<CommonPage show-footer :title="$route.title"></CommonPage>
</template>
<script setup></script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,40 @@
const Layout = () => import('@/layout/index.vue')
export default {
name: '商户管理',
path: '/merchant',
component: Layout,
redirect: '/mer_list',
children: [
{
name: 'Merlist',
path: 'mer_list',
component: () => import('./mer_list/index.vue'),
meta: {
title: '商户列表',
icon: 'mdi:account-multiple',
order: 10,
},
},
{
name: 'Mertype',
path: 'mer_type',
component: () => import('./mer_type/index.vue'),
meta: {
title: '商户类型',
icon: 'mdi:account-multiple',
order: 10,
},
},
{
name: 'Merverify',
path: 'mer_verify',
component: () => import('./mer_verify/index.vue'),
meta: {
title: '入驻审核',
icon: 'mdi:account-multiple',
order: 10,
},
},
],
}

View File

@@ -0,0 +1,6 @@
import { request } from '@/utils'
export default {
getMerClass: (data) => request.post('/classify', data),
addMerClass: (data) => request.post('/classify/edit', data),
}

View File

@@ -0,0 +1,182 @@
<template>
<CommonPage show-footer :title="$route.title">
<n-button type="primary" @click="handleAdd(1)">新增商品分类</n-button>
<!-- {{ formValue }} -->
<n-data-table
:loading="loading"
:columns="columns"
:data="data"
:pagination="pagination"
:bordered="false"
/>
<n-modal v-model:show="showModal">
<n-card
style="width: 400px"
:title="modelTitle"
:bordered="false"
size="huge"
role="dialog"
aria-modal="true"
>
<n-form ref="formRef" label-placement="left" :model="formValue" :rules="rules">
<n-form-item label="分类名称:" path="name">
<n-input v-model:value="formValue.name" placeholder="请输入商户分类名称" />
</n-form-item>
<n-form-item label="分类状态:" path="status">
<n-switch v-model:value="formValue.status" :checked-value="1" :unchecked-value="2" />
</n-form-item>
<n-form-item>
<div class="m-auto">
<n-button
class="m-auto"
type="primary"
attr-type="button"
@click="handleValidateClick"
>
提交
</n-button>
<n-button class="ml-10" @click="clear">取消</n-button>
</div>
</n-form-item>
</n-form>
</n-card>
</n-modal>
</CommonPage>
</template>
<script setup>
import { onMounted, h } from 'vue'
import api from './api'
import { NButton } from 'naive-ui'
const loading = ref(false)
const columns = ref([
{
title: 'ID',
align: 'center',
key: 'ID',
},
{
title: '分类名称',
align: 'center',
key: 'name',
},
{
title: '状态',
align: 'center',
slot: 'status',
render(row) {
return h('span', row.status === 1 ? '正常' : '禁用')
},
},
{
title: '操作',
align: 'center',
slot: 'action',
render(row) {
return [
h(
NButton,
{
type: 'primary',
size: 'small',
onClick: () => {
formValue.value = row
handleAdd(2)
},
},
() => '编辑'
),
]
},
},
])
const data = ref([])
const formRef = ref(null)
const rules = {
name: {
required: true,
message: '请输入商户分类名称',
},
}
const formValue = ref({
name: '',
status: 1,
})
const showModal = ref(false)
const pagination = ref({
current: 1,
pageSize: 10,
total: 0,
onChange: (page) => {
pagination.value.page = page
getList()
},
onUpdatePageSize: (pageSize) => {
pagination.value.pageSize = pageSize
pagination.value.page = 1
getList()
},
})
onMounted(() => {
getList()
})
const getList = async () => {
loading.value = true
try {
const res = await api.getMerClass({
pageNum: pagination.value.current,
pageSize: pagination.value.pageSize,
})
console.log(res)
data.value = res.data.data
} catch (error) {
$message.error(error.msg)
}
loading.value = false
}
const modelTitle = ref('')
const handleAdd = (e) => {
modelTitle.value = e === 1 ? '新增商品分类' : '编辑商品分类'
showModal.value = true
}
const clear = () => {
formValue.value = {
name: '',
status: 1,
}
showModal.value = false
}
const handleValidateClick = async (e) => {
e.preventDefault()
formRef.value?.validate(async (errors) => {
if (!errors) {
try {
await api.addMerClass(formValue.value)
$message.success('成功')
clear()
getList()
} catch (error) {
$message.error(error.msg)
}
} else {
$message.error('Invalid')
}
})
}
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,6 @@
import { request } from '@/utils'
export default {
getHotlist: (data) => request.post('/goods', data),
getHotStatus: (data) => request.post('/goods/process', data),
}

View File

@@ -0,0 +1,155 @@
<template>
<CommonPage show-footer :title="$route.title">
<n-data-table
:loading="loading"
:columns="columns"
:data="data"
:pagination="pagination"
:bordered="false"
remote
/>
</CommonPage>
</template>
<script setup>
import api from './api'
import { NDropdown, NButton } from 'naive-ui'
import { h } from 'vue'
const loading = ref(false)
const columns = ref([
{
title: '商品名称',
key: 'name',
align: 'center',
},
{
title: '商品封面',
slot: 'cover',
align: 'center',
render(row) {
return h('img', {
src: row.cover,
style: {
width: '30px',
height: '30px',
},
})
},
},
{
title: '商品分类',
key: 'class_name',
align: 'center',
},
{
title: '商品价格',
key: 'number',
align: 'center',
},
{
title: '商品库存',
key: 'stock',
align: 'center',
},
{
title: '商品状态',
slot: 'status',
align: 'center',
render(row) {
return row.status === 0 ? '待审核' : row.status === 1 ? '已审核' : '已拒绝'
},
},
{
title: '操作',
slot: 'action',
align: 'center',
render(row) {
const el = []
if (row.status === 0) {
el.push(
h(
NDropdown,
{
trigger: 'click',
options: [
{
label: '审核',
key: 1,
},
{
label: '拒绝',
key: 2,
},
],
onSelect: (key) => {
veeify(key, row)
},
},
() =>
h(
NButton,
{
type: 'primary',
text: true,
},
() => '审核'
)
)
)
}
return el
},
},
])
const data = ref([])
const pagination = ref({
current: 1,
pageSize: 10,
itamCount: 0,
onChange: (page) => {
pagination.value.page = page
getList()
},
onUpdatePageSize: (pageSize) => {
pagination.value.pageSize = pageSize
pagination.value.page = 1
getList()
},
})
onMounted(() => {
getList()
})
const getList = async () => {
loading.value = true
try {
const res = await api.getHotlist({
pageNum: pagination.value.current,
pageSize: pagination.value.pageSize,
})
console.log(res)
data.value = res.data.data || []
} catch (error) {
$message.error(error.msg)
}
loading.value = false
}
const veeify = async (key, row) => {
const res = await api.getHotStatus({
gid: row.gid,
status: key,
})
console.log(res)
getList()
}
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,6 @@
import { request } from '@/utils'
export default {
getPointlist: (data) => request.post('/point/goods', data),
getPointStatus: (data) => request.post('/point/goods/process', data),
}

View File

@@ -0,0 +1,155 @@
<template>
<CommonPage show-footer :title="$route.title">
<n-data-table
:loading="loading"
:columns="columns"
:data="data"
:pagination="pagination"
:bordered="false"
/>
</CommonPage>
</template>
<script setup>
import api from './api'
import { NDropdown, NButton } from 'naive-ui'
import { h } from 'vue'
const loading = ref(false)
const columns = ref([
{
title: '商品名称',
key: 'name',
align: 'center',
},
{
title: '商品封面',
slot: 'cover',
align: 'center',
render(row) {
return h('img', {
src: row.cover,
style: {
width: '30px',
height: '30px',
},
})
},
},
{
title: '商品分类',
key: 'class_name',
align: 'center',
},
{
title: '商品价格',
key: 'number',
align: 'center',
},
{
title: '商品库存',
key: 'stock',
align: 'center',
},
{
title: '商品状态',
slot: 'status',
align: 'center',
render(row) {
return row.status === 0 ? '待审核' : row.status === 1 ? '已审核' : '已拒绝'
},
},
{
title: '操作',
slot: 'action',
align: 'center',
render(row) {
const el = []
if (row.status === 0) {
el.push(
h(
NDropdown,
{
trigger: 'click',
options: [
{
label: '审核',
key: 1,
},
{
label: '拒绝',
key: 2,
},
],
onSelect: (key) => {
veeify(key, row)
},
},
() =>
h(
NButton,
{
type: 'primary',
text: true,
},
() => '审核'
)
)
)
}
return el
},
},
])
const data = ref([])
const pagination = ref({
current: 1,
pageSize: 10,
total: 0,
onChange: (page) => {
pagination.value.page = page
getList()
},
onUpdatePageSize: (pageSize) => {
pagination.value.pageSize = pageSize
pagination.value.page = 1
getList()
},
})
onMounted(() => {
getList()
})
const getList = async () => {
loading.value = true
try {
const res = await api.getPointlist({
pageNum: pagination.value.current,
pageSize: pagination.value.pageSize,
})
console.log(res)
data.value = res.data.data || []
} catch (error) {
$message.error(error.msg)
}
loading.value = false
}
const veeify = async (key, row) => {
console.log(typeof key)
const res = await api.getPointStatus({
gid: row.gid,
status: key,
})
console.log(res)
getList()
}
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,40 @@
const Layout = () => import('@/layout/index.vue')
export default {
name: '商品管理',
path: '/commodity',
component: Layout,
redirect: '/commodity_class',
children: [
{
name: 'CommodityClass',
path: 'commodity_class',
component: () => import('./commodity_class/index.vue'),
meta: {
title: '商品分类',
icon: 'mdi:account-multiple',
order: 10,
},
},
{
name: 'HotList',
path: 'hot_list',
component: () => import('./hot_list/index.vue'),
meta: {
title: '活动商品',
icon: 'mdi:account-multiple',
order: 10,
},
},
{
name: 'PointList',
path: 'point_list',
component: () => import('./point/index.vue'),
meta: {
title: '积分商品',
icon: 'mdi:account-multiple',
order: 10,
},
},
],
}

View File

@@ -5,6 +5,7 @@ export default {
path: '/base',
component: Layout,
redirect: '/base/index',
isHidden: true,
meta: {
title: '基础功能',
icon: 'majesticons:compass-line',

View File

@@ -5,6 +5,7 @@ export default {
path: '/error-page',
component: Layout,
redirect: '/error-page/404',
isHidden: true,
meta: {
title: '错误页',
icon: 'mdi:alert-circle-outline',

8
src/views/game/api.js Normal file
View File

@@ -0,0 +1,8 @@
import { request } from '@/utils'
export default {
getData: () => request.post('/dice/getisStart'),
setStatus: (data) => request.post('/dice/isStart', data),
getDS: () => request.post('/dice/getBetting'),
setDS: (data) => request.post('/dice/setBetting', data),
}

View File

@@ -0,0 +1,124 @@
<template>
<CommonPage show-footer :title="$route.title">
<div flex>
<div flex>
<div>游戏状态</div>
<n-switch
v-model:value="val1"
:checked-value="1"
:unchecked-value="2"
@update:value="handleUpdateValue1"
/>
</div>
<div ml-20 flex>
<div>点杀状态</div>
<n-switch
v-model:value="val"
:checked-value="1"
:unchecked-value="2"
@update:value="handleUpdateValue"
/>
</div>
</div>
<div flex>
<div>
预开期数
<span text-25>{{ list[0]?.periods || 0 }}</span>
</div>
<div ml-20>
剩余开奖时间
<span text-25>{{ time || 0 }}</span>
</div>
</div>
<div flex flex-wrap justify-between>
<n-card
v-for="item in list"
:key="item.ID"
class="mb-10 mt-10 w-300 flex-shrink-0 cursor-pointer"
:title="item.name"
>
<p text-25 op-60 :style="{ color: item.count === 0 ? 'green' : 'red' }">{{ item.count }}</p>
</n-card>
<div h-0 w-300></div>
<div h-0 w-300></div>
</div>
</CommonPage>
</template>
<script setup>
import api from '../api'
const ws = new WebSocket(`wss://${import.meta.env.VITE_WS_URL}`)
const ws1 = new WebSocket(`wss://${import.meta.env.VITE_WS1_URL}`)
const list = ref([])
const val1 = ref(null)
const val = ref(null)
const time = ref(null)
ws.onopen = () => {
console.log('1连接成功')
}
ws.onmessage = (msg) => {
const res = JSON.parse(msg.data)
list.value = res
}
ws1.onopen = () => {
console.log('2连接成功')
}
ws1.onmessage = (msg) => {
const res = JSON.parse(msg.data)
switch (res.code) {
case 200:
// let num = res.data
time.value = res.data
break
case 301:
$message.error(res.msg)
break
}
}
onMounted(() => {
get_data()
get_data1()
})
const get_data = async () => {
const res = await api.getDS()
val.value = res.data.diceStatus
}
const get_data1 = async () => {
const res = await api.getData()
val1.value = res.data.diceStart
}
onBeforeUnmount(() => {
ws.close()
})
const handleUpdateValue = async (e) => {
const res = await api.setDS({
status: e,
})
$message.success(res.msg)
get_data()
}
const handleUpdateValue1 = async (e) => {
const res = await api.setStatus({
start: e,
})
$message.success(res.msg)
get_data1()
}
</script>
<style lang="scss" scoped></style>

19
src/views/game/route.js Normal file
View File

@@ -0,0 +1,19 @@
const Layout = () => import('@/layout/index.vue')
export default {
name: '游戏管理',
path: '/game',
component: Layout,
redirect: '/game_data',
children: [
{
name: 'Gamelist',
path: 'game_data',
component: () => import('./data/index.vue'),
meta: {
title: '实时数据',
order: 10,
},
},
],
}

View File

View File

@@ -1,5 +1,5 @@
import { request } from '@/utils'
export default {
login: (data) => request.post('/auth/login', data, { noNeedToken: true }),
login: (data) => request.post('/login', data, { noNeedToken: true }),
}

View File

@@ -19,7 +19,7 @@
v-model:value="loginInfo.name"
autofocus
class="h-50 items-center pl-10 text-16"
placeholder="admin"
placeholder="请输入账号"
:maxlength="20"
/>
</div>
@@ -29,7 +29,7 @@
class="h-50 items-center pl-10 text-16"
type="password"
show-password-on="mousedown"
placeholder="123456"
placeholder="请输入密码"
:maxlength="20"
@keypress.enter="handleLogin"
/>
@@ -99,7 +99,8 @@ async function handleLogin() {
try {
loading.value = true
$message.loading('正在验证...')
const res = await api.login({ name, password: password.toString() })
const res = await api.login({ phone: name, password: password.toString() })
console.log(res.data.token)
$message.success('登录成功')
setToken(res.data.token)
if (isRemember.value) {

View File

@@ -0,0 +1,5 @@
import { request } from '@/utils'
export default {
getOrder: (data) => request.post('/order', data),
}

View File

@@ -0,0 +1,103 @@
<template>
<CommonPage show-footer :title="$route.title">
<n-data-table
:loading="loading"
:columns="columns"
:data="data"
:pagination="pagination"
:bordered="false"
/>
</CommonPage>
</template>
<script setup>
import api from './api'
const loading = ref(false)
const columns = ref([
{
title: '订单号',
align: 'center',
key: 'oid',
},
{
title: '用户',
align: 'center',
key: 'user_name',
},
{
title: '商品名称',
align: 'center',
key: 'goods_name',
},
{
title: '商品价格',
align: 'center',
key: 'number',
},
{
title: '订单状态',
align: 'center',
slot: 'status',
render(row) {
switch (row.status) {
case 0:
return h('span', '待付款')
case 1:
return h('span', '待使用')
case 2:
return h('span', '已完成')
case 3:
return h('span', '已过期')
}
},
},
{
title: '操作',
align: 'center',
slot: 'action',
render(row) {
console.log(row)
},
},
])
const data = ref([])
const pagination = ref({
current: 1,
pageSize: 10,
total: 0,
onChange: (page) => {
pagination.value.page = page
getList()
},
onUpdatePageSize: (pageSize) => {
pagination.value.pageSize = pageSize
pagination.value.page = 1
getList()
},
})
onMounted(() => {
getList()
})
const getList = async () => {
loading.value = true
try {
const res = await api.getOrder({
pageNum: pagination.value.current,
pageSize: pagination.value.pageSize,
})
console.log(res)
data.value = res.data.data || []
} catch (error) {
$message.error(error.msg)
}
loading.value = false
}
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,5 @@
import { request } from '@/utils'
export default {
getPoint: (data) => request.post('/point/order', data),
}

View File

@@ -0,0 +1,103 @@
<template>
<CommonPage show-footer :title="$route.title">
<n-data-table
:loading="loading"
:columns="columns"
:data="data"
:pagination="pagination"
:bordered="false"
/>
</CommonPage>
</template>
<script setup>
import api from './api'
const loading = ref(false)
const columns = ref([
{
title: '订单号',
align: 'center',
key: 'oid',
},
{
title: '用户',
align: 'center',
key: 'user_name',
},
{
title: '商品名称',
align: 'center',
key: 'goods_name',
},
{
title: '商品价格',
align: 'center',
key: 'number',
},
{
title: '订单状态',
align: 'center',
slot: 'status',
render(row) {
switch (row.status) {
case 0:
return h('span', '待付款')
case 1:
return h('span', '待使用')
case 2:
return h('span', '已完成')
case 3:
return h('span', '已过期')
}
},
},
{
title: '操作',
align: 'center',
slot: 'action',
render(row) {
console.log(row)
},
},
])
const data = ref([])
const pagination = ref({
current: 1,
pageSize: 10,
total: 0,
onChange: (page) => {
pagination.value.page = page
getList()
},
onUpdatePageSize: (pageSize) => {
pagination.value.pageSize = pageSize
pagination.value.page = 1
getList()
},
})
onMounted(() => {
getList()
})
const getList = async () => {
loading.value = true
try {
const res = await api.getPoint({
pageNum: pagination.value.current,
pageSize: pagination.value.pageSize,
})
console.log(res)
data.value = res.data.data || []
} catch (error) {
$message.error(error.msg)
}
loading.value = false
}
</script>
<style lang="scss" scoped></style>

30
src/views/order/route.js Normal file
View File

@@ -0,0 +1,30 @@
const Layout = () => import('@/layout/index.vue')
export default {
name: '订单管理',
path: '/order',
component: Layout,
redirect: '/order_list',
children: [
{
name: 'Orderlist',
path: 'order_list',
component: () => import('./index/index.vue'),
meta: {
title: '活动订单',
icon: 'mdi:account-multiple',
order: 10,
},
},
{
name: 'Pointlist',
path: 'point_list',
component: () => import('./point/index.vue'),
meta: {
title: '积分订单',
icon: 'mdi:account-multiple',
order: 10,
},
},
],
}

View File

@@ -0,0 +1,6 @@
import { request } from '@/utils'
export default {
getBanner: (data) => request.post('/rotation', data),
addBanner: (data) => request.post('/rotation/edit', data),
}

View File

@@ -0,0 +1,206 @@
<template>
<CommonPage show-footer :title="$route.title">
<n-button type="primary" @click="handleAdd(1)">新增幻灯片</n-button>
<n-data-table
:loading="loading"
:columns="columns"
:data="data"
:pagination="pagination"
:bordered="false"
/>
<n-modal v-model:show="showModal">
<n-card
style="width: 400px"
:title="modelTitle"
:bordered="false"
size="huge"
role="dialog"
aria-modal="true"
>
<n-form ref="formRef" label-placement="left" :model="formValue" :rules="rules">
<n-form-item label="图片:" path="url">
<Upload v-model:list="formValue.url" />
</n-form-item>
<n-form-item label="状态:" path="status">
<n-switch v-model:value="formValue.status" :checked-value="1" :unchecked-value="2" />
</n-form-item>
<n-form-item>
<div class="m-auto">
<n-button
class="m-auto"
type="primary"
attr-type="button"
@click="handleValidateClick"
>
提交
</n-button>
<n-button class="ml-10" @click="clear">取消</n-button>
</div>
</n-form-item>
</n-form>
</n-card>
</n-modal>
</CommonPage>
</template>
<script setup>
import { onMounted, h } from 'vue'
import api from './api'
import { NButton } from 'naive-ui'
import Upload from '@/components/Upload.vue'
const loading = ref(false)
const columns = ref([
{
title: 'ID',
align: 'center',
key: 'ID',
},
{
title: '图片',
align: 'center',
slot: 'url',
render(row) {
return h('img', {
src: row.url[0]?.url || '',
style: {
width: '30px',
height: '30px',
},
})
},
},
{
title: '状态',
align: 'center',
slot: 'status',
render(row) {
return h('span', row.status === 1 ? '正常' : '禁用')
},
},
{
title: '操作',
align: 'center',
slot: 'action',
render(row) {
return [
h(
NButton,
{
type: 'primary',
size: 'small',
onClick: () => {
formValue.value = row
handleAdd(2)
},
},
() => '编辑'
),
]
},
},
])
const data = ref([])
const formRef = ref(null)
const rules = {
url: {
required: true,
type: 'array',
message: '请上传图片',
},
}
const formValue = ref({
url: [],
status: 1,
})
const showModal = ref(false)
const pagination = ref({
current: 1,
pageSize: 10,
total: 0,
onChange: (page) => {
pagination.value.page = page
getList()
},
onUpdatePageSize: (pageSize) => {
pagination.value.pageSize = pageSize
pagination.value.page = 1
getList()
},
})
onMounted(() => {
getList()
})
const getList = async () => {
loading.value = true
try {
const res = await api.getBanner({
pageNum: pagination.value.current,
pageSize: pagination.value.pageSize,
})
console.log(res)
data.value = res.data.data.map((item) => ({
...item,
url: [
{
id: item.ID,
url: item.url,
status: 'finished',
},
],
}))
} catch (error) {
$message.error(error.msg)
}
loading.value = false
}
const modelTitle = ref('')
const handleAdd = (e) => {
modelTitle.value = e === 1 ? '新增幻灯片' : '编辑幻灯片'
showModal.value = true
}
const clear = () => {
formValue.value = {
name: '',
status: 1,
}
showModal.value = false
}
const handleValidateClick = async (e) => {
e.preventDefault()
formRef.value?.validate(async (errors) => {
if (!errors) {
try {
const data = {
...formValue.value,
url: formValue.value.url[0].url,
status: formValue.value.status,
}
await api.addBanner(data)
$message.success('成功')
clear()
getList()
} catch (error) {
$message.error(error.msg)
}
} else {
$message.error('Invalid')
}
})
}
</script>
<style lang="scss" scoped></style>

30
src/views/system/route.js Normal file
View File

@@ -0,0 +1,30 @@
const Layout = () => import('@/layout/index.vue')
export default {
name: '系统设置',
path: '/sys',
component: Layout,
redirect: '/sys_banner',
children: [
{
name: 'Sysbanner',
path: 'sys_banner',
component: () => import('./index/index.vue'),
meta: {
title: '幻灯片管理',
icon: 'mdi:account-multiple',
order: 10,
},
},
{
name: 'Syssys',
path: 'sys_sys',
component: () => import('./sys/index.vue'),
meta: {
title: '商城设置',
icon: 'mdi:account-multiple',
order: 10,
},
},
],
}

View File

@@ -0,0 +1,6 @@
import { request } from '@/utils'
export default {
getConfig: (data) => request.post('/userConfig', data),
editConfig: (data) => request.post('/userConfig/edit', data),
}

View File

@@ -0,0 +1,66 @@
<template>
<CommonPage show-footer :title="$route.title">
<n-form
ref="formRef"
:label-width="120"
:model="formValue"
label-placement="left"
:rules="rules"
>
<n-form-item label="积分佣金比例:" path="reward">
<n-input-number
v-model:value="formValue.reward"
style="width: 200px"
placeholder="输入积分佣金比例"
/>
</n-form-item>
<n-form-item>
<n-button attr-type="button" @click="handleValidateClick">保存</n-button>
</n-form-item>
</n-form>
</CommonPage>
</template>
<script setup>
import api from './api'
const formValue = ref({
reward: null,
})
const formRef = ref(null)
const rules = {
reward: [
{
required: true,
type: 'number',
message: '请输入积分佣金比例',
},
],
}
onMounted(() => {
getconfig()
})
const getconfig = async () => {
const res = await api.getConfig()
formValue.value = res.data.data
}
const handleValidateClick = () => {
formRef.value.validate(async (valid) => {
try {
if (valid) return
await api.editConfig(formValue.value)
$message.success('保存成功')
getconfig()
} catch (error) {
$message.error('保存失败')
}
})
}
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,5 @@
import { request } from '@/utils'
export default {
getUser: (data) => request.post('/user', data),
}

View File

@@ -0,0 +1,101 @@
<template>
<CommonPage show-footer :title="$route.title">
<n-data-table
:loading="loading"
:columns="columns"
:data="data"
:pagination="pagination"
:bordered="false"
/>
</CommonPage>
</template>
<script setup>
import api from './api'
const loading = ref(false)
const columns = ref([
{
title: 'ID',
align: 'center',
key: 'ID',
},
{
title: '头像',
align: 'center',
slot: 'avatar',
render(row) {
return h('img', {
src: row.avatar,
style: {
width: '30px',
height: '30px',
borderRadius: '50%',
},
})
},
},
{
title: '电话',
align: 'center',
key: 'phone',
},
{
title: '用户积分',
align: 'center',
key: 'integral',
},
{
title: '用户豆子',
align: 'center',
key: 'pulse',
},
{
title: '操作',
align: 'center',
slot: 'action',
render(row) {
console.log(row)
},
},
])
const data = ref([])
const pagination = ref({
current: 1,
pageSize: 10,
total: 0,
onChange: (page) => {
pagination.value.page = page
getList()
},
onUpdatePageSize: (pageSize) => {
pagination.value.pageSize = pageSize
pagination.value.page = 1
getList()
},
})
onMounted(() => {
getList()
})
const getList = async () => {
loading.value = true
try {
const res = await api.getUser({
pageNum: pagination.value.current,
pageSize: pagination.value.pageSize,
})
console.log(res)
data.value = res.data.data
} catch (error) {
$message.error(error.msg)
}
loading.value = false
}
</script>
<style lang="scss" scoped></style>

19
src/views/user/route.js Normal file
View File

@@ -0,0 +1,19 @@
const Layout = () => import('@/layout/index.vue')
export default {
name: '用户管理',
path: '/user',
component: Layout,
redirect: '/user_list',
children: [
{
name: 'Userlist',
path: 'user_list',
component: () => import('./index/index.vue'),
meta: {
title: '用户列表',
order: 10,
},
},
],
}

View File

@@ -9,7 +9,7 @@
<p mt-5 text-12 op-60>今天又是元气满满的一天</p>
</div>
<div ml-auto flex items-center>
<n-statistic label="待办" :value="4">
<!-- <n-statistic label="待办" :value="4">
<template #suffix>/ 10</template>
</n-statistic>
<n-statistic label="Stars" ml-80 w-100>
@@ -21,12 +21,12 @@
<a href="https://github.com/zclzone/vue-naive-admin">
<img alt="forks" src="https://badgen.net/github/forks/zclzone/vue-naive-admin" />
</a>
</n-statistic>
</n-statistic> -->
</div>
</div>
</n-card>
<n-card title="项目" size="small" :segmented="true" mt-15 rounded-10>
<!-- <n-card title="项目" size="small" :segmented="true" mt-15 rounded-10>
<template #header-extra>
<n-button text type="primary">更多</n-button>
</template>
@@ -46,7 +46,7 @@
<div h-0 w-300></div>
<div h-0 w-300></div>
</div>
</n-card>
</n-card> -->
</div>
</AppPage>
</template>