mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-17 16:56:38 +08:00
feat: finish adding chat role to user function
This commit is contained in:
parent
a688d3feb5
commit
4595dcb7ed
@ -2,6 +2,7 @@ package handler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"chatplus/core"
|
"chatplus/core"
|
||||||
|
"chatplus/core/types"
|
||||||
"chatplus/store/model"
|
"chatplus/store/model"
|
||||||
"chatplus/store/vo"
|
"chatplus/store/vo"
|
||||||
"chatplus/utils"
|
"chatplus/utils"
|
||||||
@ -76,3 +77,29 @@ func (h *ChatRoleHandler) List(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
resp.SUCCESS(c, roleVos)
|
resp.SUCCESS(c, roleVos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddRole 为用户添加角色
|
||||||
|
func (h *ChatRoleHandler) AddRole(c *gin.Context) {
|
||||||
|
user, err := utils.GetLoginUser(c, h.db)
|
||||||
|
if err != nil {
|
||||||
|
resp.NotAuth(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var data struct {
|
||||||
|
Keys []string `json:"keys"`
|
||||||
|
}
|
||||||
|
if err = c.ShouldBindJSON(&data); err != nil {
|
||||||
|
resp.ERROR(c, types.InvalidArgs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res := h.db.Model(&model.User{}).Where("id = ?", user.Id).UpdateColumn("chat_roles_json", utils.JsonEncode(data.Keys))
|
||||||
|
if res.Error != nil {
|
||||||
|
logger.Error("添加应用失败:", err)
|
||||||
|
resp.ERROR(c, "更新数据库失败!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.SUCCESS(c)
|
||||||
|
}
|
||||||
|
@ -185,6 +185,7 @@ func main() {
|
|||||||
fx.Invoke(func(s *core.AppServer, h *handler.ChatRoleHandler) {
|
fx.Invoke(func(s *core.AppServer, h *handler.ChatRoleHandler) {
|
||||||
group := s.Engine.Group("/api/role/")
|
group := s.Engine.Group("/api/role/")
|
||||||
group.GET("list", h.List)
|
group.GET("list", h.List)
|
||||||
|
group.POST("add", h.AddRole)
|
||||||
}),
|
}),
|
||||||
fx.Invoke(func(s *core.AppServer, h *handler.UserHandler) {
|
fx.Invoke(func(s *core.AppServer, h *handler.UserHandler) {
|
||||||
group := s.Engine.Group("/api/user/")
|
group := s.Engine.Group("/api/user/")
|
||||||
|
@ -36,7 +36,7 @@ func CopyObject(src interface{}, dst interface{}) error {
|
|||||||
pType := reflect.New(value.Type())
|
pType := reflect.New(value.Type())
|
||||||
v2 := pType.Interface()
|
v2 := pType.Interface()
|
||||||
err := json.Unmarshal([]byte(v.String()), &v2)
|
err := json.Unmarshal([]byte(v.String()), &v2)
|
||||||
if err == nil {
|
if err == nil && v2 != nil {
|
||||||
value.Set(reflect.ValueOf(v2).Elem())
|
value.Set(reflect.ValueOf(v2).Elem())
|
||||||
}
|
}
|
||||||
// map, struct, slice to string
|
// map, struct, slice to string
|
||||||
|
108
web/src/components/LoginDialog.vue
Normal file
108
web/src/components/LoginDialog.vue
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
class="login-dialog"
|
||||||
|
v-model="showDialog"
|
||||||
|
:close-on-click-modal="true"
|
||||||
|
:show-close="true"
|
||||||
|
:before-close="close"
|
||||||
|
:width="400"
|
||||||
|
title="用户登录"
|
||||||
|
>
|
||||||
|
<div class="form">
|
||||||
|
<el-form label-width="65px">
|
||||||
|
<el-form-item>
|
||||||
|
<template #label>
|
||||||
|
<div class="label">
|
||||||
|
<el-icon>
|
||||||
|
<User/>
|
||||||
|
</el-icon>
|
||||||
|
<span>账号</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default>
|
||||||
|
<el-input v-model="username" placeholder="手机号码"/>
|
||||||
|
</template>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<template #label>
|
||||||
|
<div class="label">
|
||||||
|
<el-icon>
|
||||||
|
<Lock/>
|
||||||
|
</el-icon>
|
||||||
|
<span>密码</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default>
|
||||||
|
<el-input v-model="password" type="password" placeholder="密码"/>
|
||||||
|
</template>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<div class="login-btn">
|
||||||
|
<el-button type="primary" @click="submit" round>登录</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {computed, ref} from "vue"
|
||||||
|
import {httpPost} from "@/utils/http";
|
||||||
|
import {ElMessage} from "element-plus";
|
||||||
|
import {setUserToken} from "@/store/session";
|
||||||
|
import {validateMobile} from "@/utils/validate";
|
||||||
|
import {Lock, User} from "@element-plus/icons-vue";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const props = defineProps({
|
||||||
|
show: Boolean,
|
||||||
|
});
|
||||||
|
const showDialog = computed(() => {
|
||||||
|
return props.show
|
||||||
|
})
|
||||||
|
const username = ref("")
|
||||||
|
const password = ref("")
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const emits = defineEmits(['hide']);
|
||||||
|
const submit = function () {
|
||||||
|
if (!validateMobile(username.value)) {
|
||||||
|
return ElMessage.error('请输入合法的手机号');
|
||||||
|
}
|
||||||
|
if (password.value.trim() === '') {
|
||||||
|
return ElMessage.error('请输入密码');
|
||||||
|
}
|
||||||
|
|
||||||
|
httpPost('/api/user/login', {username: username.value.trim(), password: password.value.trim()}).then((res) => {
|
||||||
|
setUserToken(res.data)
|
||||||
|
ElMessage.success("登录成功!")
|
||||||
|
emits("hide")
|
||||||
|
}).catch((e) => {
|
||||||
|
ElMessage.error('登录失败,' + e.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const close = function () {
|
||||||
|
emits('hide', false);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
.login-dialog {
|
||||||
|
border-radius 20px
|
||||||
|
|
||||||
|
.label {
|
||||||
|
.el-icon {
|
||||||
|
font-size 16px
|
||||||
|
margin-right 6px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn {
|
||||||
|
text-align center
|
||||||
|
padding-top 10px
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
width 50%
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -4,14 +4,21 @@
|
|||||||
AI 助手应用中心
|
AI 助手应用中心
|
||||||
</div>
|
</div>
|
||||||
<div class="inner" :style="{height: listBoxHeight + 'px'}">
|
<div class="inner" :style="{height: listBoxHeight + 'px'}">
|
||||||
<ItemList :items="list" v-if="list.length > 0" gap="20" width="250">
|
<ItemList :items="list" v-if="list.length > 0" :gap="20" :width="250">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<div class="app-item" :style="{width: scope.width+'px'}">
|
<div class="app-item" :style="{width: scope.width+'px'}">
|
||||||
<el-image :src="scope.item.icon" fit="cover" :style="{height: scope.width+'px'}"/>
|
<el-image :src="scope.item.icon" fit="cover" :style="{height: scope.width+'px'}"/>
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<span class="name">{{ scope.item.name }}</span>
|
<span class="name">{{ scope.item.name }}</span>
|
||||||
<div class="opt">
|
<div class="opt">
|
||||||
<el-button size="small"
|
|
||||||
|
<el-button v-if="hasRole(scope.item.key)" size="small" type="danger">
|
||||||
|
<el-icon>
|
||||||
|
<Delete/>
|
||||||
|
</el-icon>
|
||||||
|
<span>移除应用</span>
|
||||||
|
</el-button>
|
||||||
|
<el-button v-else size="small"
|
||||||
style="--el-color-primary:#009999"
|
style="--el-color-primary:#009999"
|
||||||
@click="addRole(scope.item)">
|
@click="addRole(scope.item)">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
@ -26,34 +33,57 @@
|
|||||||
</template>
|
</template>
|
||||||
</ItemList>
|
</ItemList>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<login-dialog :show="showLoginDialog" @hide="showLoginDialog = false"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {onMounted, ref} from "vue"
|
import {onMounted, ref} from "vue"
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
import {httpGet} from "@/utils/http";
|
import {httpGet, httpPost} from "@/utils/http";
|
||||||
import ItemList from "@/components/ItemList.vue";
|
import ItemList from "@/components/ItemList.vue";
|
||||||
import {Plus} from "@element-plus/icons-vue";
|
import {Delete, Plus} from "@element-plus/icons-vue";
|
||||||
|
import LoginDialog from "@/components/LoginDialog.vue";
|
||||||
|
import {checkSession} from "@/action/session";
|
||||||
|
import {arrayContains} from "@/utils/libs";
|
||||||
|
|
||||||
const listBoxHeight = window.innerHeight - 97
|
const listBoxHeight = window.innerHeight - 97
|
||||||
const list = ref([])
|
const list = ref([])
|
||||||
|
const showLoginDialog = ref(false)
|
||||||
|
const roles = ref([])
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
httpGet("/api/role/list?all=true").then((res) => {
|
httpGet("/api/role/list?all=true").then((res) => {
|
||||||
const data = res.data
|
list.value = res.data
|
||||||
for (let i = 0; i < data.length; i++) {
|
|
||||||
if (data[i].key === 'gpt') {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
list.value.push(data[i])
|
|
||||||
}
|
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
ElMessage.error("获取应用失败:" + e.message)
|
ElMessage.error("获取应用失败:" + e.message)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
checkSession().then(user => {
|
||||||
|
roles.value = user.chat_roles
|
||||||
|
}).catch(() => {
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const addRole = (row) => {
|
const addRole = (row) => {
|
||||||
|
checkSession().then(() => {
|
||||||
|
const exists = arrayContains(roles.value, row.key, (v1, v2) => v1 === v2)
|
||||||
|
if (exists) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
roles.value.push(row.key)
|
||||||
|
httpPost("/api/role/add", {keys: roles.value}).then(() => {
|
||||||
|
ElMessage.success("添加应用成功!")
|
||||||
|
}).catch(e => {
|
||||||
|
ElMessage.error("添加应用失败:" + e.message)
|
||||||
|
})
|
||||||
|
}).catch(() => {
|
||||||
|
showLoginDialog.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasRole = (roleKey) => {
|
||||||
|
return arrayContains(roles.value, roleKey, (v1, v2) => v1 === v2)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user