794 lines
21 KiB
XML
794 lines
21 KiB
XML
<template>
|
||
<div class="page">
|
||
<swiper class="swiper" index="{{currentIndex}}" indicator="false" loop="false"
|
||
previousmargin="0px" nextmargin="0px" onchange="onSwipeChange">
|
||
|
||
<!-- 左页:对话(Harness 式) -->
|
||
<div class="page-item left-page">
|
||
<!-- 当前会话 / 点开选工作区 -->
|
||
<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>
|
||
|
||
<!-- 消息流 -->
|
||
<scroll class="chat-scroll" scroll-y="true">
|
||
<div class="chat-msg {{$item.role === 'user' ? 'msg-user' : 'msg-assistant'}}" for="{{messages}}">
|
||
<div class="think-chip" if="{{$item.think}}">
|
||
<text>💭 思考…</text>
|
||
</div>
|
||
<text class="think-text fl{{fontLevel}}" if="{{$item.showThink}}">{{$item.think}}</text>
|
||
<text class="chat-text fl{{fontLevel}}">{{$item.collapsed ? $item.preview : $item.text}}</text>
|
||
<text class="expand-chip" if="{{$item.role === 'assistant' && $item.collapsed}}">展开 ▾</text>
|
||
<text class="expand-chip" if="{{$item.role === 'assistant' && !$item.collapsed}}">收起 ▴</text>
|
||
<image class="chat-img" src="/common/dsniang.png" if="{{$item.kind === 'image'}}" />
|
||
<div class="approve-box" if="{{$item.kind === 'approval'}}">
|
||
<input class="approve-btn allow" type="button" value="允许" />
|
||
<input class="approve-btn deny" type="button" value="拒绝" />
|
||
</div>
|
||
</div>
|
||
</scroll>
|
||
|
||
<!-- 底部输入栏 -->
|
||
<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>
|
||
|
||
<!-- 中页:主页 / 吉祥物(无按钮,点击互动) -->
|
||
<div class="page-item center-page">
|
||
<!-- 气泡区:始终占位,让气泡在头像正上方居中;只显示趣味/上轮消耗信息 -->
|
||
<div class="bubble-zone">
|
||
<div class="bubble" if="{{bubbleVisible}}">
|
||
<text class="bubble-text">{{bubbleText}}</text>
|
||
</div>
|
||
</div>
|
||
<image class="mascot step{{animStep}}" src="/common/dsniang.png" onclick="onTap" />
|
||
<text class="peak {{isPeak ? 'peak-red' : 'peak-green'}}">{{peakLabel}}</text>
|
||
<text class="stats">余额 {{balance}}</text>
|
||
<text class="stats">今日 {{todayTokens}} tokens · 预估 ¥{{todayCost}}</text>
|
||
</div>
|
||
|
||
<!-- 右页:丰富设置 -->
|
||
<div class="page-item right-page">
|
||
<text class="page-title">设置</text>
|
||
<div class="setting-row" onclick="toggleModel">
|
||
<text class="setting-label fl{{fontLevel}}">模型</text>
|
||
<text class="setting-value fl{{fontLevel}}">{{modelValue}}</text>
|
||
</div>
|
||
<div class="setting-row" onclick="toggleProvider">
|
||
<text class="setting-label fl{{fontLevel}}">提供方</text>
|
||
<text class="setting-value fl{{fontLevel}}">{{providerValue}}</text>
|
||
</div>
|
||
<div class="setting-row" onclick="toggleReason">
|
||
<text class="setting-label fl{{fontLevel}}">推理强度</text>
|
||
<text class="setting-value fl{{fontLevel}}">{{reasonValue}}</text>
|
||
</div>
|
||
<div class="setting-row" onclick="togglePerm">
|
||
<text class="setting-label fl{{fontLevel}}">权限模式</text>
|
||
<text class="setting-value fl{{fontLevel}}">{{permValue}}</text>
|
||
</div>
|
||
<div class="setting-row" onclick="toggleDialog">
|
||
<text class="setting-label fl{{fontLevel}}">对话模式</text>
|
||
<text class="setting-value fl{{fontLevel}}">{{dialogModeValue}}</text>
|
||
</div>
|
||
<text class="section-title fl{{fontLevel}}">手表端设置</text>
|
||
<div class="setting-row" onclick="toggleWatchConn">
|
||
<text class="setting-label fl{{fontLevel}}">手环连接</text>
|
||
<text class="setting-value fl{{fontLevel}}">{{watchConnValue}}</text>
|
||
</div>
|
||
<div class="setting-row" onclick="toggleServer">
|
||
<text class="setting-label fl{{fontLevel}}">服务器</text>
|
||
<text class="setting-value fl{{fontLevel}}">{{serverValue}}</text>
|
||
</div>
|
||
<div class="setting-row" onclick="openFontPicker">
|
||
<text class="setting-label fl{{fontLevel}}">字体大小</text>
|
||
<text class="setting-value fl{{fontLevel}}">{{fontLabel}}</text>
|
||
</div>
|
||
<text class="conn-text">{{connText}}</text>
|
||
</div>
|
||
</swiper>
|
||
|
||
<div class="dots">
|
||
<div class="dot {{currentIndex == 0 ? 'dot-active' : ''}}"></div>
|
||
<div class="dot {{currentIndex == 1 ? 'dot-active' : ''}}"></div>
|
||
<div class="dot {{currentIndex == 2 ? 'dot-active' : ''}}"></div>
|
||
</div>
|
||
|
||
<!-- 字体大小弹窗 -->
|
||
<div class="popup" if="{{showFontPicker}}">
|
||
<div class="popup-box">
|
||
<text class="popup-title">字体大小</text>
|
||
<slider class="font-slider" min="14" max="22" step="2" value="{{fontValue}}" onchange="onFontChange" />
|
||
<text class="popup-value">{{fontLabel}}</text>
|
||
<div class="popup-actions">
|
||
<input class="popup-btn" type="button" value="确定" onclick="confirmFont" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import bridge from '../../common/bridge.js'
|
||
|
||
// 懒加载 @system.audio,避免模拟器/无扬声器时崩
|
||
let audioModule = null
|
||
let audioTried = false
|
||
function loadAudio() {
|
||
if (audioTried) return audioModule
|
||
audioTried = true
|
||
try {
|
||
audioModule = require('@system.audio')
|
||
} catch (e) {
|
||
audioModule = null
|
||
}
|
||
return audioModule
|
||
}
|
||
function playDuckSound() {
|
||
const a = loadAudio()
|
||
if (!a) return
|
||
try {
|
||
a.src = '/common/Ya1.mp3'
|
||
a.play()
|
||
} catch (e) {}
|
||
}
|
||
|
||
export default {
|
||
private: {
|
||
currentIndex: 1,
|
||
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:'user', text:'第一件事具体说说', preview:'', think:null, kind:'normal', showThink:false, collapsed:false },
|
||
{ role:'assistant', text:'已把进度整理成:1)修复白屏(已提交) 2)布局放大(已提交) 3)待真机验证', preview:'已把进度整理成:1)修复白屏…', think:'汇总最近 5 次提交…', kind:'normal', showThink:true, collapsed:true },
|
||
{ role:'assistant', text:'需要一个权限:允许运行网络请求到 https://api.deepseek.com/user/balance', preview:'', think:null, kind:'approval', showThink:false, collapsed:false },
|
||
{ role:'user', text:'允许', preview:'', think:null, kind:'normal', showThink:false, collapsed:false },
|
||
{ role:'assistant', text:'已查询到余额 ¥6.20,今日已用 ¥12.08。', preview:'', think:'正在调用 DeepSeek user/balance…', kind:'normal', showThink:true, collapsed:false },
|
||
{ role:'user', text:'帮我生成一张手环 UI 草图', preview:'', think:null, kind:'normal', showThink:false, collapsed:false },
|
||
{ role:'assistant', text:'生成了一张「手表主界面」草图,点击可放大。', preview:'生成了一张「手表主界面」草图…', think:'正在渲染图像…', kind:'image', showThink:true, collapsed:false },
|
||
{ role:'assistant', text:'另外建议把左边做成对话流、右边放设置,中间吉祥物可交互——这样最贴合你说的“把 Harness 串流过来”。', preview:'另外建议把左边做成对话流、右边放设置…', think:'正在思考布局建议…', kind:'normal', showThink:true, collapsed:true },
|
||
{ role:'system', text:'会话已切换工作区:reactor', preview:'', think:null, kind:'normal', 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: '--',
|
||
todayTokens: '--',
|
||
todayCost: '--',
|
||
bubbleVisible: false,
|
||
bubbleText: '',
|
||
bubbleIndex: 0,
|
||
animStep: 0,
|
||
animLock: false,
|
||
settings: {
|
||
serverUrl: 'ws://127.0.0.1:8787',
|
||
userId: '',
|
||
token: ''
|
||
},
|
||
connText: '手机/手表未连接',
|
||
modelValue: 'DeepSeek-V4-Flash',
|
||
providerValue: 'DeepSeek 官方',
|
||
reasonValue: '高',
|
||
permValue: 'Workspace Write',
|
||
dialogModeValue: '深神模式',
|
||
watchConnValue: '未连接(占位)',
|
||
serverValue: 'ws://127.0.0.1:8787',
|
||
showFontPicker: false,
|
||
fontValue: 18,
|
||
fontLevel: 1,
|
||
fontLabel: '中',
|
||
bubblePresets: [
|
||
'我算得比你快,但没你可爱。',
|
||
'上轮消耗 ¥0.08,钱包还撑得住。',
|
||
'峰时了,省着点用哦~',
|
||
'谷时来了,冲就完事!',
|
||
'今天也要一起聪明地偷懒。',
|
||
'点我一下,解压一下。',
|
||
'上轮余额 ¥12.34,别浪~',
|
||
'思考中…其实是发呆。'
|
||
]
|
||
},
|
||
|
||
onInit() {
|
||
this.refreshPeak()
|
||
},
|
||
|
||
onReady() {
|
||
this._unsub = bridge.subscribe({
|
||
status: (s) => {
|
||
this.connText = s || '未连接'
|
||
},
|
||
message: (msg) => {
|
||
this.handleBridgeMessage(msg)
|
||
}
|
||
})
|
||
bridge.refreshConn()
|
||
},
|
||
|
||
onDestroy() {
|
||
if (this._unsub) this._unsub()
|
||
},
|
||
|
||
onSwipeChange(e) {
|
||
if (e && typeof e.index === 'number') {
|
||
this.currentIndex = e.index
|
||
}
|
||
},
|
||
|
||
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 || ''
|
||
},
|
||
|
||
toggleModel() { this.modelValue += ' ·' },
|
||
toggleProvider() { this.providerValue += ' ·' },
|
||
toggleReason() { this.reasonValue += ' ·' },
|
||
togglePerm() { this.permValue += ' ·' },
|
||
toggleDialog() { this.dialogModeValue += ' ·' },
|
||
toggleWatchConn() { this.watchConnValue += ' ·' },
|
||
toggleServer() { this.serverValue += ' ·' },
|
||
|
||
openFontPicker() {
|
||
this.showFontPicker = true
|
||
this.fontValue = 18
|
||
},
|
||
|
||
onFontChange(e) {
|
||
let v = e && typeof e.progress === 'number' ? e.progress : (e && typeof e.value === 'number' ? e.value : 18)
|
||
// 兼容 progress 是 0-100 百分比的情况
|
||
if (v >= 10 && v <= 24) {
|
||
this.fontValue = v
|
||
} else {
|
||
this.fontValue = Math.round(14 + (v / 100) * (22 - 14))
|
||
}
|
||
const lv = Math.round((this.fontValue - 14) / 2)
|
||
this.fontLevel = Math.max(0, Math.min(4, lv))
|
||
this.fontLabel = ['最小', '小', '中', '大', '特大'][this.fontLevel]
|
||
},
|
||
|
||
confirmFont() {
|
||
this.showFontPicker = false
|
||
const row = this.watchSettings.find((r) => r.label === '字体大小')
|
||
if (row) row.value = this.fontLabel
|
||
},
|
||
|
||
refreshPeak() {
|
||
// 用北京时间计算峰谷;周六/周日全天谷时
|
||
const now = Date.now()
|
||
const d = new Date(now + 8 * 3600 * 1000)
|
||
const day = d.getUTCDay() // 0=Sun
|
||
const hour = d.getUTCHours()
|
||
const isWeekend = day === 0 || day === 6
|
||
const inPeak = !isWeekend && ((hour >= 9 && hour < 12) || (hour >= 14 && hour < 18))
|
||
this.isPeak = inPeak
|
||
this.peakLabel = inPeak ? '峰时 · 全价' : '谷时 · 半价'
|
||
},
|
||
|
||
onTap() {
|
||
// 冷却:动画/气泡显示期间不重复触发
|
||
if (this.animLock) return
|
||
this.animLock = true
|
||
|
||
// Q 弹:底部不动,从上往下收缩,再回弹(scaleY 多帧平滑)
|
||
const self = this
|
||
this.animStep = 0
|
||
setTimeout(() => { self.animStep = 1 }, 0) // scaleY 0.92
|
||
setTimeout(() => { self.animStep = 2 }, 40) // scaleY 0.84
|
||
setTimeout(() => { self.animStep = 3 }, 85) // scaleY 0.95
|
||
setTimeout(() => { self.animStep = 4 }, 135) // scaleY 1.05
|
||
setTimeout(() => { self.animStep = 0 }, 200) // scaleY 1.00
|
||
// 回弹时播鸭叫
|
||
setTimeout(() => { playDuckSound() }, 150)
|
||
|
||
// 轮播趣味/上轮消耗信息
|
||
const idx = this.bubbleIndex % this.bubblePresets.length
|
||
this.bubbleIndex += 1
|
||
this.bubbleText = this.bubblePresets[idx]
|
||
this.bubbleVisible = true
|
||
|
||
// 气泡显示约 1 秒后自动消失
|
||
setTimeout(() => { self.bubbleVisible = false }, 1000)
|
||
// 消失后再等 0.5 秒才允许再次点击
|
||
setTimeout(() => { self.animLock = false }, 1500)
|
||
},
|
||
|
||
selectSession(index) {
|
||
this.currentIndex = 1
|
||
},
|
||
|
||
onServerChange(e) { this.settings.serverUrl = e && e.value || '' },
|
||
onUserChange(e) { this.settings.userId = e && e.value || '' },
|
||
onTokenChange(e) { this.settings.token = e && e.value || '' },
|
||
|
||
handleBridgeMessage(msg) {
|
||
if (!msg) return
|
||
if (msg.type === 'status' && msg.payload) {
|
||
const pl = msg.payload
|
||
if (typeof pl.balance !== 'undefined') this.balance = pl.balance
|
||
if (typeof pl.todayCost !== 'undefined') this.todayCost = pl.todayCost
|
||
if (pl.model) this.statusText = '在线 · ' + pl.model
|
||
if (typeof pl.running !== 'undefined') this.statusText = pl.running ? '执行中' : '空闲'
|
||
this.connText = pl.model ? ('在线 · ' + pl.model) : '已连接'
|
||
} else if (msg.type === 'event' && msg.payload) {
|
||
// 后续可更新会话/事件列表
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
.page {
|
||
width: 100%;
|
||
height: 100%;
|
||
flex-direction: column;
|
||
background-color: #0b1220;
|
||
}
|
||
|
||
.swiper {
|
||
flex: 1;
|
||
width: 100%;
|
||
indicator-size: 0px;
|
||
}
|
||
|
||
.page-item {
|
||
width: 100%;
|
||
height: 100%;
|
||
padding: 12px;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.left-page,
|
||
.right-page {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
padding-top: 22px;
|
||
}
|
||
|
||
.center-page {
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.bubble-zone {
|
||
width: 100%;
|
||
height: 54px;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.page-title {
|
||
color: #e6f0ff;
|
||
font-size: 24px;
|
||
font-weight: bold;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.page-hint {
|
||
color: #6b7a99;
|
||
font-size: 16px;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.session-list {
|
||
width: 100%;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.session-row {
|
||
width: 100%;
|
||
height: 44px;
|
||
flex-direction: row;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 8px;
|
||
padding: 0 10px;
|
||
border-radius: 10px;
|
||
background-color: #152238;
|
||
}
|
||
|
||
.session-title {
|
||
color: #dbe8ff;
|
||
font-size: 17px;
|
||
}
|
||
|
||
.session-dot {
|
||
color: #33b4ff;
|
||
font-size: 16px;
|
||
}
|
||
|
||
/* 吉祥物:放大 + 底部锚定的 scaleY+translateY 补偿 Q 弹 */
|
||
.mascot {
|
||
width: 456px;
|
||
height: 403px;
|
||
transition: transform 0.12s cubic-bezier(0.33, 1.12, 0.68, 1);
|
||
}
|
||
|
||
.step0 { transform: translateY(0px) scaleY(1); }
|
||
.step1 { transform: translateY(16px) scaleY(0.92); }
|
||
.step2 { transform: translateY(36px) scaleY(0.82); }
|
||
.step3 { transform: translateY(10px) scaleY(0.95); }
|
||
.step4 { transform: translateY(-10px) scaleY(1.05); }
|
||
|
||
.peak {
|
||
width: 100%;
|
||
font-size: 32px;
|
||
font-weight: bold;
|
||
line-height: 40px;
|
||
text-align: center;
|
||
margin-top: 6px;
|
||
}
|
||
|
||
.peak-green {
|
||
color: #3ddc84;
|
||
}
|
||
|
||
.peak-red {
|
||
color: #ff5b5b;
|
||
}
|
||
|
||
.stats {
|
||
width: 100%;
|
||
color: #c4d2ea;
|
||
font-size: 22px;
|
||
line-height: 28px;
|
||
text-align: center;
|
||
margin-top: 2px;
|
||
}
|
||
|
||
/* 气泡:头像正上方居中,稍微放大 */
|
||
.bubble {
|
||
width: 324px;
|
||
flex-direction: column;
|
||
padding: 18px 20px;
|
||
border-radius: 22px;
|
||
background-color: rgba(20, 32, 52, 0.86);
|
||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||
}
|
||
|
||
.bubble-text {
|
||
color: #e6f0ff;
|
||
font-size: 17px;
|
||
line-height: 24px;
|
||
text-align: center;
|
||
}
|
||
|
||
.setting-label {
|
||
color: #8fa4c9;
|
||
font-size: 14px;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.setting-input {
|
||
width: 100%;
|
||
height: 38px;
|
||
border-radius: 8px;
|
||
background-color: #152238;
|
||
color: #e6f0ff;
|
||
font-size: 15px;
|
||
padding: 0 8px;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.conn-text {
|
||
color: #6b7a99;
|
||
font-size: 16px;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.dots {
|
||
flex-direction: row;
|
||
justify-content: center;
|
||
align-items: center;
|
||
height: 14px;
|
||
margin-top: 4px;
|
||
gap: 8px;
|
||
}
|
||
|
||
.dot {
|
||
width: 7px;
|
||
height: 7px;
|
||
border-radius: 4px;
|
||
background-color: rgba(255, 255, 255, 0.28);
|
||
}
|
||
|
||
.dot-active {
|
||
width: 22px;
|
||
border-radius: 4px;
|
||
background-color: #33b4ff;
|
||
}
|
||
|
||
/* ===== 左页:对话 ===== */
|
||
.chat-scroll {
|
||
flex: 1;
|
||
width: 100%;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.chat-img {
|
||
width: 100%;
|
||
height: 150px;
|
||
border-radius: 8px;
|
||
margin-top: 4px;
|
||
}
|
||
|
||
.chat-msg {
|
||
width: 100%;
|
||
flex-direction: column;
|
||
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: 17px;
|
||
line-height: 25px;
|
||
}
|
||
|
||
.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: 14px;
|
||
}
|
||
|
||
.think-text {
|
||
color: #9db3d8;
|
||
font-size: 14px;
|
||
line-height: 20px;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.expand-chip {
|
||
margin-top: 4px;
|
||
color: #33b4ff;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.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;
|
||
min-height: 38px;
|
||
height: auto;
|
||
border-radius: 8px;
|
||
background-color: #152238;
|
||
color: #e6f0ff;
|
||
font-size: 15px;
|
||
padding: 6px 8px;
|
||
}
|
||
|
||
.input-send {
|
||
width: 72px;
|
||
min-height: 38px;
|
||
height: auto;
|
||
border-radius: 19px;
|
||
background-color: #33b4ff;
|
||
color: #08131f;
|
||
font-size: 16px;
|
||
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;
|
||
}
|
||
|
||
/* ===== 右页:设置 ===== */
|
||
.settings-scroll {
|
||
flex: 1;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.setting-row {
|
||
width: 100%;
|
||
min-height: 44px;
|
||
height: auto;
|
||
flex-direction: row;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 6px 10px;
|
||
border-radius: 10px;
|
||
background-color: #152238;
|
||
margin-bottom: 6px;
|
||
}
|
||
|
||
.setting-label {
|
||
color: #9db3d8;
|
||
font-size: 17px;
|
||
}
|
||
|
||
.setting-value {
|
||
color: #e6f0ff;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.section-title {
|
||
color: #33b4ff;
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
margin-top: 10px;
|
||
margin-bottom: 6px;
|
||
}
|
||
|
||
/* ===== 字体等级(随字号滑块变化) ===== */
|
||
.fl0 { font-size: 15px; line-height: 21px; }
|
||
.fl1 { font-size: 17px; line-height: 25px; }
|
||
.fl2 { font-size: 19px; line-height: 28px; }
|
||
.fl3 { font-size: 21px; line-height: 31px; }
|
||
.fl4 { font-size: 23px; line-height: 34px; }
|
||
|
||
/* ===== 字体大小弹窗 ===== */
|
||
.popup {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
justify-content: center;
|
||
align-items: center;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
}
|
||
|
||
.popup-box {
|
||
width: 300px;
|
||
min-height: 180px;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 20px;
|
||
border-radius: 18px;
|
||
background-color: #0f1a2c;
|
||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||
}
|
||
|
||
.popup-title {
|
||
color: #e6f0ff;
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.font-slider {
|
||
width: 240px;
|
||
margin-top: 14px;
|
||
}
|
||
|
||
.popup-value {
|
||
color: #33b4ff;
|
||
font-size: 18px;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.popup-actions {
|
||
margin-top: 14px;
|
||
}
|
||
|
||
.popup-btn {
|
||
width: 120px;
|
||
height: 42px;
|
||
border-radius: 21px;
|
||
background-color: #33b4ff;
|
||
color: #08131f;
|
||
font-size: 17px;
|
||
text-align: center;
|
||
}
|
||
</style>
|