mirror of
https://gitee.com/devlive-community/datacap.git
synced 2024-11-29 18:48:23 +08:00
[Core] Support chatgpt
This commit is contained in:
parent
dc36186d30
commit
e289057d25
1
.java-version
Normal file
1
.java-version
Normal file
@ -0,0 +1 @@
|
|||||||
|
11.0
|
@ -91,6 +91,11 @@
|
|||||||
<artifactId>UserAgentUtils</artifactId>
|
<artifactId>UserAgentUtils</artifactId>
|
||||||
<version>1.21</version>
|
<version>1.21</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.unfbx</groupId>
|
||||||
|
<artifactId>chatgpt-java</artifactId>
|
||||||
|
<version>1.0.4</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.edurt.datacap</groupId>
|
<groupId>io.edurt.datacap</groupId>
|
||||||
<artifactId>datacap-spi</artifactId>
|
<artifactId>datacap-spi</artifactId>
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package io.edurt.datacap.server.body;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class UserQuestionBody
|
||||||
|
{
|
||||||
|
private String question;
|
||||||
|
private String type;
|
||||||
|
}
|
@ -3,6 +3,7 @@ package io.edurt.datacap.server.controller.user;
|
|||||||
import io.edurt.datacap.server.body.FilterBody;
|
import io.edurt.datacap.server.body.FilterBody;
|
||||||
import io.edurt.datacap.server.body.UserNameBody;
|
import io.edurt.datacap.server.body.UserNameBody;
|
||||||
import io.edurt.datacap.server.body.UserPasswordBody;
|
import io.edurt.datacap.server.body.UserPasswordBody;
|
||||||
|
import io.edurt.datacap.server.body.UserQuestionBody;
|
||||||
import io.edurt.datacap.server.common.Response;
|
import io.edurt.datacap.server.common.Response;
|
||||||
import io.edurt.datacap.server.entity.PageEntity;
|
import io.edurt.datacap.server.entity.PageEntity;
|
||||||
import io.edurt.datacap.server.entity.UserEntity;
|
import io.edurt.datacap.server.entity.UserEntity;
|
||||||
@ -18,6 +19,8 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(value = "/api/v1/user")
|
@RequestMapping(value = "/api/v1/user")
|
||||||
public class UserController
|
public class UserController
|
||||||
@ -49,9 +52,21 @@ public class UserController
|
|||||||
return this.userService.changeUsername(configure);
|
return this.userService.changeUsername(configure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PutMapping(value = "changeThirdConfigure")
|
||||||
|
public Response<Long> changeThirdConfigure(@Validated @RequestBody Map<String, Map<String, Object>> configure)
|
||||||
|
{
|
||||||
|
return this.userService.changeThirdConfigure(configure);
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping(value = "log")
|
@PostMapping(value = "log")
|
||||||
public Response<PageEntity<UserLogEntity>> getAllLogByFilter(@RequestBody FilterBody filter)
|
public Response<PageEntity<UserLogEntity>> getAllLogByFilter(@RequestBody FilterBody filter)
|
||||||
{
|
{
|
||||||
return this.userLogService.getAllByFilter(filter);
|
return this.userLogService.getAllByFilter(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "startChat")
|
||||||
|
public Response<Object> startChat(@RequestBody UserQuestionBody configure)
|
||||||
|
{
|
||||||
|
return this.userService.startChat(configure);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,9 @@ public class UserEntity
|
|||||||
@Column(name = "password")
|
@Column(name = "password")
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
|
@Column(name = "third_configure")
|
||||||
|
private String thirdConfigure;
|
||||||
|
|
||||||
@Column(name = "create_time", columnDefinition = "datetime(5) default CURRENT_TIMESTAMP()")
|
@Column(name = "create_time", columnDefinition = "datetime(5) default CURRENT_TIMESTAMP()")
|
||||||
private Timestamp createTime;
|
private Timestamp createTime;
|
||||||
|
|
||||||
|
@ -2,10 +2,13 @@ package io.edurt.datacap.server.service;
|
|||||||
|
|
||||||
import io.edurt.datacap.server.body.UserNameBody;
|
import io.edurt.datacap.server.body.UserNameBody;
|
||||||
import io.edurt.datacap.server.body.UserPasswordBody;
|
import io.edurt.datacap.server.body.UserPasswordBody;
|
||||||
|
import io.edurt.datacap.server.body.UserQuestionBody;
|
||||||
import io.edurt.datacap.server.common.JwtResponse;
|
import io.edurt.datacap.server.common.JwtResponse;
|
||||||
import io.edurt.datacap.server.common.Response;
|
import io.edurt.datacap.server.common.Response;
|
||||||
import io.edurt.datacap.server.entity.UserEntity;
|
import io.edurt.datacap.server.entity.UserEntity;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public interface UserService
|
public interface UserService
|
||||||
{
|
{
|
||||||
Response<UserEntity> saveOrUpdate(UserEntity configure);
|
Response<UserEntity> saveOrUpdate(UserEntity configure);
|
||||||
@ -17,4 +20,8 @@ public interface UserService
|
|||||||
Response<Long> changePassword(UserPasswordBody configure);
|
Response<Long> changePassword(UserPasswordBody configure);
|
||||||
|
|
||||||
Response<Long> changeUsername(UserNameBody configure);
|
Response<Long> changeUsername(UserNameBody configure);
|
||||||
|
|
||||||
|
Response<Long> changeThirdConfigure(Map<String, Map<String, Object>> configure);
|
||||||
|
|
||||||
|
Response<Object> startChat(UserQuestionBody configure);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
package io.edurt.datacap.server.service.impl;
|
package io.edurt.datacap.server.service.impl;
|
||||||
|
|
||||||
|
import com.unfbx.chatgpt.OpenAiClient;
|
||||||
|
import com.unfbx.chatgpt.entity.chat.ChatCompletion;
|
||||||
|
import com.unfbx.chatgpt.entity.chat.ChatCompletionResponse;
|
||||||
|
import com.unfbx.chatgpt.entity.chat.Message;
|
||||||
import io.edurt.datacap.server.audit.AuditUserLog;
|
import io.edurt.datacap.server.audit.AuditUserLog;
|
||||||
import io.edurt.datacap.server.body.UserNameBody;
|
import io.edurt.datacap.server.body.UserNameBody;
|
||||||
import io.edurt.datacap.server.body.UserPasswordBody;
|
import io.edurt.datacap.server.body.UserPasswordBody;
|
||||||
|
import io.edurt.datacap.server.body.UserQuestionBody;
|
||||||
|
import io.edurt.datacap.server.common.JSON;
|
||||||
import io.edurt.datacap.server.common.JwtResponse;
|
import io.edurt.datacap.server.common.JwtResponse;
|
||||||
import io.edurt.datacap.server.common.Response;
|
import io.edurt.datacap.server.common.Response;
|
||||||
import io.edurt.datacap.server.common.ServiceState;
|
import io.edurt.datacap.server.common.ServiceState;
|
||||||
@ -14,6 +20,7 @@ import io.edurt.datacap.server.security.JwtService;
|
|||||||
import io.edurt.datacap.server.security.UserDetailsService;
|
import io.edurt.datacap.server.security.UserDetailsService;
|
||||||
import io.edurt.datacap.server.service.UserService;
|
import io.edurt.datacap.server.service.UserService;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
@ -21,8 +28,11 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
|||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -134,4 +144,54 @@ public class UserServiceImpl
|
|||||||
this.userRepository.save(user);
|
this.userRepository.save(user);
|
||||||
return Response.success(user.getId());
|
return Response.success(user.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response<Long> changeThirdConfigure(Map<String, Map<String, Object>> configure)
|
||||||
|
{
|
||||||
|
Optional<UserEntity> userOptional = this.userRepository.findById(UserDetailsService.getUser().getId());
|
||||||
|
if (!userOptional.isPresent()) {
|
||||||
|
return Response.failure(ServiceState.USER_NOT_FOUND);
|
||||||
|
}
|
||||||
|
UserEntity user = userOptional.get();
|
||||||
|
user.setThirdConfigure(JSON.toJSON(configure));
|
||||||
|
this.userRepository.save(user);
|
||||||
|
return Response.success(user.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response<Object> startChat(UserQuestionBody configure)
|
||||||
|
{
|
||||||
|
Optional<UserEntity> userOptional = this.userRepository.findById(UserDetailsService.getUser().getId());
|
||||||
|
if (!userOptional.isPresent()) {
|
||||||
|
return Response.failure(ServiceState.USER_NOT_FOUND);
|
||||||
|
}
|
||||||
|
if (!configure.getType().equals("ChatGPT")) {
|
||||||
|
return Response.failure("Not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
UserEntity user = userOptional.get();
|
||||||
|
List<String> content = new ArrayList<>();
|
||||||
|
if (StringUtils.isNotEmpty(user.getThirdConfigure())) {
|
||||||
|
Map<String, Object> configureMap = JSON.toMap(user.getThirdConfigure());
|
||||||
|
if (configureMap.containsKey("chatgpt")) {
|
||||||
|
Map<String, Object> chatGPTMap = (Map<String, Object>) configureMap.get("chatgpt");
|
||||||
|
if (chatGPTMap.containsKey("token")) {
|
||||||
|
String token = (String) chatGPTMap.get("token");
|
||||||
|
if (StringUtils.isNotEmpty(token)) {
|
||||||
|
OpenAiClient openAiClient = OpenAiClient.builder()
|
||||||
|
.apiKey(token)
|
||||||
|
.build();
|
||||||
|
Message message = Message.builder()
|
||||||
|
.role(Message.Role.USER)
|
||||||
|
.content(configure.getQuestion())
|
||||||
|
.build();
|
||||||
|
ChatCompletion chatCompletion = ChatCompletion.builder().messages(Arrays.asList(message)).build();
|
||||||
|
ChatCompletionResponse chatCompletionResponse = openAiClient.chatCompletion(chatCompletion);
|
||||||
|
chatCompletionResponse.getChoices().forEach(e -> content.add(e.getMessage().getContent()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Response.success(content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
alter table users
|
||||||
|
add third_configure text;
|
1
core/datacap-server/src/main/schema/1.7.0/update.sql
Normal file
1
core/datacap-server/src/main/schema/1.7.0/update.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
source schema/users.sql;
|
@ -80,5 +80,8 @@ export default {
|
|||||||
ssl: 'SSL',
|
ssl: 'SSL',
|
||||||
id: 'ID',
|
id: 'ID',
|
||||||
authority: 'Authority',
|
authority: 'Authority',
|
||||||
code: 'Code'
|
code: 'Code',
|
||||||
|
chatgpt: 'ChatGPT',
|
||||||
|
send: 'Send',
|
||||||
|
token: 'Token'
|
||||||
}
|
}
|
||||||
|
@ -81,4 +81,7 @@ export default {
|
|||||||
id: 'ID',
|
id: 'ID',
|
||||||
authority: '权限',
|
authority: '权限',
|
||||||
code: '代码',
|
code: '代码',
|
||||||
|
chatgpt: 'ChatGPT',
|
||||||
|
send: '发送',
|
||||||
|
token: '密钥'
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,17 @@
|
|||||||
export interface User
|
export interface User
|
||||||
{
|
{
|
||||||
username: string;
|
username: string;
|
||||||
|
thirdConfigure: { chatgpt: ThirdConfigure };
|
||||||
createTime?: string;
|
createTime?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class UserQuestion
|
||||||
|
{
|
||||||
|
question: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ThirdConfigure
|
||||||
|
{
|
||||||
|
token = '';
|
||||||
|
}
|
||||||
|
@ -182,6 +182,13 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
},
|
},
|
||||||
component: () => import("../views/pages/profile/ProfileLog.vue")
|
component: () => import("../views/pages/profile/ProfileLog.vue")
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'chatgpt',
|
||||||
|
meta: {
|
||||||
|
roles: ['Admin', 'User']
|
||||||
|
},
|
||||||
|
component: () => import("../views/pages/profile/ProfileChatGPT.vue")
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'account',
|
path: 'account',
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -3,6 +3,7 @@ import {ResponseModel} from "@/model/ResponseModel";
|
|||||||
import {UserPassword} from "@/model/UserPassword";
|
import {UserPassword} from "@/model/UserPassword";
|
||||||
import {UserName} from "@/model/UserName";
|
import {UserName} from "@/model/UserName";
|
||||||
import {Filter} from "@/model/Filter";
|
import {Filter} from "@/model/Filter";
|
||||||
|
import {UserQuestion} from "@/model/User";
|
||||||
|
|
||||||
const baseUrl = "/api/v1/user";
|
const baseUrl = "/api/v1/user";
|
||||||
|
|
||||||
@ -23,6 +24,16 @@ class UserService
|
|||||||
return new HttpCommon().put(baseUrl + '/changeUsername', configure);
|
return new HttpCommon().put(baseUrl + '/changeUsername', configure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changeThirdConfigure(configure: any): Promise<ResponseModel>
|
||||||
|
{
|
||||||
|
return new HttpCommon().put(baseUrl + '/changeThirdConfigure', configure);
|
||||||
|
}
|
||||||
|
|
||||||
|
startChat(configure: UserQuestion): Promise<ResponseModel>
|
||||||
|
{
|
||||||
|
return new HttpCommon().post(baseUrl + '/startChat', configure);
|
||||||
|
}
|
||||||
|
|
||||||
getLogs(filter: Filter): Promise<ResponseModel>
|
getLogs(filter: Filter): Promise<ResponseModel>
|
||||||
{
|
{
|
||||||
return new HttpCommon().post(baseUrl + '/log', filter);
|
return new HttpCommon().post(baseUrl + '/log', filter);
|
||||||
|
@ -0,0 +1,142 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<Card style="width:100%; minHeight: 150px;">
|
||||||
|
<template #title>
|
||||||
|
{{ $t('common.chatgpt') }}
|
||||||
|
</template>
|
||||||
|
<template #extra>
|
||||||
|
<Tooltip :content="$t('common.settings')" transfer>
|
||||||
|
<Button type="primary" size="small" shape="circle" icon="ios-cog" @click="handlerVisibleDetail(true)"></Button>
|
||||||
|
</Tooltip>
|
||||||
|
</template>
|
||||||
|
<div>
|
||||||
|
<Layout>
|
||||||
|
<Content style="padding: 24px 50px;">
|
||||||
|
<Input v-model="userQuestionResponse" :disabled="!userInfo?.thirdConfigure?.chatgpt?.token" type="textarea" :rows="10"/>
|
||||||
|
</Content>
|
||||||
|
<Footer>
|
||||||
|
<Row>
|
||||||
|
<Col span="20">
|
||||||
|
<Input v-model="userQuestion.question" :disabled="!userInfo?.thirdConfigure?.chatgpt?.token" type="textarea" :autosize="{minRows: 2,maxRows: 5}"/>
|
||||||
|
</Col>
|
||||||
|
<Col span="2" offset="1">
|
||||||
|
<Button :disabled="!userInfo?.thirdConfigure?.chatgpt?.token" type="primary" icon="md-send"
|
||||||
|
:loading="startChatLoading" @click="handlerStartChat()">{{ $t('common.send') }}
|
||||||
|
</Button>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Footer>
|
||||||
|
</Layout>
|
||||||
|
</div>
|
||||||
|
<Spin size="large" fix :show="loading"></Spin>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Modal v-if="visibleModel" v-model="visibleModel" :title="$t('common.chatgpt') +' ' + $t('common.settings')"
|
||||||
|
:mask-closable="false" :closable="false">
|
||||||
|
<Form :label-width="80">
|
||||||
|
<FormItem :label="$t('common.token')">
|
||||||
|
<Input v-model="userInfo.thirdConfigure.chatgpt.token" type="text" placeholder="example: sk-xxxx"/>
|
||||||
|
</FormItem>
|
||||||
|
</Form>
|
||||||
|
<template #footer>
|
||||||
|
<Space>
|
||||||
|
<Button type="error" @click="handlerVisibleDetail(false)">{{ $t('common.cancel') }}</Button>
|
||||||
|
<Button type="primary" icon="md-document" @click="handlerSave()">{{ $t('common.save') }}</Button>
|
||||||
|
</Space>
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import {defineComponent} from 'vue';
|
||||||
|
import UserService from "@/services/UserService";
|
||||||
|
import {ThirdConfigure, User, UserQuestion} from '@/model/User';
|
||||||
|
|
||||||
|
const userQuestion = new UserQuestion();
|
||||||
|
userQuestion.type = 'ChatGPT';
|
||||||
|
export default defineComponent({
|
||||||
|
setup()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
userQuestion
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created()
|
||||||
|
{
|
||||||
|
this.handlerInitialize()
|
||||||
|
},
|
||||||
|
data()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
visibleModel: false,
|
||||||
|
startChatLoading: false,
|
||||||
|
userInfo: null as User,
|
||||||
|
userQuestionResponse: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handlerInitialize()
|
||||||
|
{
|
||||||
|
this.loading = true;
|
||||||
|
UserService.getInfo()
|
||||||
|
.then(response => {
|
||||||
|
if (response.status) {
|
||||||
|
this.userInfo = response.data;
|
||||||
|
// If the initialization property has not been set
|
||||||
|
if (!this.userInfo.thirdConfigure) {
|
||||||
|
this.userInfo.thirdConfigure = {
|
||||||
|
chatgpt: new ThirdConfigure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.userInfo.thirdConfigure = JSON.parse(this.userInfo.thirdConfigure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handlerVisibleDetail(value: boolean)
|
||||||
|
{
|
||||||
|
this.visibleModel = value;
|
||||||
|
if (!value) {
|
||||||
|
this.handlerInitialize();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handlerSave()
|
||||||
|
{
|
||||||
|
UserService.changeThirdConfigure(this.userInfo.thirdConfigure)
|
||||||
|
.then(response => {
|
||||||
|
this.$Message.success(response.message);
|
||||||
|
this.handlerVisibleDetail(false);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handlerStartChat()
|
||||||
|
{
|
||||||
|
this.startChatLoading = true;
|
||||||
|
UserService.startChat(this.userQuestion)
|
||||||
|
.then(response => {
|
||||||
|
if (response.status) {
|
||||||
|
this.userQuestionResponse = response.data;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.$Message.error(response.message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.startChatLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.content {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
}
|
||||||
|
</style>
|
@ -20,6 +20,11 @@
|
|||||||
<Icon type="md-egg"/>
|
<Icon type="md-egg"/>
|
||||||
{{ $t('setting.log') }}
|
{{ $t('setting.log') }}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem name="setting_chatgpt" to="/profile/chatgpt">
|
||||||
|
<Icon type="md-chatbubbles"/>
|
||||||
|
{{ $t('common.chatgpt') }}
|
||||||
|
<Badge text="new"></Badge>
|
||||||
|
</MenuItem>
|
||||||
<MenuItem name="security" to="/profile/account">
|
<MenuItem name="security" to="/profile/account">
|
||||||
<Icon type="ios-contact"/>
|
<Icon type="ios-contact"/>
|
||||||
{{ $t('setting.accountSetting') }}
|
{{ $t('setting.accountSetting') }}
|
||||||
|
Loading…
Reference in New Issue
Block a user