u
This commit is contained in:
1 parent
04491e14a3
commit
12fdf320c2
12 files changed
+2493
-824
No files matched your search
@@ -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>
|
||||
|
||||
Reference in new issue
Block a user