mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 16:23:42 +08:00 
			
		
		
		
	feat: finish adding chat role to user function
This commit is contained in:
		@@ -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>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user