This commit is contained in:
oneao committed 2026-04-27 17:26:15 +08:00
1 parent 04491e14a3
commit 12fdf320c2
12 files changed
+2493 -824

No files matched your search

+349 -132
View File
@@ -1,159 +1,376 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>多空间 App 原型</title>
<script src="https://cdn.tailwindcss.com"></script>
<meta charset="UTF-8" />
<title>附件组件(最终完整版)</title>
<style>
body {
margin: 0;
font-family: Arial;
background: #f5f6f8;
}
.layout {
display: flex;
height: 100vh;
}
/* 左 */
.left {
width: 200px;
background: #fff;
border-right: 1px solid #eee;
padding: 10px;
}
/* 中 */
.center {
flex: 1;
display: flex;
flex-direction: column;
}
.grid {
flex: 1;
padding: 12px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 12px;
overflow: auto;
}
/* 卡片 */
.card {
position: relative;
background: #fff;
border-radius: 10px;
border: 1px solid transparent;
display: flex;
flex-direction: column;
cursor: pointer;
}
.card:hover {
border-color: #1677ff;
}
.card.selected {
background: #eaf2ff;
border-color: #1677ff;
}
/* checkbox */
.check {
position: absolute;
top: 6px;
left: 6px;
z-index: 5;
}
/* 右上角 */
.top-actions {
position: absolute;
top: 6px;
right: 6px;
display: flex;
gap: 4px;
}
/* 状态 */
.status {
background: #ff4d4f;
color: #fff;
font-size: 10px;
padding: 2px 5px;
border-radius: 3px;
}
/* 删除按钮 */
.delete-btn {
border: none;
background: #fff;
color: #ff4d4f;
cursor: pointer;
font-size: 12px;
border-radius: 4px;
padding: 2px 4px;
opacity: 0;
transition: 0.2s;
}
.card:hover .delete-btn {
opacity: 1;
}
.delete-btn:hover {
background: #fff1f0;
}
/* 缩略图 */
.thumb {
height: 100px;
background: #f0f2f5;
display:flex;
align-items:center;
justify-content:center;
}
.thumb img {
width:100%;
height:100%;
object-fit:cover;
}
/* info */
.info {
padding: 8px;
}
.name {
font-size: 13px;
}
.meta {
font-size: 12px;
color: #888;
}
/* 操作 */
.actions {
display: flex;
border-top: 1px solid #eee;
}
.actions button {
flex: 1;
border: none;
background: #fff;
padding: 6px 0;
cursor: pointer;
font-size: 12px;
}
.actions button:hover {
background: #f5f6f8;
}
/* 更多菜单 */
.more-menu {
position: absolute;
bottom: 38px;
right: 6px;
background: #fff;
border: 1px solid #eee;
border-radius: 6px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
display: none;
min-width: 100px;
}
.more-menu div {
padding: 6px 10px;
cursor: pointer;
font-size: 12px;
}
.more-menu div:hover {
background: #f5f6f8;
}
/* 右侧 */
.right {
width: 300px;
background: #fff;
border-left: 1px solid #eee;
padding: 10px;
}
.preview {
height: 200px;
background: #f0f2f5;
display:flex;
align-items:center;
justify-content:center;
}
.preview img {
max-width: 100%;
max-height: 100%;
}
</style>
</head>
<body class="bg-gray-100">
<body>
<div class="max-w-md mx-auto h-screen flex flex-col bg-gray-100">
<div class="layout">
<!-- 顶部 -->
<div class="bg-white shadow px-4 py-3 flex justify-between items-center">
<div id="pageTitle" class="font-semibold text-lg">首页</div>
<div class="left">分类区域(可扩展)</div>
<button onclick="openSpaceModal()"
class="text-sm bg-gray-100 px-3 py-1 rounded-lg">
<span id="currentSpace">空间A</span>
</button>
<div class="center">
<div class="grid" id="grid"></div>
</div>
<!-- 内容 -->
<div class="flex-1 overflow-auto p-4" id="content">
<!-- 首页 -->
<div id="homePage">
<div class="h-32 bg-gradient-to-r from-blue-500 to-purple-500 rounded-2xl mb-4"></div>
<!-- 功能 -->
<div class="grid grid-cols-4 gap-4 mb-4">
<div class="bg-white p-3 rounded-xl shadow text-center">任务</div>
<div class="bg-white p-3 rounded-xl shadow text-center">聊天</div>
<div class="bg-white p-3 rounded-xl shadow text-center">文件</div>
<div class="bg-white p-3 rounded-xl shadow text-center">报表</div>
</div>
<!-- 最近 -->
<div class="bg-white p-4 rounded-xl shadow">
<div class="font-semibold mb-2">最近内容</div>
<div class="text-sm text-gray-500">任务:优化UI设计</div>
<div class="text-sm text-gray-500">消息:项目讨论</div>
</div>
</div>
<!-- 消息 -->
<div id="messagePage" class="hidden space-y-3">
<div class="bg-white p-4 rounded-xl shadow">用户1:你好</div>
<div class="bg-white p-4 rounded-xl shadow">用户2:项目OK</div>
<div class="bg-white p-4 rounded-xl shadow">用户3:收到</div>
</div>
<!-- 我的 -->
<div id="minePage" class="hidden space-y-4">
<div class="bg-white p-4 rounded-xl shadow flex items-center gap-3">
<div class="w-12 h-12 bg-gray-300 rounded-full"></div>
<div>
<div class="font-semibold">张三</div>
<div class="text-xs text-gray-400">ID: 10001</div>
</div>
</div>
<div class="bg-white p-4 rounded-xl shadow">
<div class="font-semibold mb-2">当前空间</div>
<div class="flex justify-between items-center">
<span id="currentSpace2">空间A</span>
<button onclick="openSpaceModal()" class="text-blue-500 text-sm">切换</button>
</div>
</div>
<div class="bg-white p-4 rounded-xl shadow space-y-2">
<div class="font-semibold">空间操作</div>
<button class="w-full bg-blue-500 text-white py-2 rounded-lg">创建空间</button>
<button class="w-full bg-green-500 text-white py-2 rounded-lg">加入空间</button>
</div>
</div>
<div class="right">
<div class="preview" id="previewBox">暂无预览</div>
<div id="detail">请选择文件</div>
</div>
<!-- 底部导航 -->
<div class="bg-white border-t flex justify-around py-3">
<button onclick="switchPage('home')" id="navHome" class="text-blue-500">首页</button>
<button onclick="switchPage('message')" id="navMessage" class="text-gray-500">消息</button>
<button onclick="switchPage('mine')" id="navMine" class="text-gray-500">我的</button>
</div>
</div>
<!-- 空间弹层 -->
<div id="spaceModal"
class="fixed inset-0 bg-black/40 hidden flex items-end">
<div class="bg-white w-full rounded-t-2xl p-4">
<div class="text-center font-semibold mb-4">选择空间</div>
<div class="space-y-2">
<div onclick="switchSpace('空间A')" class="p-3 bg-gray-100 rounded-lg cursor-pointer">空间A</div>
<div onclick="switchSpace('空间B')" class="p-3 bg-gray-100 rounded-lg cursor-pointer">空间B</div>
<div onclick="switchSpace('空间C')" class="p-3 bg-gray-100 rounded-lg cursor-pointer">空间C</div>
</div>
<div class="mt-4 space-y-2">
<button class="w-full bg-blue-500 text-white py-2 rounded-lg">创建空间</button>
<button class="w-full bg-green-500 text-white py-2 rounded-lg">加入空间</button>
</div>
<button onclick="closeSpaceModal()" class="w-full mt-3 text-gray-500">关闭</button>
</div>
</div>
<script>
let currentPage = "home";
let currentSpace = "空间A";
const files = [
{ id: 1, name: "合同.pdf", type: "doc", size: "800KB", date: "2026-04-25" },
{ id: 2, name: "设计图.png", type: "img", url: "https://picsum.photos/400/300?1", size: "1.2MB", date: "2026-04-24", status: "未上传" }
];
function switchPage(page) {
currentPage = page;
let selected = new Set();
document.getElementById("homePage").classList.add("hidden");
document.getElementById("messagePage").classList.add("hidden");
document.getElementById("minePage").classList.add("hidden");
/* 渲染 */
function render() {
const grid = document.getElementById("grid");
grid.innerHTML = "";
document.getElementById(page + "Page").classList.remove("hidden");
files.forEach(f => {
const card = document.createElement("div");
card.className = "card" + (selected.has(f.id) ? " selected" : "");
document.getElementById("pageTitle").innerText =
page === "home" ? "首页" :
page === "message" ? "消息" : "我的";
card.onclick = () => toggleSelect(f.id);
// 导航高亮
["navHome","navMessage","navMine"].forEach(id=>{
document.getElementById(id).classList.remove("text-blue-500");
document.getElementById(id).classList.add("text-gray-500");
});
/* checkbox */
const check = document.createElement("input");
check.type = "checkbox";
check.className = "check";
check.checked = selected.has(f.id);
check.onclick = (e) => {
e.stopPropagation();
toggleSelect(f.id);
};
document.getElementById("nav" + page.charAt(0).toUpperCase() + page.slice(1))
.classList.add("text-blue-500");
}
/* 右上角 */
const top = document.createElement("div");
top.className = "top-actions";
function openSpaceModal() {
document.getElementById("spaceModal").classList.remove("hidden");
}
if (f.status) {
const st = document.createElement("div");
st.className = "status";
st.innerText = f.status;
top.appendChild(st);
}
function closeSpaceModal() {
document.getElementById("spaceModal").classList.add("hidden");
}
const del = document.createElement("button");
del.className = "delete-btn";
del.innerText = "🗑";
del.onclick = (e) => {
e.stopPropagation();
if (confirm("确定删除?")) deleteFile(f.id);
};
function switchSpace(space) {
currentSpace = space;
document.getElementById("currentSpace").innerText = space;
document.getElementById("currentSpace2").innerText = space;
closeSpaceModal();
}
top.appendChild(del);
/* thumb */
const thumb = document.createElement("div");
thumb.className = "thumb";
thumb.innerHTML = f.type === "img"
? `<img src="${f.url}">`
: "📄";
/* info */
const info = document.createElement("div");
info.className = "info";
info.innerHTML = `
<div class="name">${f.name}</div>
<div class="meta">${f.date} · ${f.size}</div>
`;
/* actions */
const actions = document.createElement("div");
actions.className = "actions";
const btnView = createBtn("预览", () => preview(f));
const btnDown = createBtn("下载", () => alert("下载 " + f.name));
/* 更多 */
const btnMore = document.createElement("button");
btnMore.innerText = "⋯";
const menu = document.createElement("div");
menu.className = "more-menu";
const rename = document.createElement("div");
rename.innerText = "重命名";
rename.onclick = (e) => {
e.stopPropagation();
const n = prompt("新文件名", f.name);
if (n) f.name = n;
render();
};
const remark = document.createElement("div");
remark.innerText = "备注";
remark.onclick = (e) => {
e.stopPropagation();
const r = prompt("备注", f.remark || "");
f.remark = r;
};
menu.append(rename, remark);
btnMore.onclick = (e) => {
e.stopPropagation();
closeMenus();
menu.style.display = "block";
};
actions.append(btnView, btnDown, btnMore);
card.append(check, top, thumb, info, actions, menu);
grid.appendChild(card);
});
}
/* 工具函数 */
function createBtn(text, fn) {
const b = document.createElement("button");
b.innerText = text;
b.onclick = (e) => {
e.stopPropagation();
fn();
};
return b;
}
function toggleSelect(id) {
selected.has(id) ? selected.delete(id) : selected.add(id);
render();
}
function preview(f) {
const box = document.getElementById("previewBox");
const detail = document.getElementById("detail");
box.innerHTML = f.type === "img"
? `<img src="${f.url}">`
: "📄 " + f.name;
detail.innerHTML = `${f.name}<br>${f.size}<br>${f.date}`;
}
function deleteFile(id) {
const i = files.findIndex(f => f.id === id);
if (i > -1) files.splice(i, 1);
selected.delete(id);
render();
}
function closeMenus() {
document.querySelectorAll(".more-menu").forEach(m => m.style.display = "none");
}
document.addEventListener("click", closeMenus);
/* init */
render();
</script>
</body>