feat: glassy chat UI (liquid glass) + collapsed assistant messages + expand; workspace selector + input bar
This commit is contained in:
+287
-22
@@ -3,16 +3,43 @@
|
||||
<swiper class="swiper" index="{{currentIndex}}" indicator="false" loop="false"
|
||||
previousmargin="14px" nextmargin="14px" onchange="onSwipeChange">
|
||||
|
||||
<!-- 左页:会话 -->
|
||||
<!-- 左页:对话(Harness 式) -->
|
||||
<div class="page-item left-page">
|
||||
<text class="page-title">会话</text>
|
||||
<div class="session-list">
|
||||
<div class="session-row" for="{{sessions}}" onclick="selectSession($index)">
|
||||
<text class="session-title">{{$item.title}}</text>
|
||||
<text class="session-dot" if="{{$item.running}}">●</text>
|
||||
<!-- 当前会话 / 点开选工作区 -->
|
||||
<text class="page-title" onclick="toggleSelect">对话 · {{currentConv}}</text>
|
||||
|
||||
<!-- 工作区/会话选择器 -->
|
||||
<div class="select-overlay" if="{{showSelect}}">
|
||||
<div class="select-ws" for="{{workspaces}}" onclick="toggleSelect">
|
||||
<text class="select-name">{{$item.name}}</text>
|
||||
<div class="select-conv" for="{{$item.conversations}}" onclick="selectConversation($index,$item)">
|
||||
<text class="select-conv-text">{{$item}}</text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<text class="page-hint" if="{{!sessions.length}}">暂无会话</text>
|
||||
|
||||
<!-- 消息流 -->
|
||||
<div class="chat-list">
|
||||
<div class="chat-msg {{$item.role === 'user' ? 'msg-user' : 'msg-assistant'}}" for="{{messages}}">
|
||||
<div class="think-chip" if="{{$item.think}}" onclick="toggleThink($index)">
|
||||
<text>💭 思考…</text>
|
||||
</div>
|
||||
<text class="think-text" if="{{$item.showThink}}">{{$item.think}}</text>
|
||||
<text class="chat-text">{{$item.collapsed ? $item.preview : $item.text}}</text>
|
||||
<text class="expand-chip" if="{{$item.collapsed}}" onclick="toggleCollapse($index)">展开 ▾</text>
|
||||
<text class="expand-chip" if="{{!$item.collapsed}}" onclick="toggleCollapse($index)">收起 ▴</text>
|
||||
<div class="approve-box" if="{{$item.kind === 'approval'}}">
|
||||
<input class="approve-btn allow" type="button" value="允许" onclick="approve($index)" />
|
||||
<input class="approve-btn deny" type="button" value="拒绝" onclick="deny($index)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部输入栏 -->
|
||||
<div class="input-bar">
|
||||
<input class="input-field" type="text" value="{{inputText}}" placeholder="说点什么…" onchange="onInputChange" />
|
||||
<input class="input-send" type="button" value="输入" onclick="openInput" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 中页:主页 / 吉祥物(无按钮,点击互动) -->
|
||||
@@ -29,15 +56,18 @@
|
||||
<text class="stats">今日 {{todayTokens}} tokens · 预估 ¥{{todayCost}}</text>
|
||||
</div>
|
||||
|
||||
<!-- 右页:设置 -->
|
||||
<!-- 右页:丰富设置 -->
|
||||
<div class="page-item right-page">
|
||||
<text class="page-title">设置</text>
|
||||
<text class="setting-label">服务器</text>
|
||||
<input class="setting-input" type="text" value="{{settings.serverUrl}}" onchange="onServerChange" />
|
||||
<text class="setting-label">用户ID</text>
|
||||
<input class="setting-input" type="text" value="{{settings.userId}}" onchange="onUserChange" />
|
||||
<text class="setting-label">Token</text>
|
||||
<input class="setting-input" type="text" value="{{settings.token}}" onchange="onTokenChange" />
|
||||
<div class="setting-row" for="{{settingsList}}" onclick="toggleSetting($index)">
|
||||
<text class="setting-label">{{$item.label}}</text>
|
||||
<text class="setting-value">{{$item.value}}</text>
|
||||
</div>
|
||||
<text class="section-title">手表端设置</text>
|
||||
<div class="setting-row" for="{{watchSettings}}" onclick="toggleSetting($index)">
|
||||
<text class="setting-label">{{$item.label}}</text>
|
||||
<text class="setting-value">{{$item.value}}</text>
|
||||
</div>
|
||||
<text class="conn-text">{{connText}}</text>
|
||||
</div>
|
||||
</swiper>
|
||||
@@ -78,11 +108,19 @@ function playDuckSound() {
|
||||
export default {
|
||||
private: {
|
||||
currentIndex: 1,
|
||||
sessions: [
|
||||
{ title: '原型演示会话', running: false },
|
||||
{ title: 'UI 对齐中', running: true },
|
||||
{ title: '待接入 Harness', running: false }
|
||||
messages: [
|
||||
{ role:'user', text:'帮我看看今天有什么任务', preview:'', think:null, kind:'normal', showThink:false, collapsed:false },
|
||||
{ role:'assistant', text:'好的,今天三件事:1) 回复 DSHWatch 进度;2) 调整手环 UI;3) 准备部署。', preview:'好的,今天三件事:1) 回复 DSHWatch 进度;2) 调整手环…', think:'正在从工作区任务列表整理…', kind:'normal', showThink:true, collapsed:true },
|
||||
{ role:'assistant', text:'需要一个权限:允许运行网络请求到 https://api.deepseek.com/user/balance', preview:'', think:null, kind:'approval', showThink:false, collapsed:false }
|
||||
],
|
||||
workspaces: [
|
||||
{ name:'DeepSeek_Harness_Watch', conversations:['小米手环10 Pro远程控制','DSHWatch 验收'] },
|
||||
{ name:'reactor', conversations:['任务-001','任务-002'] },
|
||||
{ name:'truestudio.online', conversations:['评估-今天'] }
|
||||
],
|
||||
currentConv: '小米手环10 Pro远程控制',
|
||||
showSelect: false,
|
||||
inputText: '',
|
||||
isPeak: false,
|
||||
peakLabel: '谷时 · 半价',
|
||||
balance: '--',
|
||||
@@ -99,6 +137,21 @@ export default {
|
||||
token: ''
|
||||
},
|
||||
connText: '手机/手表未连接',
|
||||
settingsList: [
|
||||
{ label:'模型', value:'DeepSeek-V4-Flash' },
|
||||
{ label:'提供方', value:'DeepSeek 官方' },
|
||||
{ label:'推理强度', value:'高' },
|
||||
{ label:'权限模式', value:'Workspace Write' },
|
||||
{ label:'对话模式', value:'深神模式' },
|
||||
{ label:'语言', value:'中文' },
|
||||
{ label:'外观', value:'深色' },
|
||||
{ label:'Enter 行为', value:'插话发送' }
|
||||
],
|
||||
watchSettings: [
|
||||
{ label:'手环连接', value:'未连接(占位)' },
|
||||
{ label:'服务器', value:'ws://127.0.0.1:8787' },
|
||||
{ label:'用户ID', value:'--' }
|
||||
],
|
||||
bubblePresets: [
|
||||
'我算得比你快,但没你可爱。',
|
||||
'上轮消耗 ¥0.08,钱包还撑得住。',
|
||||
@@ -137,6 +190,50 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
toggleSelect() {
|
||||
this.showSelect = !this.showSelect
|
||||
},
|
||||
|
||||
selectConversation(convIndex, convName) {
|
||||
this.currentConv = convName || this.currentConv
|
||||
this.showSelect = false
|
||||
},
|
||||
|
||||
toggleThink(index) {
|
||||
const m = this.messages[index]
|
||||
if (m) m.showThink = !m.showThink
|
||||
},
|
||||
|
||||
toggleCollapse(index) {
|
||||
const m = this.messages[index]
|
||||
if (m) m.collapsed = !m.collapsed
|
||||
},
|
||||
|
||||
approve(index) {
|
||||
const m = this.messages[index]
|
||||
if (m) { m.kind = 'done'; m.text = '已允许 ✓' }
|
||||
},
|
||||
|
||||
deny(index) {
|
||||
const m = this.messages[index]
|
||||
if (m) { m.kind = 'done'; m.text = '已拒绝 ✕' }
|
||||
},
|
||||
|
||||
openInput() {
|
||||
// 占位:后续调用官方输入法组件
|
||||
this.inputText = ''
|
||||
},
|
||||
|
||||
onInputChange(e) {
|
||||
this.inputText = e && e.value || ''
|
||||
},
|
||||
|
||||
toggleSetting(index) {
|
||||
const all = [...this.settingsList, ...this.watchSettings]
|
||||
const row = all[index]
|
||||
if (row) row.value += ' ·'
|
||||
},
|
||||
|
||||
refreshPeak() {
|
||||
// 用北京时间计算峰谷;周六/周日全天谷时
|
||||
const now = Date.now()
|
||||
@@ -326,13 +423,14 @@ export default {
|
||||
flex-direction: column;
|
||||
padding: 18px 20px;
|
||||
border-radius: 22px;
|
||||
background-color: #ffffff;
|
||||
background-color: rgba(20, 32, 52, 0.86);
|
||||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||
}
|
||||
|
||||
.bubble-text {
|
||||
color: #1c2c47;
|
||||
font-size: 18px;
|
||||
line-height: 26px;
|
||||
color: #e6f0ff;
|
||||
font-size: 17px;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -380,4 +478,171 @@ export default {
|
||||
border-radius: 4px;
|
||||
background-color: #33b4ff;
|
||||
}
|
||||
|
||||
/* ===== 左页:对话 ===== */
|
||||
.chat-list {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chat-msg {
|
||||
width: 100%;
|
||||
margin-bottom: 6px;
|
||||
padding: 7px 9px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.msg-user {
|
||||
background-color: rgba(51, 180, 255, 0.18);
|
||||
border: 1px solid rgba(120, 200, 255, 0.28);
|
||||
}
|
||||
|
||||
.msg-assistant {
|
||||
background-color: rgba(22, 34, 56, 0.58);
|
||||
border: 1px solid rgba(255, 255, 255, 0.10);
|
||||
}
|
||||
|
||||
.chat-text {
|
||||
color: #f0f6ff;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.think-chip {
|
||||
background-color: rgba(28, 44, 71, 0.7);
|
||||
border: 1px solid rgba(255,255,255,0.08);
|
||||
border-radius: 6px;
|
||||
padding: 4px;
|
||||
margin-bottom: 4px;
|
||||
color: #9db3d8;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.think-text {
|
||||
color: #9db3d8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.expand-chip {
|
||||
margin-top: 4px;
|
||||
color: #33b4ff;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.approve-box {
|
||||
flex-direction: row;
|
||||
margin-top: 6px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.approve-btn {
|
||||
width: 82px;
|
||||
height: 34px;
|
||||
border-radius: 17px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.approve-btn.allow {
|
||||
background-color: #33b4ff;
|
||||
color: #08131f;
|
||||
}
|
||||
|
||||
.approve-btn.deny {
|
||||
background-color: #ff5b5b;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.input-bar {
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-top: 6px;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.input-field {
|
||||
flex: 1;
|
||||
height: 36px;
|
||||
border-radius: 8px;
|
||||
background-color: #152238;
|
||||
color: #e6f0ff;
|
||||
font-size: 14px;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.input-send {
|
||||
width: 64px;
|
||||
height: 36px;
|
||||
border-radius: 18px;
|
||||
background-color: #33b4ff;
|
||||
color: #08131f;
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.select-overlay {
|
||||
width: 100%;
|
||||
margin-bottom: 8px;
|
||||
padding: 8px;
|
||||
border-radius: 10px;
|
||||
background-color: #0f1a2c;
|
||||
}
|
||||
|
||||
.select-ws {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.select-name {
|
||||
color: #e6f0ff;
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.select-conv {
|
||||
padding: 6px 8px;
|
||||
margin-top: 4px;
|
||||
border-radius: 8px;
|
||||
background-color: #152238;
|
||||
}
|
||||
|
||||
.select-conv-text {
|
||||
color: #b7c8e8;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* ===== 右页:设置 ===== */
|
||||
.setting-row {
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 8px;
|
||||
border-radius: 8px;
|
||||
background-color: #152238;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.setting-label {
|
||||
color: #8fa4c9;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.setting-value {
|
||||
color: #dbe8ff;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
color: #33b4ff;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user