feat: vue-mobile => 完成移动端聊天配置功能

This commit is contained in:
RockYang 2023-06-26 18:18:45 +08:00
parent 6a733de556
commit 5187a43543
13 changed files with 189 additions and 36 deletions

1
api/go/.gitignore vendored
View File

@ -16,3 +16,4 @@ tmp
bin bin
data data
config.toml config.toml
static/upload

View File

@ -51,6 +51,9 @@ func (s *AppServer) Init(debug bool) {
s.Engine.Use(authorizeMiddleware(s)) s.Engine.Use(authorizeMiddleware(s))
s.Engine.Use(errorHandler) s.Engine.Use(errorHandler)
//gob.Register(model.User{}) //gob.Register(model.User{})
// 添加静态资源访问
s.Engine.Static("/static", s.AppConfig.StaticDir)
} }
func (s *AppServer) Run(db *gorm.DB) error { func (s *AppServer) Run(db *gorm.DB) error {

View File

@ -18,6 +18,7 @@ func NewDefaultConfig() *types.AppConfig {
Listen: "0.0.0.0:5678", Listen: "0.0.0.0:5678",
ProxyURL: "", ProxyURL: "",
Manager: types.Manager{Username: "admin", Password: "admin123"}, Manager: types.Manager{Username: "admin", Password: "admin123"},
StaticDir: "./static",
Session: types.Session{ Session: types.Session{
SecretKey: utils.RandString(64), SecretKey: utils.RandString(64),

View File

@ -11,6 +11,7 @@ type AppConfig struct {
ProxyURL string ProxyURL string
MysqlDns string // mysql 连接地址 MysqlDns string // mysql 连接地址
Manager Manager // 后台管理员账户信息 Manager Manager // 后台管理员账户信息
StaticDir string // 静态资源目录
} }
// Manager 管理员 // Manager 管理员

View File

@ -289,8 +289,6 @@ func (h *UserHandler) Profile(c *gin.Context) {
} }
userVo.Id = user.Id userVo.Id = user.Id
userVo.CreatedAt = user.CreatedAt.Unix()
userVo.UpdatedAt = user.UpdatedAt.Unix()
resp.SUCCESS(c, userVo) resp.SUCCESS(c, userVo)
} }

1
api/go/static/hello.txt Normal file
View File

@ -0,0 +1 @@
hello, world!

View File

@ -4,16 +4,16 @@ import "chatplus/core/types"
type User struct { type User struct {
BaseVo BaseVo
Username string `json:"username"` Username string `json:"username,omitempty"`
Nickname string `json:"nickname"` Nickname string `json:"nickname,omitempty"`
Avatar string `json:"avatar"` Avatar string `json:"avatar,omitempty"`
Salt string `json:"salt"` // 密码盐 Salt string `json:"salt,omitempty"` // 密码盐
Tokens int64 `json:"tokens"` // 剩余tokens Tokens int64 `json:"tokens,omitempty"` // 剩余tokens
Calls int `json:"calls"` // 剩余对话次数 Calls int `json:"calls,omitempty"` // 剩余对话次数
ChatConfig types.ChatConfig `json:"chat_config"` // 聊天配置 ChatConfig types.ChatConfig `json:"chat_config,omitempty"` // 聊天配置
ChatRoles []string `json:"chat_roles"` // 聊天角色集合 ChatRoles []string `json:"chat_roles,omitempty"` // 聊天角色集合
ExpiredTime int64 `json:"expired_time"` // 账户到期时间 ExpiredTime int64 `json:"expired_time,omitempty"` // 账户到期时间
Status bool `json:"status"` // 当前状态 Status bool `json:"status,omitempty"` // 当前状态
LastLoginAt int64 `json:"last_login_at"` // 最后登录时间 LastLoginAt int64 `json:"last_login_at,omitempty"` // 最后登录时间
LastLoginIp string `json:"last_login_ip"` // 最后登录 IP LastLoginIp string `json:"last_login_ip,omitempty"` // 最后登录 IP
} }

View File

@ -47,7 +47,7 @@ onMounted(() => {
margin-left 5px margin-left 5px
.van-image { .van-image {
width 25px width 32px
img { img {
border-radius 5px border-radius 5px
@ -73,7 +73,7 @@ onMounted(() => {
.content { .content {
word-break break-word; word-break break-word;
padding: 6px 10px; padding: 5px 10px;
background-color: #98E165; background-color: #98E165;
color #444444 color #444444
font-size: 16px font-size: 16px

View File

@ -56,7 +56,7 @@ onMounted(() => {
margin-right 5px margin-right 5px
.van-image { .van-image {
width 25px width 32px
img { img {
border-radius 5px border-radius 5px
@ -92,7 +92,7 @@ onMounted(() => {
overflow-x auto overflow-x auto
min-height 20px; min-height 20px;
word-break break-word; word-break break-word;
padding: 6px 10px; padding: 5px 10px;
color #444444 color #444444
background-color: #ffffff; background-color: #ffffff;
font-size: 16px font-size: 16px

View File

@ -25,6 +25,7 @@ import {
ShareSheet, ShareSheet,
Sticky, Sticky,
SwipeCell, SwipeCell,
Switch,
Tabbar, Tabbar,
TabbarItem, TabbarItem,
TextEllipsis TextEllipsis
@ -56,6 +57,7 @@ app.use(Sticky);
app.use(SwipeCell); app.use(SwipeCell);
app.use(Dialog); app.use(Dialog);
app.use(ShareSheet); app.use(ShareSheet);
app.use(Switch);
app.use(router).use(ElementPlus).mount('#app') app.use(router).use(ElementPlus).mount('#app')

View File

@ -227,20 +227,22 @@ const removeChat = (item) => {
</script> </script>
<style lang="stylus" scoped> <style lang="stylus" scoped>
$fontSize = 16px;
.mobile-chat-list { .mobile-chat-list {
.content { .content {
.van-cell__value { .van-cell__value {
.chat-list-item { .chat-list-item {
display flex display flex
font-size $fontSize
.van-image { .van-image {
width 30px width 32px
height 30px height 32px
} }
.van-ellipsis { .van-ellipsis {
margin-top 4px; margin-top 5px;
margin-left 10px; margin-left 10px;
} }
} }

View File

@ -1,6 +1,33 @@
<template> <template>
<div> <div class="mobile-user-profile container">
<van-nav-bar :title="title"/> <van-nav-bar :title="title"/>
<div class="content">
<van-form @submit="onSubmit">
<van-cell-group inset>
<van-field
v-model="username"
name="用户名"
label="用户名"
placeholder="用户名"
:rules="[{ required: true, message: '请填写用户名' }]"
/>
<van-field
v-model="password"
type="password"
name="密码"
label="密码"
placeholder="密码"
:rules="[{ required: true, message: '请填写密码' }]"
/>
</van-cell-group>
<div style="margin: 16px;">
<van-button round block type="primary" native-type="submit">
提交
</van-button>
</div>
</van-form>
</div>
</div> </div>
</template> </template>

View File

@ -1,15 +1,132 @@
<template> <template>
<div> <div class="mobile-setting container">
<van-nav-bar :title="title"/> <van-nav-bar :title="title"/>
<div class="content">
<van-form @submit="save" v-model="form">
<van-cell-group inset>
<van-field
v-model="form.chat_config.model"
is-link
readonly
label="默认模型"
placeholder=""
@click="showPicker = true"
/>
<van-field
v-model.number="form.chat_config.max_tokens"
name="MaxTokens"
type="number"
label="MaxTokens"
placeholder="每次请求最大 token 数量"
:rules="[{ required: true, message: '请填写 MaxTokens' }]"
/>
<van-field
v-model.number="form.chat_config.temperature"
type="number"
name="Temperature"
label="Temperature"
placeholder="模型温度"
:rules="[{ required: true, message: '请填写 Temperature' }]"
/>
<van-field name="switch" label="聊天记录">
<template #input>
<van-switch v-model="form.chat_config.enable_history"/>
</template>
</van-field>
<van-field name="switch" label="聊天上下文">
<template #input>
<van-switch v-model="form.chat_config.enable_context"/>
</template>
</van-field>
<van-field
v-model="form.chat_config.api_key"
name="API KEY"
label="API KEY"
placeholder="配置自己的 api key"
:rules="[{ required: true, message: '请填写 API KEY' }]"
/>
</van-cell-group>
<div style="margin: 16px;">
<van-button round block type="primary" native-type="submit">
保存
</van-button>
</div>
</van-form>
</div>
<van-popup v-model:show="showPicker" round position="bottom">
<van-picker
:columns="models"
@cancel="showPicker = false"
@confirm="selectModel"
/>
</van-popup>
</div> </div>
</template> </template>
<script setup> <script setup>
import {ref} from "vue"; import {onMounted, ref} from "vue";
import {httpGet, httpPost} from "@/utils/http";
import {showFailToast, showSuccessToast} from "vant";
import {ElMessage} from "element-plus";
const title = ref('聊天设置') const title = ref('聊天设置')
const form = ref({
chat_config: {
model: '',
max_tokens: 0,
enable_context: false,
enable_history: false,
temperature: false,
api_key: ''
}
})
const showPicker = ref(false)
const models = ref([])
onMounted(() => {
//
httpGet('/api/user/profile').then(res => {
console.log(res.data)
form.value = res.data
}).catch(() => {
showFailToast('获取用户信息失败')
});
//
httpGet('/api/admin/config/get?key=system').then(res => {
const mds = res.data.models;
console.log(mds)
mds.forEach(item => {
models.value.push({text: item, value: item})
})
}).catch(e => {
ElMessage.error("加载系统配置失败: " + e.message)
})
})
const selectModel = (item) => {
showPicker.value = false
form.value.chat_config.model = item.selectedValues[0]
}
const save = () => {
httpPost('/api/user/profile/update', form.value).then(() => {
showSuccessToast('保存成功')
}).catch(() => {
showFailToast('保存失败')
})
}
</script> </script>
<style scoped> <style scoped lang="stylus">
.mobile-setting {
.content {
padding-top 60px
}
}
</style> </style>