opt: adjust ItemList component styles

This commit is contained in:
RockYang 2023-10-15 15:47:42 +08:00
parent 7d1d88a32f
commit a688d3feb5
11 changed files with 195 additions and 105 deletions

View File

@ -145,7 +145,10 @@ func authorizeMiddleware(s *AppServer, client *redis.Client) gin.HandlerFunc {
c.Request.URL.Path == "/api/mj/notify" ||
c.Request.URL.Path == "/api/chat/history" ||
c.Request.URL.Path == "/api/chat/detail" ||
c.Request.URL.Path == "/api/role/list" ||
c.Request.URL.Path == "/api/mj/jobs" ||
c.Request.URL.Path == "/api/mj/proxy" ||
c.Request.URL.Path == "/api/sd/jobs" ||
strings.HasPrefix(c.Request.URL.Path, "/api/sms/") ||
strings.HasPrefix(c.Request.URL.Path, "/api/captcha/") ||
strings.HasPrefix(c.Request.URL.Path, "/static/") ||

View File

@ -48,13 +48,15 @@ func (h *ChatRoleHandler) List(c *gin.Context) {
return
}
user, err := utils.GetLoginUser(c, h.db)
if err != nil {
userId := h.GetInt(c, "user_id", 0)
if userId == 0 {
resp.NotAuth(c)
return
}
var user model.User
h.db.First(&user, userId)
var roleKeys []string
err = utils.JsonDecode(user.ChatRoles, &roleKeys)
err := utils.JsonDecode(user.ChatRoles, &roleKeys)
if err != nil {
resp.ERROR(c, "角色解析失败!")
return

View File

@ -14,12 +14,59 @@
.inner {
display flex
color #ffffff
padding 20px;
padding 15px;
overflow-y visible
overflow-x hidden
.left-menu {
width 160px
.list-box {
.app-item {
border 1px solid #666666
border-radius 6px
overflow hidden
transition: all 0.3s ease; /* */
.el-image {
padding 6px
.el-image__inner {
border-radius 10px
}
}
.title {
display flex
padding 10px
.name {
width 100%
text-align left
font-size 16px
font-weight bold
color #47fff1
}
.opt {
position: relative;
top -5px
}
}
.hello-msg {
overflow: hidden;
white-space normal
text-overflow: ellipsis;
height 60px
padding 10px
font-size 14px
color #999999
}
&:hover {
box-shadow: 0 0 10px rgba(71, 255, 241, 0.6); /* */
transform: translateY(-10px); /* 10 */
}
}
}
}
}

View File

@ -1,96 +1,115 @@
.task-list-box {
width: 100%;
padding: 10px;
color: #fff;
overflow-x: hidden;
width: 100%;
padding: 10px;
color: #fff;
overflow-x: hidden;
}
.task-list-box .running-job-list .job-item {
width: 100%;
padding: 2px;
background-color: #555;
width: 100%;
padding: 2px;
background-color: #555;
}
.task-list-box .running-job-list .job-item .job-item-inner {
position: relative;
height: 100%;
overflow: hidden;
position: relative;
height: 100%;
overflow: hidden;
}
.task-list-box .running-job-list .job-item .job-item-inner .progress {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
}
.task-list-box .running-job-list .job-item .job-item-inner .progress span {
font-size: 20px;
color: #fff;
font-size: 20px;
color: #fff;
}
.task-list-box .finish-job-list .job-item {
width: 100%;
height: 100%;
width: 100%;
height: 100%;
}
.task-list-box .finish-job-list .job-item .opt .opt-line {
margin: 6px 0;
margin: 6px 0;
}
.task-list-box .finish-job-list .job-item .opt .opt-line ul {
display: flex;
flex-flow: row;
display: flex;
flex-flow: row;
}
.task-list-box .finish-job-list .job-item .opt .opt-line ul li {
margin-right: 10px;
margin-right: 10px;
}
.task-list-box .finish-job-list .job-item .opt .opt-line ul li a {
padding: 3px 0;
width: 44px;
text-align: center;
border-radius: 5px;
display: block;
cursor: pointer;
background-color: #4e5058;
color: #fff;
padding: 3px 0;
width: 44px;
text-align: center;
border-radius: 5px;
display: block;
cursor: pointer;
background-color: #4e5058;
color: #fff;
}
.task-list-box .finish-job-list .job-item .opt .opt-line ul li a:hover {
background-color: #6d6f78;
background-color: #6d6f78;
}
.task-list-box .finish-job-list .job-item .opt .opt-line ul .show-prompt {
font-size: 20px;
cursor: pointer;
font-size: 20px;
cursor: pointer;
}
.task-list-box .el-image {
width: 100%;
height: 100%;
max-height: 240px;
width: 100%;
height: 100%;
max-height: 240px;
}
.task-list-box .el-image img {
height: 240px;
height: 240px;
}
.task-list-box .el-image .el-image-viewer__wrapper img {
width: auto;
height: auto;
width: auto;
height: auto;
}
.task-list-box .el-image .image-slot {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
height: 100%;
min-height: 200px;
color: #fff;
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
height: 100%;
min-height: 200px;
color: #fff;
}
.task-list-box .el-image .image-slot .iconfont {
font-size: 50px;
margin-bottom: 10px;
font-size: 50px;
margin-bottom: 10px;
}
.task-list-box .el-image.upscale {
max-height: 304px;
max-height: 312px;
}
.task-list-box .el-image.upscale img {
height: 304px;
height: 312px;
}
.task-list-box .el-image.upscale .el-image-viewer__wrapper img {
width: auto;
height: auto;
width: auto;
height: auto;
}

View File

@ -40,6 +40,10 @@
.job-item {
width 100%
height 100%
border 1px solid #666666
padding 6px
overflow hidden
border-radius 6px
.opt {
.opt-line {
@ -54,7 +58,7 @@
a {
padding 3px 0
width 44px
width 40px
text-align center
border-radius 5px
display block
@ -113,10 +117,10 @@
}
.el-image.upscale {
max-height 304px
max-height 310px
img {
height 304px
height 310px
}
.el-image-viewer__wrapper {

View File

@ -5,11 +5,11 @@
class="list-item"
v-for="(item, index) in items"
:key="index"
:style="{width:itemWidth + 'px', marginBottom: margin*2+'px'}"
:style="{width:itemWidth + 'px'}"
>
<div :style="{marginLeft: margin+'px', marginRight: margin+'px'}">
<div class="item-inner" :style="{padding: gap/2+'px'}">
<div class="item-wrapper">
<slot :item="item" :index="index"></slot>
<slot :item="item" :index="index" :width="itemWidth"></slot>
</div>
</div>
</div>
@ -21,6 +21,7 @@
//
import {onMounted, ref} from "vue";
// eslint-disable-next-line no-undef
const props = defineProps({
items: {
type: Array,
@ -28,38 +29,25 @@ const props = defineProps({
},
gap: {
type: Number,
default: 10
default: 12
},
width: {
type: Number,
default: 240
},
height: {
type: Number,
default: 240
}
});
const container = ref(null)
const itemWidth = ref(props.width)
const margin = ref(props.gap)
onMounted(() => {
computeSize()
})
const computeSize = () => {
const w = container.value.offsetWidth - 10 //
const w = container.value.offsetWidth - 8 //
let cols = Math.floor(w / props.width)
itemWidth.value = Math.floor(w / cols) - 1
while (itemWidth.value < props.width && cols > 1) {
cols -= 1
itemWidth.value = Math.floor(w / cols) - 1
}
if (props.gap > 0) {
margin.value = props.gap / 2
}
itemWidth.value = Math.floor(w / cols)
}
window.onresize = () => {
@ -76,15 +64,14 @@ window.onresize = () => {
flex-wrap wrap
.list-item {
div {
.item-inner {
display flex
height 100%
overflow hidden
.item-wrapper {
height 100%
width 100%
display flex
justify-content center
}
}
}

View File

@ -1,16 +1,30 @@
<template>
<div class="page-apps">
<div class="page-apps custom-scroll">
<div class="title">
AI 助手应用中心
</div>
<div class="inner custom-scroll">
<div class="app-list">
<div class="list-item" v-for="item in list" :key="item.id">
<div v-if="item.key !=='gpt'">
<el-image :src="item.icon"/>
<div class="inner" :style="{height: listBoxHeight + 'px'}">
<ItemList :items="list" v-if="list.length > 0" gap="20" width="250">
<template #default="scope">
<div class="app-item" :style="{width: scope.width+'px'}">
<el-image :src="scope.item.icon" fit="cover" :style="{height: scope.width+'px'}"/>
<div class="title">
<span class="name">{{ scope.item.name }}</span>
<div class="opt">
<el-button size="small"
style="--el-color-primary:#009999"
@click="addRole(scope.item)">
<el-icon>
<Plus/>
</el-icon>
<span>添加应用</span>
</el-button>
</div>
</div>
<div class="hello-msg">{{ scope.item['hello_msg'] }}</div>
</div>
</div>
</div>
</template>
</ItemList>
</div>
</div>
</template>
@ -19,18 +33,31 @@
import {onMounted, ref} from "vue"
import {ElMessage} from "element-plus";
import {httpGet} from "@/utils/http";
import ItemList from "@/components/ItemList.vue";
import {Plus} from "@element-plus/icons-vue";
const listBoxHeight = window.innerHeight - 97
const list = ref([])
onMounted(() => {
httpGet("/api/role/list?all=true").then((res) => {
list.value = res.data
const data = res.data
for (let i = 0; i < data.length; i++) {
if (data[i].key === 'gpt') {
continue
}
list.value.push(data[i])
}
}).catch(e => {
ElMessage.error("获取应用失败:" + e.message)
})
})
const addRole = (row) => {
}
</script>
<style lang="stylus" scoped>
<style lang="stylus">
@import "@/assets/css/chat-app.styl"
@import "@/assets/css/custom-scroll.styl"
</style>

View File

@ -553,7 +553,7 @@ const connect = function (chat_id, role_id) {
content: _role['hello_msg'],
orgContent: _role['hello_msg'],
})
ElMessage.success({message: "对话连接成功!", duration: 500})
ElMessage.success({message: "对话连接成功!", duration: 1000})
} else { //
loadChatHistory(chat_id);
}

View File

@ -286,7 +286,7 @@
<h2>创作记录</h2>
<div class="finish-job-list">
<ItemList :items="finishedJobs" v-if="finishedJobs.length > 0">
<ItemList :items="finishedJobs" v-if="finishedJobs.length > 0" width="240">
<template #default="scope">
<div class="job-item">
<el-image
@ -503,7 +503,7 @@ onMounted(() => {
const clipboard = new Clipboard('.copy-prompt');
clipboard.on('success', () => {
ElMessage.success({message: "复制成功!", duration: 500});
ElMessage.success("复制成功!");
})
clipboard.on('error', () => {

View File

@ -289,7 +289,7 @@
<div class="task-list-inner" :style="{ height: listBoxHeight + 'px' }">
<h2>任务列表</h2>
<div class="running-job-list">
<ItemList :items="runningJobs" v-if="runningJobs.length > 0">
<ItemList :items="runningJobs" v-if="runningJobs.length > 0" width="240">
<template #default="scope">
<div class="job-item">
<el-popover
@ -645,7 +645,7 @@ onMounted(() => {
const clipboard = new Clipboard('.copy-prompt');
clipboard.on('success', () => {
ElMessage.success({message: "复制成功!", duration: 500});
ElMessage.success("复制成功!");
})
clipboard.on('error', () => {

View File

@ -281,7 +281,7 @@ getNext()
onMounted(() => {
const clipboard = new Clipboard('.copy-prompt');
clipboard.on('success', () => {
ElMessage.success({message: "复制成功!", duration: 500});
ElMessage.success("复制成功!");
})
clipboard.on('error', () => {
@ -293,6 +293,7 @@ const changeImgType = () => {
document.getElementById('waterfall-box').scrollTo(0, 0)
page.value = 0
list.value = []
loading.value = true
isOver.value = false
nextTick(() => getNext())
}