```js
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>工作台</title>
<script src="
https://unpkg.com/vue@3/dist/vue.global.js"></script>
<link
href="
https://cdn.jsdelivr.net/npm/remixicon@4.5.0/fonts/remixicon.css"
rel="stylesheet"
/>
<style>
:root {
--primary-bg: #f8fafc;
--card-bg: #ffffff;
--text-primary: #1f2937;
--text-secondary: #64748b;
--shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
background: var(--primary-bg);
color: var(--text-primary);
min-height: 100vh;
}
.app-container {
display: flex;
min-height: 100vh;
}
.sidebar {
width: 64px;
background: #ffffff;
padding: 16px 0;
display: flex;
flex-direction: column;
align-items: center;
gap: 24px;
box-shadow: var(--shadow);
z-index: 10;
}
.sidebar-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
cursor: pointer;
color: var(--text-secondary);
transition: all 0.2s;
padding: 8px;
border-radius: 8px;
}
.sidebar-item:hover {
color: var(--text-primary);
background: #f1f5f9;
}
.main-content {
flex: 1;
padding: 24px;
}
.search-bar {
background: #ffffff;
border-radius: 8px;
padding: 12px 24px;
margin-bottom: 24px;
display: flex;
align-items: center;
gap: 12px;
box-shadow: var(--shadow);
}
.search-input {
background: none;
border: none;
color: var(--text-primary);
flex: 1;
font-size: 16px;
outline: none;
}
.widget-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 24px;
margin-top: 24px;
}
.widget-card {
background: var(--card-bg);
border-radius: 12px;
padding: 20px;
box-shadow: var(--shadow);
}
.clock-widget {
text-align: center;
font-size: 48px;
font-weight: 300;
background: linear-gradient(135deg, #60a5fa, #3b82f6);
color: white;
}
.date-text {
font-size: 14px;
color: rgba(255, 255, 255, 0.9);
margin-top: 8px;
}
.weather-widget {
display: flex;
flex-direction: column;
gap: 16px;
background: linear-gradient(135deg, #34d399, #10b981);
color: white;
}
.weather-current {
font-size: 36px;
display: flex;
align-items: center;
gap: 12px;
}
.weather-forecast {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 12px;
padding-top: 16px;
border-top: 1px solid rgba(255, 255, 255, 0.2);
}
.forecast-item {
text-align: center;
font-size: 14px;
}
.app-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
gap: 16px;
margin-top: 24px;
}
.app-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
cursor: pointer;
transition: transform 0.2s;
}
.app-item:hover {
transform: translateY(-4px);
}
.app-icon {
width: 48px;
height: 48px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
background: #f1f5f9;
color: #3b82f6;
transition: all 0.2s;
}
.app-item:hover .app-icon {
background: #3b82f6;
color: white;
}
.app-name {
font-size: 12px;
color: var(--text-secondary);
text-align: center;
}
</style>
</head>
<body>
<div id="app">
<div class="app-container">
<div class="sidebar">
<div class="sidebar-item" v-for="item in sidebarItems" :key="
item.id">
<i :class="item.icon"></i>
<span>{{ item.label }}</span>
</div>
</div>
<div class="main-content">
<div class="search-bar">
<i class="ri-search-line"></i>
<input
type="text"
class="search-input"
placeholder="输入搜索内容"
v-model="searchText"
/>
</div>
<div class="widget-grid">
<div class="widget-card clock-widget">
<div>{{ currentTime }}</div>
<div class="date-text">{{ currentDate }}</div>
</div>
<div class="widget-card weather-widget">
<div class="weather-current">
<i class="ri-sun-line"></i>
<span>{{ weather.current }}°</span>
</div>
<div class="weather-forecast">
<div
class="forecast-item"
v-for="item in weather.forecast"
:key="
item.date"
>
<div>{{
item.date }}</div>
<i :class="item.icon"></i>
<div>{{ item.temp }}°</div>
</div>
</div>
</div>
</div>
<div class="app-grid">
<div class="app-item" v-for="app in apps" :key="
app.id">
<div class="app-icon">
<i :class="app.icon"></i>
</div>
<div class="app-name">{{
app.name }}</div>
</div>
</div>
</div>
</div>
</div>
<script>
const { createApp, ref, onMounted } = Vue;
createApp({
setup() {
const searchText = ref("");
const currentTime = ref("");
const currentDate = ref("");
const sidebarItems = ref([
{ id: 1, icon: "ri-home-line", label: "主页" },
{ id: 2, icon: "ri-code-line", label: "开发" },
{ id: 3, icon: "ri-palette-line", label: "设计" },
{ id: 4, icon: "ri-product-hunt-line", label: "产品" },
]);
const weather = ref({
current: 19,
forecast: [
{ date: "周一", icon: "ri-sun-line", temp: 22 },
{ date: "周二", icon: "ri-cloudy-line", temp: 20 },
{ date: "周三", icon: "ri-sun-cloudy-line", temp: 21 },
{ date: "周四", icon: "ri-drizzle-line", temp: 19 },
{ date: "周五", icon: "ri-sun-line", temp: 23 },
{ date: "周六", icon: "ri-cloudy-line", temp: 20 },
],
});
const apps = ref([
{ id: 1, icon: "ri-bilibili-line", name: "哔哩哔哩" },
{ id: 2, icon: "ri-zhihu-line", name: "知乎" },
{ id: 3, icon: "ri-wechat-line", name: "微信" },
{ id: 4, icon: "ri-alipay-line", name: "支付宝" },
{ id: 5, icon: "ri-douyin-line", name: "抖音" },
{ id: 6, icon: "ri-qq-line", name: "QQ" },
{ id: 7, icon: "ri-weibo-line", name: "微博" },
{ id: 8, icon: "ri-shopping-bag-line", name: "淘宝" },
]);
const updateTime = () => {
const now = new Date();
currentTime.value = now.toLocaleTimeString("zh-CN", {
hour: "2-digit",
minute: "2-digit",
});
currentDate.value = now.toLocaleDateString("zh-CN", {
year: "numeric",
month: "long",
day: "numeric",
weekday: "long",
});
};
onMounted(() => {
updateTime();
setInterval(updateTime, 1000);
});
return {
searchText,
currentTime,
currentDate,
sidebarItems,
weather,
apps,
};
},
}).mount("#app");
</script>
</body>
</html>
```