mirror of
https://github.com/Cola-Echo/Cola.git
synced 2026-06-06 11:55:51 +00:00
Add files via upload
This commit is contained in:
@@ -677,10 +677,6 @@ function handleFuncItemClick(func) {
|
||||
showTransferPage();
|
||||
}
|
||||
return;
|
||||
case 'time':
|
||||
hideFuncPanel();
|
||||
showTimePicker();
|
||||
return;
|
||||
case 'listen':
|
||||
hideFuncPanel();
|
||||
// 群聊不支持一起听
|
||||
@@ -758,194 +754,5 @@ export function initFuncPanel() {
|
||||
// 初始化音乐面板事件
|
||||
initMusicEvents();
|
||||
initMusicShareListener();
|
||||
initTimePickerEvents();
|
||||
initListenTogether();
|
||||
}
|
||||
|
||||
// ============ 时间选择器相关 ============
|
||||
|
||||
// 存储选择的时间(null 表示使用当前时间)
|
||||
let selectedTime = null;
|
||||
let timePickerInited = false;
|
||||
|
||||
// 时间选择器当前选中的值
|
||||
let pickerValues = {
|
||||
year: new Date().getFullYear(),
|
||||
month: new Date().getMonth() + 1,
|
||||
day: new Date().getDate(),
|
||||
hour: new Date().getHours(),
|
||||
minute: new Date().getMinutes(),
|
||||
second: new Date().getSeconds()
|
||||
};
|
||||
|
||||
// 获取选择的时间(供 chat.js 使用)
|
||||
export function getSelectedTime() {
|
||||
return selectedTime;
|
||||
}
|
||||
|
||||
// 清除选择的时间
|
||||
export function clearSelectedTime() {
|
||||
selectedTime = null;
|
||||
updateTimeIndicator();
|
||||
}
|
||||
|
||||
// 显示时间选择器
|
||||
function showTimePicker() {
|
||||
const picker = document.getElementById('wechat-time-picker');
|
||||
if (!picker) return;
|
||||
|
||||
// 初始化为当前时间
|
||||
const now = new Date();
|
||||
pickerValues = {
|
||||
year: now.getFullYear(),
|
||||
month: now.getMonth() + 1,
|
||||
day: now.getDate(),
|
||||
hour: now.getHours(),
|
||||
minute: now.getMinutes(),
|
||||
second: now.getSeconds()
|
||||
};
|
||||
|
||||
renderTimePickerColumns();
|
||||
updateTimePickerDisplay();
|
||||
picker.classList.remove('hidden');
|
||||
}
|
||||
|
||||
// 隐藏时间选择器
|
||||
function hideTimePicker() {
|
||||
const picker = document.getElementById('wechat-time-picker');
|
||||
picker?.classList.add('hidden');
|
||||
}
|
||||
|
||||
// 渲染时间选择器列
|
||||
function renderTimePickerColumns() {
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
// 年份:前后5年
|
||||
renderPickerColumn('year', currentYear - 5, currentYear + 5, pickerValues.year, '年');
|
||||
// 月份:1-12
|
||||
renderPickerColumn('month', 1, 12, pickerValues.month, '月');
|
||||
// 日期:根据年月动态计算
|
||||
const daysInMonth = new Date(pickerValues.year, pickerValues.month, 0).getDate();
|
||||
renderPickerColumn('day', 1, daysInMonth, pickerValues.day, '日');
|
||||
// 小时:0-23
|
||||
renderPickerColumn('hour', 0, 23, pickerValues.hour, '时');
|
||||
// 分钟:0-59
|
||||
renderPickerColumn('minute', 0, 59, pickerValues.minute, '分');
|
||||
// 秒:0-59
|
||||
renderPickerColumn('second', 0, 59, pickerValues.second, '秒');
|
||||
}
|
||||
|
||||
// 渲染单个列
|
||||
function renderPickerColumn(type, min, max, selected, suffix) {
|
||||
const container = document.getElementById(`wechat-time-picker-${type}`);
|
||||
if (!container) return;
|
||||
|
||||
let html = '';
|
||||
for (let i = min; i <= max; i++) {
|
||||
const value = type === 'year' ? i : i.toString().padStart(2, '0');
|
||||
const isSelected = i === selected;
|
||||
html += `<div class="wechat-time-picker-item${isSelected ? ' selected' : ''}" data-value="${i}">${value}${suffix}</div>`;
|
||||
}
|
||||
container.innerHTML = html;
|
||||
|
||||
// 滚动到选中项
|
||||
setTimeout(() => {
|
||||
const selectedItem = container.querySelector('.selected');
|
||||
if (selectedItem) {
|
||||
container.scrollTop = selectedItem.offsetTop - container.offsetHeight / 2 + selectedItem.offsetHeight / 2;
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// 更新显示的时间
|
||||
function updateTimePickerDisplay() {
|
||||
const display = document.getElementById('wechat-time-picker-display');
|
||||
if (!display) return;
|
||||
|
||||
const { year, month, day, hour, minute, second } = pickerValues;
|
||||
display.textContent = `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')} ${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}:${second.toString().padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
// 更新输入框旁的时间指示器
|
||||
function updateTimeIndicator() {
|
||||
let indicator = document.getElementById('wechat-time-indicator');
|
||||
|
||||
if (!selectedTime) {
|
||||
indicator?.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!indicator) {
|
||||
const inputArea = document.querySelector('.wechat-chat-input-area');
|
||||
if (!inputArea) return;
|
||||
|
||||
indicator = document.createElement('div');
|
||||
indicator.id = 'wechat-time-indicator';
|
||||
indicator.className = 'wechat-time-indicator';
|
||||
inputArea.insertBefore(indicator, inputArea.firstChild);
|
||||
}
|
||||
|
||||
const date = new Date(selectedTime);
|
||||
const month = date.getMonth() + 1;
|
||||
const day = date.getDate();
|
||||
const hour = date.getHours().toString().padStart(2, '0');
|
||||
const minute = date.getMinutes().toString().padStart(2, '0');
|
||||
|
||||
indicator.innerHTML = `
|
||||
<span class="wechat-time-indicator-text">${month}月${day}日 ${hour}:${minute}</span>
|
||||
<button class="wechat-time-indicator-clear" id="wechat-time-indicator-clear">✕</button>
|
||||
`;
|
||||
|
||||
// 绑定清除按钮
|
||||
document.getElementById('wechat-time-indicator-clear')?.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
clearSelectedTime();
|
||||
});
|
||||
}
|
||||
|
||||
// 初始化时间选择器事件
|
||||
function initTimePickerEvents() {
|
||||
if (timePickerInited) return;
|
||||
timePickerInited = true;
|
||||
|
||||
// 监听列项点击
|
||||
document.addEventListener('click', (e) => {
|
||||
const item = e.target.closest('.wechat-time-picker-item');
|
||||
if (!item) return;
|
||||
|
||||
const column = item.closest('.wechat-time-picker-column');
|
||||
if (!column) return;
|
||||
|
||||
const type = column.dataset.type;
|
||||
const value = parseInt(item.dataset.value);
|
||||
|
||||
// 更新选中值
|
||||
pickerValues[type] = value;
|
||||
|
||||
// 更新选中样式
|
||||
column.querySelectorAll('.wechat-time-picker-item').forEach(el => {
|
||||
el.classList.toggle('selected', parseInt(el.dataset.value) === value);
|
||||
});
|
||||
|
||||
// 如果改变了年或月,需要重新渲染日期列
|
||||
if (type === 'year' || type === 'month') {
|
||||
const daysInMonth = new Date(pickerValues.year, pickerValues.month, 0).getDate();
|
||||
if (pickerValues.day > daysInMonth) {
|
||||
pickerValues.day = daysInMonth;
|
||||
}
|
||||
renderPickerColumn('day', 1, daysInMonth, pickerValues.day, '日');
|
||||
}
|
||||
|
||||
updateTimePickerDisplay();
|
||||
});
|
||||
|
||||
// 确认按钮
|
||||
document.getElementById('wechat-time-picker-confirm')?.addEventListener('click', () => {
|
||||
const { year, month, day, hour, minute, second } = pickerValues;
|
||||
selectedTime = new Date(year, month - 1, day, hour, minute, second).getTime();
|
||||
|
||||
hideTimePicker();
|
||||
updateTimeIndicator();
|
||||
showToast('已设置发送时间', '⏰');
|
||||
});
|
||||
}
|
||||
|
||||
40
chat.js
40
chat.js
@@ -17,7 +17,6 @@ import { startVoiceCall } from './voice-call.js';
|
||||
import { startVideoCall } from './video-call.js';
|
||||
import { showOpenRedPacket, generateRedPacketId } from './red-packet.js';
|
||||
import { showReceiveTransferPage, generateTransferId } from './transfer.js';
|
||||
import { getSelectedTime, clearSelectedTime } from './chat-func-panel.js';
|
||||
|
||||
// 当前聊天的联系人索引
|
||||
export let currentChatIndex = -1;
|
||||
@@ -1393,6 +1392,7 @@ export async function sendMessage(messageText, isMultipleMessages = false, isVoi
|
||||
|
||||
const now = new Date();
|
||||
const timeStr = `${now.getFullYear()}-${(now.getMonth()+1).toString().padStart(2,'0')}-${now.getDate().toString().padStart(2,'0')} ${now.getHours().toString().padStart(2,'0')}:${now.getMinutes().toString().padStart(2,'0')}`;
|
||||
const msgTimestamp = Date.now();
|
||||
|
||||
let messagesToSend = [];
|
||||
if (isMultipleMessages && Array.isArray(messageText)) {
|
||||
@@ -1413,8 +1413,6 @@ export async function sendMessage(messageText, isMultipleMessages = false, isVoi
|
||||
// 清除引用
|
||||
clearQuote();
|
||||
|
||||
const msgTimestamp = Date.now();
|
||||
|
||||
for (let i = 0; i < messagesToSend.length; i++) {
|
||||
const msg = messagesToSend[i];
|
||||
// 只有第一条消息带引用
|
||||
@@ -1453,15 +1451,6 @@ export async function sendMessage(messageText, isMultipleMessages = false, isVoi
|
||||
? `[用户发送了语音消息,内容是:${messagesToSend.join('\n')}]`
|
||||
: messagesToSend.join('\n');
|
||||
|
||||
// 如果有选择的时间,添加时间上下文
|
||||
const selectedTime = getSelectedTime();
|
||||
if (selectedTime) {
|
||||
const timeDate = new Date(selectedTime);
|
||||
const timeStr = `${timeDate.getFullYear()}年${timeDate.getMonth() + 1}月${timeDate.getDate()}日 ${timeDate.getHours().toString().padStart(2, '0')}:${timeDate.getMinutes().toString().padStart(2, '0')}`;
|
||||
combinedMessage = `[当前时间:${timeStr}]\n${combinedMessage}`;
|
||||
clearSelectedTime();
|
||||
}
|
||||
|
||||
// 如果有引用,添加引用上下文
|
||||
if (quote) {
|
||||
let quoteDesc;
|
||||
@@ -1981,15 +1970,6 @@ export async function sendStickerMessage(stickerUrl, description = '') {
|
||||
? `[用户发送了一个表情包:${description}]`
|
||||
: '[用户发送了一个表情包]';
|
||||
|
||||
// 如果有选择的时间,添加时间上下文
|
||||
const selectedTime = getSelectedTime();
|
||||
if (selectedTime) {
|
||||
const timeDate = new Date(selectedTime);
|
||||
const timeStr = `${timeDate.getFullYear()}年${timeDate.getMonth() + 1}月${timeDate.getDate()}日 ${timeDate.getHours().toString().padStart(2, '0')}:${timeDate.getMinutes().toString().padStart(2, '0')}`;
|
||||
aiPrompt = `[当前时间:${timeStr}]\n${aiPrompt}`;
|
||||
clearSelectedTime();
|
||||
}
|
||||
|
||||
const aiResponse = await callAI(contact, aiPrompt);
|
||||
|
||||
// 只有用户还在当前聊天时才隐藏打字指示器
|
||||
@@ -2371,15 +2351,6 @@ export async function sendPhotoMessage(description) {
|
||||
const { callAI } = await import('./ai.js');
|
||||
let aiPrompt = `[用户发送了一张照片,图片描述:${polishedDescription}]`;
|
||||
|
||||
// 如果有选择的时间,添加时间上下文
|
||||
const selectedTime = getSelectedTime();
|
||||
if (selectedTime) {
|
||||
const timeDate = new Date(selectedTime);
|
||||
const timeStr = `${timeDate.getFullYear()}年${timeDate.getMonth() + 1}月${timeDate.getDate()}日 ${timeDate.getHours().toString().padStart(2, '0')}:${timeDate.getMinutes().toString().padStart(2, '0')}`;
|
||||
aiPrompt = `[当前时间:${timeStr}]\n${aiPrompt}`;
|
||||
clearSelectedTime();
|
||||
}
|
||||
|
||||
const aiResponse = await callAI(contact, aiPrompt);
|
||||
|
||||
// 只有用户还在当前聊天时才隐藏打字指示器
|
||||
@@ -2861,15 +2832,6 @@ export async function sendBatchMessages(messages) {
|
||||
const { callAI } = await import('./ai.js');
|
||||
let combinedPrompt = promptParts.join('\n');
|
||||
|
||||
// 如果有选择的时间,添加时间上下文
|
||||
const selectedTime = getSelectedTime();
|
||||
if (selectedTime) {
|
||||
const timeDate = new Date(selectedTime);
|
||||
const timeStr = `${timeDate.getFullYear()}年${timeDate.getMonth() + 1}月${timeDate.getDate()}日 ${timeDate.getHours().toString().padStart(2, '0')}:${timeDate.getMinutes().toString().padStart(2, '0')}`;
|
||||
combinedPrompt = `[当前时间:${timeStr}]\n${combinedPrompt}`;
|
||||
clearSelectedTime();
|
||||
}
|
||||
|
||||
const aiResponse = await callAI(contact, combinedPrompt);
|
||||
|
||||
// 只有用户还在当前聊天时才隐藏打字指示器
|
||||
|
||||
@@ -10,6 +10,7 @@ import { escapeHtml, sleep, formatMessageTime, calculateVoiceDuration, bindImage
|
||||
import { getUserAvatarHTML, refreshChatList, getUserPersonaFromST } from './ui.js';
|
||||
import { getSTChatContext, HAKIMI_HEADER } from './ai.js';
|
||||
import { playMusic as kugouPlayMusic } from './music.js';
|
||||
import { showMessageMenu } from './message-menu.js';
|
||||
|
||||
// 当前群聊的索引
|
||||
export let currentGroupChatIndex = -1;
|
||||
@@ -813,25 +814,29 @@ function renderGroupChatHistory(groupChat, members, chatHistory) {
|
||||
|
||||
// 生成群聊静态语音气泡
|
||||
function generateGroupVoiceBubbleStatic(content, isSelf) {
|
||||
const seconds = calculateVoiceDuration(content);
|
||||
const width = Math.min(50 + seconds * 3, 180);
|
||||
const safeContent = (content || '').toString();
|
||||
const seconds = calculateVoiceDuration(safeContent);
|
||||
const width = Math.min(60 + seconds * 4, 200);
|
||||
const voiceId = 'voice_' + Math.random().toString(36).substring(2, 9);
|
||||
// 用户消息波形朝右,角色消息波形朝左
|
||||
const wavesSvg = isSelf
|
||||
? `<svg viewBox="0 0 24 24" width="20" height="20"><path d="M3 12h2v4H3zM7 8h2v8H7zm4 4h2v6h-2zm4-6h2v10h-2z" fill="currentColor"/></svg>`
|
||||
: `<svg viewBox="0 0 24 24" width="20" height="20"><path d="M19 12h2v4h-2zm-4-4h2v8h-2zm-4 4h2v6h-2zm-4-6h2v10H7z" fill="currentColor"/></svg>`;
|
||||
|
||||
// 用户消息:波形在左,秒数在右
|
||||
// 角色消息:秒数在左,波形在右
|
||||
// WiFi信号样式的三条弧线图标(与单聊保持一致)
|
||||
const wavesSvg = `<svg class="wechat-voice-waves-icon" viewBox="0 0 24 24" width="18" height="18">
|
||||
<circle class="wechat-voice-arc arc1" cx="5" cy="12" r="2" fill="currentColor"/>
|
||||
<path class="wechat-voice-arc arc2" d="M10 8 A 5 5 0 0 1 10 16" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/>
|
||||
<path class="wechat-voice-arc arc3" d="M15 4 A 10 10 0 0 1 15 20" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/>
|
||||
</svg>`;
|
||||
|
||||
// 用户消息:时长在左,波形在右
|
||||
// 角色消息:波形在左,时长在右
|
||||
const bubbleInner = isSelf
|
||||
? `<span class="wechat-voice-waves">${wavesSvg}</span><span class="wechat-voice-duration">${seconds}</span>`
|
||||
: `<span class="wechat-voice-duration">${seconds}</span><span class="wechat-voice-waves">${wavesSvg}</span>`;
|
||||
? `<span class="wechat-voice-duration">${seconds}"</span><span class="wechat-voice-waves">${wavesSvg}</span>`
|
||||
: `<span class="wechat-voice-waves">${wavesSvg}</span><span class="wechat-voice-duration">${seconds}"</span>`;
|
||||
|
||||
return `
|
||||
<div class="wechat-voice-bubble ${isSelf ? 'self' : ''}" style="width: ${width}px" data-voice-id="${voiceId}">
|
||||
<div class="wechat-voice-bubble ${isSelf ? 'self' : ''}" style="width: ${width}px" data-voice-id="${voiceId}" data-voice-content="${escapeHtml(safeContent)}">
|
||||
${bubbleInner}
|
||||
</div>
|
||||
<div class="wechat-voice-text hidden" id="${voiceId}">${escapeHtml(content)}</div>
|
||||
<div class="wechat-voice-text hidden" id="${voiceId}">${escapeHtml(safeContent)}</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -866,17 +871,43 @@ function generateGroupMusicCardStatic(musicInfo) {
|
||||
`;
|
||||
}
|
||||
|
||||
// 绑定群聊语音气泡点击事件
|
||||
// 绑定群聊语音气泡点击事件(播放动画 + 显示上方菜单,与单聊保持一致)
|
||||
function bindGroupVoiceBubbleEvents(container) {
|
||||
const voiceBubbles = container.querySelectorAll('.wechat-voice-bubble:not([data-bound])');
|
||||
voiceBubbles.forEach(bubble => {
|
||||
bubble.setAttribute('data-bound', 'true');
|
||||
bubble.addEventListener('click', () => {
|
||||
const voiceId = bubble.dataset.voiceId;
|
||||
const textEl = document.getElementById(voiceId);
|
||||
if (textEl) {
|
||||
textEl.classList.toggle('hidden');
|
||||
|
||||
// 获取父消息元素
|
||||
const messageEl = bubble.closest('.wechat-message');
|
||||
|
||||
// 计算消息索引
|
||||
const allMessages = Array.from(container.querySelectorAll('.wechat-message'));
|
||||
const msgIndex = allMessages.indexOf(messageEl);
|
||||
|
||||
// 点击事件:播放动画 + 显示上方菜单
|
||||
bubble.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
// 切换播放状态
|
||||
const isPlaying = bubble.classList.contains('playing');
|
||||
if (isPlaying) {
|
||||
bubble.classList.remove('playing');
|
||||
} else {
|
||||
// 停止其他正在播放的语音
|
||||
document.querySelectorAll('.wechat-voice-bubble.playing').forEach(b => {
|
||||
b.classList.remove('playing');
|
||||
});
|
||||
bubble.classList.add('playing');
|
||||
|
||||
// 模拟播放时间后停止
|
||||
const duration = parseInt(bubble.querySelector('.wechat-voice-duration')?.textContent) || 3;
|
||||
setTimeout(() => {
|
||||
bubble.classList.remove('playing');
|
||||
}, duration * 1000);
|
||||
}
|
||||
|
||||
// 显示上方菜单
|
||||
showMessageMenu(bubble, msgIndex, e);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
4
main.js
4
main.js
@@ -1634,8 +1634,8 @@ function init() {
|
||||
}
|
||||
|
||||
if (typeof jQuery === 'function') {
|
||||
jQuery(() => init());
|
||||
jQuery(() => setTimeout(init, 500));
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', init, { once: true });
|
||||
document.addEventListener('DOMContentLoaded', () => setTimeout(init, 500), { once: true });
|
||||
}
|
||||
|
||||
|
||||
@@ -205,28 +205,6 @@ export function generatePhoneHTML() {
|
||||
<input type="file" id="wechat-chat-bg-file" accept="image/*" style="display: none;">
|
||||
</div>
|
||||
</div>
|
||||
<!-- 图片裁剪弹窗 -->
|
||||
<div id="wechat-cropper-modal" class="wechat-modal hidden">
|
||||
<div class="wechat-modal-content wechat-modal-cropper" style="position: relative; max-width: 350px; max-height: 90vh; overflow: hidden;">
|
||||
<button class="wechat-modal-close-x" id="wechat-cropper-cancel">×</button>
|
||||
<div class="wechat-modal-title">裁剪图片</div>
|
||||
<div class="wechat-cropper-container" id="wechat-cropper-container">
|
||||
<canvas id="wechat-cropper-canvas"></canvas>
|
||||
<div class="wechat-cropper-overlay" id="wechat-cropper-overlay">
|
||||
<div class="wechat-cropper-box" id="wechat-cropper-box">
|
||||
<div class="wechat-cropper-handle nw"></div>
|
||||
<div class="wechat-cropper-handle ne"></div>
|
||||
<div class="wechat-cropper-handle sw"></div>
|
||||
<div class="wechat-cropper-handle se"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wechat-cropper-hint" style="font-size: 11px; color: var(--wechat-text-secondary); text-align: center; margin: 8px 0;">拖动选择区域,拖动角落调整大小</div>
|
||||
<div class="wechat-modal-actions">
|
||||
<button class="wechat-btn wechat-btn-primary" id="wechat-cropper-confirm">确认裁剪</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wechat-chat">
|
||||
<div class="wechat-chat-messages" id="wechat-chat-messages"></div>
|
||||
</div>
|
||||
@@ -248,7 +226,6 @@ export function generatePhoneHTML() {
|
||||
<div class="wechat-func-page" data-page="1">
|
||||
<div class="wechat-func-grid">
|
||||
<div class="wechat-func-item" data-func="voice"><div class="wechat-func-icon"><svg viewBox="0 0 24 24"><path d="M12 1a4 4 0 00-4 4v7a4 4 0 008 0V5a4 4 0 00-4-4z" stroke="currentColor" stroke-width="1.5" fill="none"/><path d="M19 10v2a7 7 0 01-14 0v-2M12 19v4M8 23h8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none"/></svg></div><span>语音输入</span></div>
|
||||
<div class="wechat-func-item" data-func="time"><div class="wechat-func-icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="1.5" fill="none"/><path d="M12 6v6l4 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/></svg></div><span>时间</span></div>
|
||||
<div class="wechat-func-item" data-func="listen"><div class="wechat-func-icon"><svg viewBox="0 0 24 24"><path d="M3 18v-6a9 9 0 0118 0v6" stroke="currentColor" stroke-width="1.5" fill="none"/><path d="M21 19a2 2 0 01-2 2h-1a2 2 0 01-2-2v-3a2 2 0 012-2h3v5z" stroke="currentColor" stroke-width="1.5" fill="none"/><path d="M3 19a2 2 0 002 2h1a2 2 0 002-2v-3a2 2 0 00-2-2H3v5z" stroke="currentColor" stroke-width="1.5" fill="none"/></svg></div><span>一起听</span></div>
|
||||
<div class="wechat-func-item" data-func="music"><div class="wechat-func-icon"><svg viewBox="0 0 24 24"><path d="M9 18V5l12-2v13" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/><circle cx="6" cy="18" r="3" stroke="currentColor" stroke-width="1.5" fill="none"/><circle cx="18" cy="16" r="3" stroke="currentColor" stroke-width="1.5" fill="none"/></svg></div><span>音乐</span></div>
|
||||
</div>
|
||||
@@ -270,36 +247,6 @@ export function generatePhoneHTML() {
|
||||
<button class="wechat-btn wechat-expand-send" id="wechat-expand-send">发送</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 时间选择器面板 -->
|
||||
<div class="wechat-time-picker hidden" id="wechat-time-picker">
|
||||
<div class="wechat-time-picker-header">
|
||||
<span class="wechat-time-picker-title">发送时间</span>
|
||||
</div>
|
||||
<div class="wechat-time-picker-display" id="wechat-time-picker-display">2025-12-22 21:33:19</div>
|
||||
<div class="wechat-time-picker-columns">
|
||||
<div class="wechat-time-picker-column" data-type="year">
|
||||
<div class="wechat-time-picker-items" id="wechat-time-picker-year"></div>
|
||||
</div>
|
||||
<div class="wechat-time-picker-column" data-type="month">
|
||||
<div class="wechat-time-picker-items" id="wechat-time-picker-month"></div>
|
||||
</div>
|
||||
<div class="wechat-time-picker-column" data-type="day">
|
||||
<div class="wechat-time-picker-items" id="wechat-time-picker-day"></div>
|
||||
</div>
|
||||
<div class="wechat-time-picker-column" data-type="hour">
|
||||
<div class="wechat-time-picker-items" id="wechat-time-picker-hour"></div>
|
||||
</div>
|
||||
<div class="wechat-time-picker-column" data-type="minute">
|
||||
<div class="wechat-time-picker-items" id="wechat-time-picker-minute"></div>
|
||||
</div>
|
||||
<div class="wechat-time-picker-column" data-type="second">
|
||||
<div class="wechat-time-picker-items" id="wechat-time-picker-second"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wechat-time-picker-footer">
|
||||
<button class="wechat-time-picker-confirm" id="wechat-time-picker-confirm">完成</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 表情面板 -->
|
||||
<div class="wechat-emoji-panel hidden" id="wechat-emoji-panel">
|
||||
<div class="wechat-emoji-tabs">
|
||||
@@ -342,6 +289,29 @@ export function generatePhoneHTML() {
|
||||
${generateTransferPageHTML()}
|
||||
${generateReceiveTransferPageHTML()}
|
||||
${generateTransferRefundConfirmHTML()}
|
||||
|
||||
<!-- 图片裁剪弹窗(全局) -->
|
||||
<div id="wechat-cropper-modal" class="wechat-modal hidden">
|
||||
<div class="wechat-modal-content wechat-modal-cropper" style="position: relative; max-width: 350px; max-height: 90vh; overflow: hidden;">
|
||||
<button class="wechat-modal-close-x" id="wechat-cropper-cancel">×</button>
|
||||
<div class="wechat-modal-title">裁剪图片</div>
|
||||
<div class="wechat-cropper-container" id="wechat-cropper-container">
|
||||
<canvas id="wechat-cropper-canvas"></canvas>
|
||||
<div class="wechat-cropper-overlay" id="wechat-cropper-overlay">
|
||||
<div class="wechat-cropper-box" id="wechat-cropper-box">
|
||||
<div class="wechat-cropper-handle nw"></div>
|
||||
<div class="wechat-cropper-handle ne"></div>
|
||||
<div class="wechat-cropper-handle sw"></div>
|
||||
<div class="wechat-cropper-handle se"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wechat-cropper-hint" style="font-size: 11px; color: var(--wechat-text-secondary); text-align: center; margin: 8px 0;">拖动选择区域,拖动角落调整大小</div>
|
||||
<div class="wechat-modal-actions">
|
||||
<button class="wechat-btn wechat-btn-primary" id="wechat-cropper-confirm">确认裁剪</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 隐藏的文件输入 -->
|
||||
|
||||
159
style.css
159
style.css
@@ -8767,165 +8767,6 @@
|
||||
color: rgba(255,255,255,0.7);
|
||||
}
|
||||
|
||||
/* ===== 时间选择器 ===== */
|
||||
.wechat-time-picker {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: var(--wechat-white);
|
||||
border-top: 1px solid var(--wechat-border);
|
||||
z-index: 100;
|
||||
animation: slideUp 0.25s ease;
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.wechat-time-picker.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.wechat-time-picker-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid var(--wechat-border);
|
||||
}
|
||||
|
||||
.wechat-time-picker-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: var(--wechat-text);
|
||||
}
|
||||
|
||||
.wechat-time-picker-confirm {
|
||||
background: var(--wechat-green);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 6px 16px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.wechat-time-picker-confirm:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.wechat-time-picker-display {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
font-size: 14px;
|
||||
color: var(--wechat-green);
|
||||
font-weight: 500;
|
||||
background: var(--wechat-bg);
|
||||
}
|
||||
|
||||
.wechat-time-picker-columns {
|
||||
display: flex;
|
||||
height: 180px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wechat-time-picker-column {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
scroll-snap-type: y mandatory;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
/* 隐藏滚动条 */
|
||||
.wechat-time-picker-column::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.wechat-time-picker-column {
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
.wechat-time-picker-item {
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
color: var(--wechat-text-secondary);
|
||||
cursor: pointer;
|
||||
scroll-snap-align: center;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
|
||||
.wechat-time-picker-item:active {
|
||||
background: var(--wechat-bg);
|
||||
}
|
||||
|
||||
.wechat-time-picker-item.selected {
|
||||
color: var(--wechat-text);
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* 时间指示器(输入框上方) */
|
||||
.wechat-time-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 6px 12px;
|
||||
background: rgba(7, 193, 96, 0.1);
|
||||
border-bottom: 1px solid var(--wechat-border);
|
||||
}
|
||||
|
||||
.wechat-time-indicator-text {
|
||||
font-size: 12px;
|
||||
color: var(--wechat-green);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.wechat-time-indicator-clear {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: none;
|
||||
background: var(--wechat-text-secondary);
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
font-size: 10px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0.6;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.wechat-time-indicator-clear:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* 暗色模式时间选择器 */
|
||||
.wechat-dark .wechat-time-picker {
|
||||
background: var(--wechat-white);
|
||||
}
|
||||
|
||||
.wechat-dark .wechat-time-picker-display {
|
||||
background: var(--wechat-bg);
|
||||
}
|
||||
|
||||
.wechat-dark .wechat-time-indicator {
|
||||
background: rgba(62, 181, 117, 0.15);
|
||||
}
|
||||
|
||||
/* ========== 一起听功能样式 ========== */
|
||||
|
||||
/* 搜索页面 */
|
||||
|
||||
Reference in New Issue
Block a user