chore:输入框样式

This commit is contained in:
2026-09-11 09:15:12 +08:00
parent 596e7cdb03
commit bc127a45e8

View File

@@ -226,73 +226,112 @@
<!-- 输入区域 (WorkBuddy IDE 风格: 圆角白底容器 + 顶部输入 + 底部工具栏) -->
<!-- 输入区域 (新版: 顶部胶囊形输入条 + 底部 5 个图标) -->
<view class="input-area" :style="inputAreaStyle">
<view class="input-card">
<!-- 顶部输入区: textarea + 占位模式下显示的快捷指令提示 -->
<!-- 顶部输入行: 语音图标 + 输入区 + 加号 + 发送 -->
<view class="input-row-top">
<textarea
v-model="inputText"
class="message-input"
placeholder="今天帮你做些什么?"
placeholder-class="message-input-placeholder"
:maxlength="500"
:auto-height="true"
:show-confirm-bar="false"
:adjust-position="false"
:cursor-spacing="150"
@confirm="sendMessage"
@input="onInput"
@linechange="onLineChange" />
<!-- 快捷指令: 仅在空输入时显示, 位于输入框右侧 -->
<view v-if="!inputText && !inputLineCount" class="quick-tips">
<text class="quick-tip" @click="onQuickTipClick('quote')">
<text class="quick-tip-icon">@</text>
<text>引用对话文件</text>
</text>
<text class="quick-tip-sep">/</text>
<text class="quick-tip" @click="onQuickTipClick('skill')">
<text>调用技能与指令</text>
</text>
<!-- 无文字时左侧显示语音图标,点击才打开语音面板 -->
<view v-if="!hasInputText" class="input-row-icon" @click="onVoiceClick">
<svg class="voice-icon-svg" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="#1f1f1f" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
<path d="M10 12 h6 l6 -4 v16 l-6 -4 h-6 a2 2 0 0 1 -2 -2 v-4 a2 2 0 0 1 2 -2 z"/>
<path d="M24 10 c2 3 2 9 0 12"/>
</svg>
</view>
<!-- 扩大按钮 (输入行数过多时显示) -->
<button v-if="inputLineCount > 3" class="expand-btn" @click="openExpandEditor">
<text class="iconfont icon-expand">[ ]</text>
</button>
</view>
<!-- 输入区: textarea 始终可点击输入,有文字时下方显示 Auto 选择器 -->
<view class="input-left-content" :class="{ 'with-voice-icon': !hasInputText }">
<textarea
v-model="inputText"
class="message-input"
placeholder="发消息或按住说话"
placeholder-class="message-input-placeholder"
:maxlength="500"
:auto-height="true"
:show-confirm-bar="false"
:adjust-position="false"
:cursor-spacing="150"
@confirm="sendMessage"
@input="onInput"
@linechange="onLineChange" />
<view v-if="hasInputText" class="model-selector" @click="onToggleModelSelector">
<!-- 圆圈 @ 图标,H5/小程序通用 -->
<view class="model-icon-circle">
<text class="model-icon-text">@</text>
</view>
<text class="model-name">{{ selectedModel }}</text>
<text class="model-arrow">▾</text>
</view>
</view>
<!-- 底部工具栏 -->
<view class="input-toolbar">
<!-- 左侧: + 按钮 + 默认权限下拉 -->
<view class="toolbar-left">
<button class="tool-btn-plus" @click="showMoreTools">
<view class="input-right-actions">
<button class="top-plus-btn" @click="showMoreTools">
<text class="plus-icon">+</text>
</button>
<button class="tool-btn-with-text" @click="onTogglePermission">
<text class="perm-icon">☑</text>
<text class="perm-text">默认权限</text>
<text class="arrow-icon">▾</text>
<!-- 有文字时显示发送按钮 -->
<button v-if="hasInputText" class="top-send-btn" @click="sendMessage">
<!-- H5/小程序都兼容:旋转箭头模拟向上的纸飞机 -->
<text class="send-plane-text">➤</text>
</button>
</view>
</view>
<!-- 右侧: emoji + 麦克风 + 发送按钮 -->
<view class="toolbar-right">
<button class="emoji-btn" v-if="false" @click="toggleEmojiPanel">
<text class="iconfont icon-smile">😊</text>
</button>
<button class="voice-btn" v-if="false" @click="onVoiceClick">
<text class="iconfont" :class="voiceInputing ? 'icon-stop' : 'icon-voice'">🎤</text>
</button>
<!-- 发送按钮: 圆形灰色, 内含向上箭头图标 -->
<button
class="send-btn"
:class="{ disabled: !canSendMessage }"
@click="sendMessage"
:disabled="!canSendMessage">
<text class="send-icon">▲</text>
</button>
<!-- 底部工具栏: 5 个图标按钮均匀分布 -->
<view class="input-toolbar">
<view class="toolbar-item" hover-class="toolbar-item--hover" @click="onToolbarItem('task')">
<view class="toolbar-icon-svg">
<!-- 任务: 黑底对话气泡(微信式) + 三个白点 -->
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
<path d="M4 6 h22 a4 4 0 0 1 4 4 v12 a4 4 0 0 1 -4 4 h-15 l-7 5 v-5 h0 a4 4 0 0 1 -4 -4 v-12 a4 4 0 0 1 4 -4 z" fill="#1f1f1f"/>
<circle cx="11" cy="16" r="1.6" fill="#fff"/>
<circle cx="16" cy="16" r="1.6" fill="#fff"/>
<circle cx="21" cy="16" r="1.6" fill="#fff"/>
</svg>
</view>
<text class="toolbar-text">任务</text>
</view>
<view class="toolbar-item" hover-class="toolbar-item--hover" @click="onToolbarItem('automation')">
<view class="toolbar-icon-svg">
<!-- 自动化: 圆形 + 对勾 -->
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="#1f1f1f" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="16" cy="16" r="11"/>
<path d="M11 16 l4 4 l7 -8"/>
</svg>
</view>
<text class="toolbar-text">自动化</text>
</view>
<view class="toolbar-item" hover-class="toolbar-item--hover" @click="onToolbarItem('library')">
<view class="toolbar-icon-svg">
<!-- 资料库: 打开的书(两页 + 书脊) -->
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="#1f1f1f" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 7 c5 -2 10 -2 13 1 c3 -3 8 -3 13 -1 v18 c-5 -2 -10 -2 -13 1 c-3 -3 -8 -3 -13 -1 z"/>
<path d="M16 8 v18"/>
</svg>
</view>
<text class="toolbar-text">资料库</text>
</view>
<view class="toolbar-item" hover-class="toolbar-item--hover" @click="onToolbarItem('expert')">
<view class="toolbar-icon-svg">
<!-- 专家: 圆形表盘 + 时针分针 -->
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="#1f1f1f" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="16" cy="16" r="11"/>
<path d="M16 9 v7 l5 3"/>
</svg>
</view>
<text class="toolbar-text">专家</text>
</view>
<view class="toolbar-item" hover-class="toolbar-item--hover" @click="onToolbarItem('more')">
<view class="toolbar-icon-svg">
<!-- 更多: 2x2 网格方块(apps) -->
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="#1f1f1f" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="4" y="4" width="9" height="9" rx="1.5"/>
<rect x="19" y="4" width="9" height="9" rx="1.5"/>
<rect x="4" y="19" width="9" height="9" rx="1.5"/>
<rect x="19" y="19" width="9" height="9" rx="1.5"/>
</svg>
</view>
<text class="toolbar-text">更多</text>
</view>
</view>
</view>
@@ -456,6 +495,9 @@ export default {
showNicknameEditor: false, // 昵称编辑弹窗控制
// AI头像错误状态
avatarError: false,
// 当前选中的 AI 模型, 显示在输入框左侧(如 Auto)
selectedModel: 'Auto',
availableModels: ['Auto', 'GPT-4', 'Claude', '文心一言', '通义千问', 'Kimi'],
// AiChat API相关
currentConversationId: null,
@@ -512,6 +554,9 @@ export default {
const hasContent = this.inputText && this.inputText.trim() !== ''
const hasEmoji = this.containsEmoji(this.inputText)
return hasContent || hasEmoji
},
hasInputText() {
return this.inputText && this.inputText.trim() !== ''
}
},
// 新增:组件销毁时清除所有定时器
@@ -2096,6 +2141,25 @@ _handleStreamError(msg) {
} catch (e) { /* noop */ }
},
// 底部 5 图标工具栏点击: 任务 / 专家 / 资料库 / 自动化 / 更多
// - task / expert / library / automation: 触发 toolbar-click 事件(占位)
// - more: 复用 showMoreTools 触发更多功能弹窗
onToolbarItem(type) {
try {
switch (type) {
case 'task':
case 'expert':
case 'library':
case 'automation':
this.$emit('toolbar-click', { type })
break
case 'more':
this.showMoreTools()
break
}
} catch (e) { /* noop */ }
},
// 默认权限下拉点击: 占位交互, 后续接入权限弹窗
onTogglePermission() {
try {
@@ -2112,6 +2176,14 @@ _handleStreamError(msg) {
}
},
// 切换模型选择器: 在 availableModels 列表中循环选择
onToggleModelSelector() {
const list = this.availableModels || ['Auto']
const idx = list.indexOf(this.selectedModel)
const nextIdx = (idx + 1) % list.length
this.selectedModel = list[nextIdx]
},
// 打开扩大编辑器
openExpandEditor() {
this.expandInputText = this.inputText
@@ -3043,16 +3115,20 @@ _handleStreamError(msg) {
background: #f5f5f5 !important;
color: #1f1f1f !important;
border: none !important;
border-radius: 16rpx !important;
border-radius: 20rpx !important;
box-shadow: none !important;
padding: 14rpx 18rpx !important;
padding: 20rpx 30rpx !important; // 加大内边距,让气泡更"大"
display: inline-block;
word-break: break-word;
white-space: pre-wrap;
line-height: 1.6;
line-height: 1.7;
text-align: left;
max-width: 100%;
.message-text {
font-size: 20rpx !important; // 还原为用户消息原字号
}
&::before {
display: none !important;
content: none !important;
@@ -3166,244 +3242,232 @@ _handleStreamError(msg) {
transition: height 0.25s ease;
}
/* 输入区域 (WorkBuddy IDE 风格: 圆角白底容器 + 顶部输入 + 底部工具栏) */
/* 输入区域 (新版: 顶部胶囊形输入条 + 底部 5 个图标均匀分布) */
.input-area {
background: transparent;
padding: 12rpx 20rpx 16rpx;
flex-shrink: 0;
box-sizing: border-box;
/* 圆角白底容器: 把输入框、占位提示、底部工具栏都包在一个带边框的卡片里 */
.input-card {
background: #ffffff;
border: 1rpx solid #e5e7eb;
border-radius: 20rpx;
padding: 14rpx 16rpx 12rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
background: transparent;
border: none;
border-radius: 0;
padding: 0;
box-shadow: none;
box-sizing: border-box;
}
/* 顶部输入区: textarea + 占位模式下的 @ / / 快捷提示 */
/* 顶部输入横条: 胶囊形,左侧输入区 + 右侧操作按钮 */
.input-row-top {
position: relative;
display: flex;
align-items: flex-start;
min-height: 72rpx;
align-items: center;
justify-content: space-between;
background: #ffffff;
border-radius: 999rpx;
padding: 18rpx 14rpx 18rpx 32rpx;
min-height: 108rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
.message-input {
flex: 1;
min-height: 56rpx;
max-height: 240rpx;
background: transparent !important;
border: none !important;
padding: 12rpx 8rpx 12rpx 4rpx;
font-size: 30rpx;
line-height: 1.5;
color: #1f1f1f;
box-sizing: border-box;
}
/* placeholder 样式: 浅灰色 */
.message-input-placeholder {
color: #999 !important;
font-size: 30rpx !important;
}
/* 占位模式下显示在输入框右侧的快捷指令链接 */
.quick-tips {
position: absolute;
top: 50%;
left: 8rpx;
transform: translateY(-50%);
/* 无文字时左侧语音图标,点击打开语音面板 */
.input-row-icon {
flex-shrink: 0;
width: 52rpx;
height: 52rpx;
display: flex;
align-items: center;
pointer-events: none; /* 让 textarea 能接收点击 */
justify-content: center;
margin-right: 12rpx;
.quick-tip,
.quick-tip-sep {
font-size: 24rpx;
color: #1f6cff;
margin-right: 12rpx;
pointer-events: auto;
.voice-icon-svg {
width: 36rpx;
height: 36rpx;
display: block;
}
}
.quick-tip-icon {
margin-right: 4rpx;
/* 输入区: textarea 在上,模型选择器在下 */
.input-left-content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
min-height: 72rpx;
padding-right: 12rpx;
&.with-voice-icon {
margin-left: 0;
}
.message-input {
width: 100%;
min-height: 44rpx;
max-height: 240rpx;
background: transparent !important;
border: none !important;
padding: 0 0 6rpx 0;
font-size: 34rpx;
line-height: 1.5;
color: #1f1f1f;
box-sizing: border-box;
}
.message-input-placeholder {
color: #999 !important;
font-size: 32rpx !important;
}
.model-selector {
align-self: flex-start;
display: flex;
align-items: center;
gap: 6rpx;
height: 36rpx;
padding: 0;
margin-top: 4rpx;
background: transparent;
.model-icon-circle {
width: 28rpx;
height: 28rpx;
border-radius: 50%;
border: 2rpx solid #666666;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
.model-icon-text {
font-size: 18rpx;
color: #666666;
line-height: 1;
margin-top: 2rpx;
}
}
.model-name {
font-size: 26rpx;
color: #666666;
font-weight: 400;
line-height: 1;
}
.model-arrow {
font-size: 22rpx;
color: #999999;
line-height: 1;
margin-top: 2rpx;
}
}
.quick-tip-sep {
color: #999;
margin-right: 12rpx;
}
}
/* textarea 有内容时, 占位链接隐藏 (CSS 简易判断) */
.quick-tips {
opacity: 1;
}
/* 扩大按钮 */
.expand-btn {
/* 右侧操作按钮: + 号 和 发送 */
.input-right-actions {
flex-shrink: 0;
width: 56rpx;
height: 56rpx;
display: flex;
align-items: center;
gap: 8rpx;
}
.top-plus-btn {
flex-shrink: 0;
width: 76rpx;
height: 76rpx;
border-radius: 50%;
background-color: #f5f5f5;
background: transparent;
border: none;
display: flex;
align-items: center;
justify-content: center;
margin-left: 8rpx;
padding: 0;
.iconfont {
font-size: 28rpx;
color: #666;
.plus-icon {
font-size: 52rpx;
color: #1f1f1f;
font-weight: 300;
line-height: 1;
}
&::after {
border: none;
}
}
.top-send-btn {
flex-shrink: 0;
width: 76rpx;
height: 76rpx;
border-radius: 50%;
background: #1f1f1f;
border: none;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
.send-plane-text {
color: #ffffff;
font-size: 34rpx;
line-height: 1;
transform: rotate(-90deg); // 箭头向上,呈向上纸飞机
display: inline-block;
margin-left: -2rpx; // 视觉居中
margin-top: -2rpx;
}
&::after {
border: none;
}
}
}
/* 底部工具栏 */
/* 底部工具栏: 5 个图标按钮均匀分布 */
.input-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 6rpx;
min-height: 64rpx;
justify-content: space-around;
margin-top: 24rpx;
padding: 4rpx 0;
.toolbar-left,
.toolbar-right {
.toolbar-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
}
gap: 8rpx;
padding: 4rpx 0;
/* 左侧: + 圆形按钮 */
.tool-btn-plus {
width: 56rpx;
height: 56rpx;
border-radius: 50%;
background-color: #f5f5f5;
border: none;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12rpx;
&.toolbar-item--hover,
&:active {
opacity: 0.55;
}
.plus-icon {
font-size: 32rpx;
color: #666;
.toolbar-icon {
font-size: 44rpx;
line-height: 1;
color: #1f1f1f;
}
}
/* 左侧: 默认权限下拉 */
.tool-btn-with-text {
height: 56rpx;
padding: 0 18rpx;
border-radius: 28rpx;
background-color: #f5f5f5;
border: none;
display: flex;
align-items: center;
margin-right: 12rpx;
.perm-icon {
font-size: 28rpx;
color: #1f6cff;
margin-right: 6rpx;
.toolbar-icon-svg {
width: 44rpx;
height: 44rpx;
line-height: 1;
}
display: flex;
align-items: center;
justify-content: center;
.perm-text {
font-size: 26rpx;
color: #333;
line-height: 1;
}
.arrow-icon {
font-size: 22rpx;
color: #999;
margin-left: 6rpx;
line-height: 1;
}
}
/* 右侧: emoji 按钮 */
.emoji-btn {
width: 56rpx;
height: 56rpx;
border-radius: 50%;
background-color: #f5f5f5;
border: none;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12rpx;
padding: 0;
.iconfont {
font-size: 30rpx;
color: #666;
line-height: 1;
}
}
/* 右侧: 语音按钮 */
.voice-btn {
width: 56rpx;
height: 56rpx;
border-radius: 50%;
background-color: #f5f5f5;
border: none;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12rpx;
padding: 0;
.iconfont {
font-size: 30rpx;
color: #666;
line-height: 1;
}
}
/* 发送按钮: 圆形灰色, 内含向上箭头图标 (WorkBuddy 风格) */
.send-btn {
flex-shrink: 0;
width: 60rpx;
height: 60rpx;
border-radius: 50%;
background-color: #d1d5db;
border: none;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
margin-left: 0;
color: #ffffff;
text-align: center;
white-space: nowrap;
line-height: 1;
transition: background-color 0.2s ease;
.send-icon {
font-size: 28rpx;
line-height: 1;
color: #ffffff;
}
&.disabled {
background-color: #d1d5db;
opacity: 0.65;
}
&:not(.disabled) {
background-color: #1f1f1f;
.send-icon {
color: #ffffff;
svg {
width: 100%;
height: 100%;
display: block;
}
}
.toolbar-text {
font-size: 22rpx;
color: #1f1f1f;
line-height: 1;
}
}
}
}