mirror of
https://gitee.com/bootx/dax-pay-ui.git
synced 2025-09-09 13:40:06 +00:00
feat 用户基础消息修改, 一些报错修改
This commit is contained in:
@@ -5,7 +5,7 @@ VITE_USE_MOCK=true
|
||||
VITE_PUBLIC_PATH=/
|
||||
|
||||
# 跨域代理,您可以配置多个 ,请注意,没有换行符
|
||||
VITE_PROXY=[["/api","http://localhost:9999"],["/upload","http://localhost:3300/upload"]]
|
||||
VITE_PROXY=[["/api","http://localhost:9999"],["/upload","http://localhost:9999/file/upload"]]
|
||||
|
||||
# 控制台不输出console
|
||||
VITE_DROP_CONSOLE=false
|
||||
|
@@ -1,5 +1,8 @@
|
||||
import { defHttp } from '/@/utils/http/axios'
|
||||
import { Result } from '/#/axios'
|
||||
import { Result, UploadFileParams } from '/#/axios'
|
||||
import { UploadApiResult } from '/@/api/sys/model/uploadModel'
|
||||
import { getAppEnvConfig } from '/@/utils/env'
|
||||
const { VITE_GLOB_API_URL } = getAppEnvConfig()
|
||||
|
||||
/**
|
||||
* 获取文件预览地址
|
||||
@@ -29,3 +32,34 @@ export const getFileDownloadUrl = (id) => {
|
||||
params: { id },
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @param params
|
||||
* @param onUploadProgress
|
||||
*/
|
||||
export function uploadFile(params: UploadFileParams, onUploadProgress: (progressEvent: ProgressEvent) => void) {
|
||||
return defHttp.uploadFile<UploadApiResult>(
|
||||
{
|
||||
url: VITE_GLOB_API_URL + '/file/upload',
|
||||
onUploadProgress,
|
||||
},
|
||||
params,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件信息
|
||||
*/
|
||||
export interface UpdateFileInfo {
|
||||
// 文件id
|
||||
id: string
|
||||
// 文件名称
|
||||
fileName: string
|
||||
// 文件后缀
|
||||
fileSuffix: string
|
||||
// 文件类型
|
||||
fileType: string
|
||||
// 文件大小
|
||||
fileSize: number
|
||||
}
|
||||
|
@@ -1,11 +1,7 @@
|
||||
import { defHttp } from '/@/utils/http/axios'
|
||||
import { getMenuListResultModel, MenuAndResource } from './model/menuModel'
|
||||
import { MenuAndResource } from './model/menuModel'
|
||||
import { Result } from '/#/axios'
|
||||
|
||||
enum Api {
|
||||
GetMenuList = '/getMenuList',
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单和权限码
|
||||
*/
|
||||
|
@@ -16,9 +16,16 @@ export interface LoginParams {
|
||||
captcha: string
|
||||
}
|
||||
|
||||
export interface RoleInfo {
|
||||
roleName: string
|
||||
value: string
|
||||
/**
|
||||
* 用户信息(用户详情)
|
||||
*/
|
||||
export interface UserDetails {
|
||||
// 用户id
|
||||
id: number
|
||||
// 名称
|
||||
name: string
|
||||
// 账号
|
||||
username: string
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,3 +41,19 @@ export interface GetUserInfoModel {
|
||||
// 头像
|
||||
avatar: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户基础消息
|
||||
*/
|
||||
export interface UserBaseInfo {
|
||||
// 用户id
|
||||
id: number
|
||||
// 名称
|
||||
name: string
|
||||
// 性别
|
||||
sex: number
|
||||
// 头像
|
||||
avatar: string
|
||||
// 生日
|
||||
birthday: string
|
||||
}
|
||||
|
@@ -1,13 +1,6 @@
|
||||
import { defHttp } from '/@/utils/http/axios'
|
||||
import { LoginParams, GetUserInfoModel } from './model/userModel'
|
||||
|
||||
import { ErrorMessageMode, Result } from '/#/axios'
|
||||
|
||||
enum Api {
|
||||
Logout = '/logout',
|
||||
GetPermCode = '/getPermCode',
|
||||
TestRetry = '/testRetry',
|
||||
}
|
||||
import { LoginParams, GetUserInfoModel, UserBaseInfo, UserDetails } from './model/userModel'
|
||||
import { Result } from '/#/axios'
|
||||
|
||||
/**
|
||||
* 登录接口 返回token
|
||||
@@ -18,6 +11,7 @@ export function loginApi(params: LoginParams) {
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录后获取用户信息
|
||||
*/
|
||||
@@ -26,14 +20,31 @@ export function getUserInfo() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户菜单和资源权限
|
||||
* 获取用户安全信息
|
||||
*/
|
||||
export function getPermissions(clientCode: string) {
|
||||
return defHttp.get<Result<GetUserInfoModel>>({ url: '/role/menu/getPermissions', params: { clientCode } })
|
||||
export function getUserSecurityInfo() {
|
||||
return defHttp.get<Result<UserDetails>>({
|
||||
url: `/user/getUserSecurityInfo`,
|
||||
})
|
||||
}
|
||||
|
||||
export function getPermCode() {
|
||||
return defHttp.get<string[]>({ url: Api.GetPermCode })
|
||||
/**
|
||||
* 获取用户基础信息
|
||||
*/
|
||||
export function getUserBaseInfo() {
|
||||
return defHttp.get<Result<UserBaseInfo>>({
|
||||
url: `/user/getUserBaseInfo`,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户基础信息
|
||||
*/
|
||||
export function updateBaseInfo(data) {
|
||||
return defHttp.post({
|
||||
url: '/user/updateBaseInfo',
|
||||
data: data,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,19 +53,3 @@ export function getPermCode() {
|
||||
export function doLogout() {
|
||||
return defHttp.post({ url: '/token/logout' })
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试重试
|
||||
*/
|
||||
export function testRetry() {
|
||||
return defHttp.get(
|
||||
{ url: Api.TestRetry },
|
||||
{
|
||||
retryRequest: {
|
||||
isOpenRetry: true,
|
||||
count: 5,
|
||||
waitTime: 1000,
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@@ -65,10 +65,15 @@
|
||||
},
|
||||
)
|
||||
|
||||
function handleUploadSuccess({ source }) {
|
||||
/**
|
||||
* 响应
|
||||
* @param source 文件bold内容
|
||||
* @param data 上传成功后的文件信息 见 UpdateFileInfo
|
||||
*/
|
||||
function handleUploadSuccess({ source, data: { data } }) {
|
||||
sourceValue.value = source
|
||||
emit('change', source)
|
||||
createMessage.success(t('component.cropper.uploadSuccess'))
|
||||
emit('change', data, source)
|
||||
createMessage.success('上传成功')
|
||||
}
|
||||
|
||||
expose({ openModal: openModal.bind(null, true), closeModal })
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<BasicModal :footer="null" :title="t('layout.header.lockScreen')" v-bind="$attrs" :class="prefixCls" @register="register">
|
||||
<BasicModal :footer="null" title="锁定屏幕" v-bind="$attrs" :class="prefixCls" @register="register">
|
||||
<div :class="`${prefixCls}__entry`">
|
||||
<div :class="`${prefixCls}__header`">
|
||||
<img :src="avatar" :class="`${prefixCls}__header-img`" />
|
||||
@@ -11,9 +11,7 @@
|
||||
<BasicForm @register="registerForm" />
|
||||
|
||||
<div :class="`${prefixCls}__footer`">
|
||||
<a-button type="primary" block class="mt-2" @click="handleLock">
|
||||
{{ t('layout.header.lockScreenBtn') }}
|
||||
</a-button>
|
||||
<a-button type="primary" block class="mt-2" @click="handleLock"> 锁定 </a-button>
|
||||
</div>
|
||||
</div>
|
||||
</BasicModal>
|
||||
@@ -46,7 +44,7 @@
|
||||
schemas: [
|
||||
{
|
||||
field: 'password',
|
||||
label: t('layout.header.lockScreenPassword'),
|
||||
label: '锁屏密码',
|
||||
colProps: {
|
||||
span: 24,
|
||||
},
|
||||
|
@@ -86,7 +86,7 @@ export function createPermissionGuard(router: Router) {
|
||||
// get userinfo while last fetch time is empty
|
||||
if (userStore.getLastUpdateTime === 0) {
|
||||
try {
|
||||
await userStore.getUserInfoAction()
|
||||
await userStore.refreshUserInfoAction()
|
||||
} catch (err) {
|
||||
next()
|
||||
return
|
||||
|
@@ -14,10 +14,8 @@ import { router } from '/@/router'
|
||||
import { usePermissionStore } from '/@/store/modules/permission'
|
||||
import { RouteRecordRaw } from 'vue-router'
|
||||
import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic'
|
||||
import { isArray } from '/@/utils/is'
|
||||
import { h } from 'vue'
|
||||
import { getFilePreviewUrlPrefix } from '/@/api/common/FileUpload'
|
||||
import headerImg from "/@/assets/images/header.jpg";
|
||||
|
||||
interface UserState {
|
||||
userInfo: Nullable<UserInfo>
|
||||
@@ -68,6 +66,10 @@ export const useUserStore = defineStore({
|
||||
this.roleList = roleList
|
||||
setAuthCache(ROLES_KEY, roleList)
|
||||
},
|
||||
/**
|
||||
* 保存用户信息, 不要直接使用
|
||||
* 使用 UserStoreUtil 中的包装方法来处理
|
||||
*/
|
||||
setUserInfo(info: UserInfo | null) {
|
||||
this.userInfo = info
|
||||
this.lastUpdateTime = new Date().getTime()
|
||||
@@ -102,7 +104,7 @@ export const useUserStore = defineStore({
|
||||
async afterLoginAction(goHome?: boolean) {
|
||||
if (!this.getToken) return null
|
||||
// 获取用户信息
|
||||
await this.getUserInfoAction()
|
||||
await this.refreshUserInfoAction()
|
||||
const sessionTimeout = this.sessionTimeout
|
||||
// 超时
|
||||
if (sessionTimeout) {
|
||||
@@ -122,18 +124,17 @@ export const useUserStore = defineStore({
|
||||
goHome && (await router.replace(PageEnum.BASE_HOME))
|
||||
}
|
||||
},
|
||||
// 获取并存储用户信息
|
||||
async getUserInfoAction() {
|
||||
// 刷新登陆后用户信息
|
||||
async refreshUserInfoAction() {
|
||||
if (!this.getToken) return null
|
||||
const { data: userInfo } = await getUserInfo()
|
||||
// 设置头像
|
||||
const { data: urlPrefix } = await getFilePreviewUrlPrefix()
|
||||
userInfo.avatar = userInfo.avatar ? urlPrefix + userInfo.avatar : ''
|
||||
this.setUserInfo(userInfo)
|
||||
return userInfo
|
||||
},
|
||||
/**
|
||||
* @description: logout
|
||||
* 退出
|
||||
*/
|
||||
async logout(goLogin = false) {
|
||||
if (this.getToken) {
|
||||
|
@@ -89,7 +89,6 @@ const transform: AxiosTransform = {
|
||||
// 请求之前处理config
|
||||
beforeRequestHook: (config, options) => {
|
||||
const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true, urlPrefix } = options
|
||||
|
||||
if (joinPrefix) {
|
||||
config.url = `${urlPrefix}${config.url}`
|
||||
}
|
||||
|
@@ -5,11 +5,8 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { testRetry } from '/@/api/sys/user'
|
||||
// @ts-ignore
|
||||
const handleClick = async () => {
|
||||
await testRetry()
|
||||
}
|
||||
const handleClick = async () => {}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
@@ -68,7 +68,7 @@
|
||||
userStore.setToken(token)
|
||||
|
||||
// 重新获取用户信息和菜单
|
||||
userStore.getUserInfoAction()
|
||||
userStore.refreshUserInfoAction()
|
||||
permissionStore.changePermissionCode()
|
||||
}
|
||||
|
||||
|
@@ -44,7 +44,7 @@
|
||||
userStore.setToken(token)
|
||||
|
||||
// 重新获取用户信息和菜单
|
||||
userStore.getUserInfoAction()
|
||||
userStore.refreshUserInfoAction()
|
||||
refreshMenu()
|
||||
}
|
||||
|
||||
|
@@ -1,91 +1,131 @@
|
||||
<template>
|
||||
<CollapseContainer title="基本设置" :canExpan="false">
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="14">
|
||||
<a-form
|
||||
class="small-from-item"
|
||||
ref="formRef"
|
||||
:validate-trigger="['blur', 'change']"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
:label-col="labelCol"
|
||||
:wrapper-col="wrapperCol"
|
||||
>
|
||||
<a-form-item label="名称" name="name">
|
||||
<a-input v-model:value="form.name" :disabled="!edit" placeholder="请输入名称" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<!-- <BasicForm @register="register" />-->
|
||||
</a-col>
|
||||
<a-col :span="10">
|
||||
<div class="change-avatar">
|
||||
<div class="mb-2">头像</div>
|
||||
<CropperAvatar
|
||||
:uploadApi="uploadApi"
|
||||
:value="avatar"
|
||||
btnText="更换头像"
|
||||
:btnProps="{ preIcon: 'ant-design:cloud-upload-outlined' }"
|
||||
@change="updateAvatar"
|
||||
width="150"
|
||||
/>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-button type="primary" @click="handleSubmit"> 更新基本信息 </a-button>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="14">
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:validate-trigger="['blur', 'change']"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
:label-col="labelCol"
|
||||
:wrapper-col="wrapperCol"
|
||||
>
|
||||
<a-form-item label="名称" name="name">
|
||||
<a-input v-model:value="form.name" :disabled="!edit" placeholder="请输入名称" />
|
||||
</a-form-item>
|
||||
<a-form-item label="性别" name="sex">
|
||||
<a-select style="width: 200px" v-model:value="form.sex" :options="sexList" :disabled="!edit" placeholder="请选择性别" />
|
||||
</a-form-item>
|
||||
<a-form-item label="生日" name="birthday">
|
||||
<a-date-picker placeholder="请选择日期" valueFormat="YYYY-MM-DD" :disabled="!edit" v-model:value="form.birthday" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-col>
|
||||
<a-col :span="10">
|
||||
<div class="change-avatar">
|
||||
<div class="mb-2">头像</div>
|
||||
<CropperAvatar
|
||||
v-if="edit"
|
||||
:uploadApi="uploadFile"
|
||||
:value="avatar"
|
||||
btnText="上传头像"
|
||||
:btnProps="{ preIcon: 'ant-design:cloud-upload-outlined' }"
|
||||
@change="updateAvatar"
|
||||
width="150"
|
||||
/>
|
||||
<img :src="avatar" style="width: 150px" v-else alt="avatar" />
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-button v-if="edit" type="primary" @click="handleOk">更新基础信息</a-button>
|
||||
<a-button v-else @click="edit = true">编辑基础信息</a-button>
|
||||
</a-spin>
|
||||
</CollapseContainer>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { Button, Row, Col } from 'ant-design-vue'
|
||||
import { computed, defineComponent, onMounted, reactive } from 'vue'
|
||||
import { BasicForm, useForm } from '/@/components/Form/index'
|
||||
import headerImg from '/@/assets/images/header.jpg'
|
||||
import { onMounted, reactive } from 'vue'
|
||||
import { CollapseContainer } from '/@/components/Container'
|
||||
import { CropperAvatar } from '/@/components/Cropper'
|
||||
|
||||
import { useMessage } from '/@/hooks/web/useMessage'
|
||||
|
||||
import headerImg from '/@/assets/images/header.jpg'
|
||||
import { accountInfoApi } from '/@/api/demo/account'
|
||||
import { baseSetschemas } from './data'
|
||||
import { useUserStore } from '/@/store/modules/user'
|
||||
import { uploadApi } from '/@/api/sys/upload'
|
||||
import { $ref } from 'vue/macros'
|
||||
import { UserInfo } from '/#/store'
|
||||
import { Rule } from 'ant-design-vue/lib/form'
|
||||
import { FormInstance, Rule } from 'ant-design-vue/lib/form'
|
||||
import { getUserBaseInfo, updateBaseInfo } from '/@/api/sys/user'
|
||||
import { getFilePreviewUrlPrefix, UpdateFileInfo, uploadFile } from '/@/api/common/FileUpload'
|
||||
import { UserBaseInfo } from '/@/api/sys/model/userModel'
|
||||
import { useDict } from '/@/hooks/bootx/useDict'
|
||||
import { LabeledValue } from 'ant-design-vue/lib/select'
|
||||
|
||||
const { createMessage } = useMessage()
|
||||
const { createMessage, createConfirm } = useMessage()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const { dictDropDownNumber } = useDict()
|
||||
let sexList = $ref<LabeledValue[]>()
|
||||
// 表单项标题文字
|
||||
const labelCol = { sm: { span: 3 } }
|
||||
// 表单项内容
|
||||
const wrapperCol = { sm: { span: 12 } }
|
||||
let formRef = $ref<FormInstance>()
|
||||
|
||||
let confirmLoading = $ref(false)
|
||||
let edit = $ref(false)
|
||||
let avatar = $ref(headerImg)
|
||||
let urlPrefix = $ref('')
|
||||
|
||||
// 用户信息
|
||||
let form = $ref({} as UserInfo)
|
||||
let form = $ref<UserBaseInfo>({
|
||||
avatar: '',
|
||||
birthday: '',
|
||||
id: 0,
|
||||
name: '',
|
||||
sex: 0,
|
||||
})
|
||||
const rules = reactive({
|
||||
code: [{ required: true, message: '请输入表单编码' }],
|
||||
name: [{ required: true, message: '请输入表单名称' }],
|
||||
} as Record<string, Rule[]>)
|
||||
|
||||
// onMounted(async () => {
|
||||
// const data = await accountInfoApi()
|
||||
// setFieldsValue(data)
|
||||
// })
|
||||
|
||||
// 头像
|
||||
const avatar = computed(() => {
|
||||
const { avatar } = userStore.getUserInfo
|
||||
return avatar || headerImg
|
||||
onMounted(async () => {
|
||||
// 初始化用户信息
|
||||
await init()
|
||||
})
|
||||
|
||||
// 更新头像
|
||||
function updateAvatar(src: string) {
|
||||
const userinfo = userStore.getUserInfo
|
||||
userinfo.avatar = src
|
||||
userStore.setUserInfo(userinfo)
|
||||
// 基础数据
|
||||
async function init() {
|
||||
confirmLoading = true
|
||||
// 初始化菜单
|
||||
sexList = dictDropDownNumber('Sex')
|
||||
|
||||
const { data: userInfo } = await getUserBaseInfo()
|
||||
// 设置头像
|
||||
const result = await getFilePreviewUrlPrefix()
|
||||
urlPrefix = result.data
|
||||
avatar = userInfo.avatar ? urlPrefix + userInfo.avatar : ''
|
||||
form = userInfo
|
||||
confirmLoading = false
|
||||
}
|
||||
// 上传头像回调
|
||||
function updateAvatar(file: UpdateFileInfo) {
|
||||
console.log(file)
|
||||
form.avatar = file.id
|
||||
}
|
||||
// 更新用户信息
|
||||
async function handleOk() {
|
||||
await formRef.validate()
|
||||
createConfirm({
|
||||
iconType: 'warning',
|
||||
title: '警告',
|
||||
content: '是否更新用户基础信息',
|
||||
onOk: async () => {
|
||||
confirmLoading = true
|
||||
await updateBaseInfo(form)
|
||||
createMessage.success('更新用户信息成功')
|
||||
await userStore.refreshUserInfoAction()
|
||||
confirmLoading = false
|
||||
},
|
||||
})
|
||||
}
|
||||
function handleSubmit() {}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
@@ -1,6 +1,5 @@
|
||||
<template>
|
||||
< forceRender :visible="visible" :maskClosable="true" width="60%" placement="right" :closable="true" @close="visible = false" >
|
||||
<basic-drawer showFooter v-bind="$attrs" title="字典列表" width="60%" :visible="visible" @close="visible = false">
|
||||
<basic-drawer forceRender showFooter v-bind="$attrs" title="字典列表" width="60%" :visible="visible" @close="visible = false">
|
||||
<vxe-toolbar ref="xToolbar" custom :refresh="{ query: queryPage }">
|
||||
<template #buttons>
|
||||
<a-space>
|
||||
|
@@ -9,16 +9,6 @@
|
||||
:closable="true"
|
||||
@close="visible = false"
|
||||
>
|
||||
<basic-drawer
|
||||
forceRender
|
||||
v-bind="$attrs"
|
||||
title="任务执行日志"
|
||||
width="60%"
|
||||
:maskClosable="false"
|
||||
:visible="visible"
|
||||
@close="visible = false"
|
||||
>
|
||||
|
||||
<b-query :query-params="model.queryParam" :fields="fields" @query="queryPage" @reset="resetQueryParams" />
|
||||
<vxe-toolbar ref="xToolbar" custom :refresh="{ query: queryPage }" />
|
||||
<vxe-table row-id="id" ref="xTable" :data="pagination.records" :loading="loading">
|
||||
@@ -49,17 +39,15 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, onMounted, ref } from 'vue'
|
||||
import { nextTick } from 'vue'
|
||||
import { $ref } from 'vue/macros'
|
||||
import { del, page } from './QuartzJobLog.api'
|
||||
import useTablePage from '/@/hooks/bootx/useTablePage'
|
||||
import { VxeTableInstance, VxeToolbarInstance } from 'vxe-table'
|
||||
import BQuery from '/@/components/Bootx/Query/BQuery.vue'
|
||||
import { FormEditType } from '/@/enums/formTypeEnum'
|
||||
import { useMessage } from '/@/hooks/web/useMessage'
|
||||
import { QueryField } from '/@/components/Bootx/Query/Query'
|
||||
import { QuartzJob } from './QuartzJob.api'
|
||||
import BasicDrawer from "/@/components/Drawer/src/BasicDrawer.vue";
|
||||
|
||||
// 使用hooks
|
||||
const { handleTableChange, pageQueryResHandel, resetQueryParams, pagination, pages, model, loading } = useTablePage(queryPage)
|
||||
|
3
types/store.d.ts
vendored
3
types/store.d.ts
vendored
@@ -1,6 +1,5 @@
|
||||
import { ErrorTypeEnum } from '/@/enums/exceptionEnum'
|
||||
import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum'
|
||||
import { RoleInfo } from '/@/api/sys/model/userModel'
|
||||
|
||||
// Lock screen information
|
||||
export interface LockInfo {
|
||||
@@ -40,7 +39,7 @@ export interface UserInfo {
|
||||
name: string
|
||||
// 账号
|
||||
username: string
|
||||
// 头像图片地址
|
||||
// 头像图片id
|
||||
avatar: string
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user