实现一个支持移动端的工单系统
我来为你设计一个完整的移动端工单系统。这个系统将包含用户和管理员两个视角,支持工单的创建、处理、跟踪等核心功能。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>移动工单系统</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
* {
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background-color: #f5f7fa;
overflow-x: hidden;
}
.app-container {
max-width: 768px;
margin: 0 auto;
background-color: white;
min-height: 100vh;
position: relative;
box-shadow: 0 0 20px rgba(0,0,0,0.05);
}
.page {
display: none;
animation: slideIn 0.3s ease-out;
}
.page.active {
display: block;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.ticket-card {
transition: all 0.3s ease;
border: 1px solid #e5e7eb;
}
.ticket-card:active {
transform: scale(0.98);
background-color: #f9fafb;
}
.status-badge {
display: inline-flex;
align-items: center;
padding: 4px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
}
.status-pending {
background-color: #fef3c7;
color: #92400e;
}
.status-processing {
background-color: #dbeafe;
color: #1e40af;
}
.status-completed {
background-color: #d1fae5;
color: #065f46;
}
.status-closed {
background-color: #f3f4f6;
color: #6b7280;
}
.bottom-nav {
position: fixed;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 100%;
max-width: 768px;
background-color: white;
border-top: 1px solid #e5e7eb;
z-index: 1000;
}
.nav-item {
flex: 1;
text-align: center;
padding: 8px 0;
transition: color 0.3s ease;
}
.nav-item.active {
color: #3b82f6;
}
.fab {
position: fixed;
bottom: 80px;
right: 20px;
width: 56px;
height: 56px;
border-radius: 50%;
background-color: #3b82f6;
color: white;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
transition: all 0.3s ease;
z-index: 100;
}
.fab:active {
transform: scale(0.9);
}
.input-group {
position: relative;
margin-bottom: 16px;
}
.input-group input,
.input-group textarea,
.input-group select {
width: 100%;
padding: 12px 16px;
border: 1px solid #d1d5db;
border-radius: 8px;
font-size: 16px;
transition: all 0.3s ease;
}
.input-group input:focus,
.input-group textarea:focus,
.input-group select:focus {
outline: none;
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.input-group label {
position: absolute;
left: 16px;
top: 12px;
color: #6b7280;
transition: all 0.3s ease;
pointer-events: none;
}
.input-group input:focus ~ label,
.input-group input:not(:placeholder-shown) ~ label,
.input-group textarea:focus ~ label,
.input-group textarea:not(:placeholder-shown) ~ label {
top: -8px;
left: 12px;
font-size: 12px;
background-color: white;
padding: 0 4px;
color: #3b82f6;
}
.priority-high {
color: #dc2626;
}
.priority-medium {
color: #d97706;
}
.priority-low {
color: #059669;
}
.skeleton {
background: linear-gradient(90deg, #f3f4f6 25%, #e5e7eb 50%, #f3f4f6 75%);
background-size: 200% 100%;
animation: loading 1.5s infinite;
}
@keyframes loading {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
.pull-to-refresh {
position: absolute;
top: -60px;
left: 50%;
transform: translateX(-50%);
color: #6b7280;
font-size: 14px;
transition: all 0.3s ease;
}
.pull-to-refresh.active {
top: 20px;
}
.toast {
position: fixed;
top: 50px;
left: 50%;
transform: translateX(-50%) translateY(-100px);
background-color: #1f2937;
color: white;
padding: 12px 24px;
border-radius: 8px;
font-size: 14px;
z-index: 2000;
transition: transform 0.3s ease;
}
.toast.show {
transform: translateX(-50%) translateY(0);
}
</style>
</head>
<body>
<div class="app-container">
<!-- 登录页面 -->
<div id="loginPage" class="page active">
<div class="h-screen flex flex-col justify-center items-center px-6">
<div class="w-full max-w-sm">
<div class="text-center mb-8">
<div class="w-20 h-20 bg-blue-500 rounded-2xl flex items-center justify-center mx-auto mb-4">
<i class="fas fa-ticket-alt text-white text-3xl"></i>
</div>
<h1 class="text-2xl font-bold text-gray-900">移动工单系统</h1>
<p class="text-gray-600 mt-2">欢迎使用,请登录</p>
</div>
<form id="loginForm" class="space-y-4">
<div class="input-group">
<input type="text" id="username" placeholder=" " required>
<label>用户名</label>
</div>
<div class="input-group">
<input type="password" id="password" placeholder=" " required>
<label>密码</label>
</div>
<div class="flex items-center space-x-4">
<label class="flex items-center">
<input type="radio" name="role" value="user" class="mr-2" checked>
<span class="text-sm">用户</span>
</label>
<label class="flex items-center">
<input type="radio" name="role" value="admin" class="mr-2">
<span class="text-sm">管理员</span>
</label>
</div>
<button type="submit" class="w-full bg-blue-500 text-white py-3 rounded-lg font-medium transition-all hover:bg-blue-600 active:scale-95">
登录
</button>
</form>
</div>
</div>
</div>
<!-- 用户端 - 工单列表 -->
<div id="userTicketListPage" class="page">
<div class="bg-white border-b">
<div class="px-4 py-3 flex items-center justify-between">
<h1 class="text-lg font-semibold">我的工单</h1>
<button onclick="logout()" class="text-gray-600">
<i class="fas fa-sign-out-alt"></i>
</button>
</div>
</div>
<div class="relative">
<div id="pullToRefresh" class="pull-to-refresh">
<i class="fas fa-arrow-down mr-2"></i>下拉刷新
</div>
<div id="ticketList" class="p-4 space-y-3">
<!-- 工单列表将在这里动态生成 -->
</div>
</div>
<button onclick="showCreateTicketPage()" class="fab">
<i class="fas fa-plus text-xl"></i>
</button>
</div>
<!-- 用户端 - 创建工单 -->
<div id="createTicketPage" class="page">
<div class="bg-white border-b">
<div class="px-4 py-3 flex items-center">
<button onclick="showUserTicketList()" class="mr-3">
<i class="fas fa-arrow-left"></i>
</button>
<h1 class="text-lg font-semibold">创建工单</h1>
</div>
</div>
<form id="createTicketForm" class="p-4 space-y-4">
<div class="input-group">
<select id="ticketType" required>
<option value="">请选择工单类型</option>
<option value="repair">维修申请</option>
<option value="complaint">投诉建议</option>
<option value="consultation">咨询求助</option>
<option value="other">其他</option>
</select>
<label>工单类型</label>
</div>
<div class="input-group">
<select id="ticketPriority" required>
<option value="">请选择优先级</option>
<option value="low">低</option>
<option value="medium">中</option>
<option value="high">高</option>
</select>
<label>优先级</label>
</div>
<div class="input-group">
<input type="text" id="ticketTitle" placeholder=" " required>
<label>工单标题</label>
</div>
<div class="input-group">
<textarea id="ticketContent" rows="4" placeholder=" " required></textarea>
<label>问题描述</label>
</div>
<div class="input-group">
<input type="file" id="ticketAttachment" accept="image/*">
<label>添加图片(可选)</label>
</div>
<button type="submit" class="w-full bg-blue-500 text-white py-3 rounded-lg font-medium transition-all hover:bg-blue-600 active:scale-95">
提交工单
</button>
</form>
</div>
<!-- 用户端 - 工单详情 -->
<div id="ticketDetailPage" class="page">
<div class="bg-white border-b">
<div class="px-4 py-3 flex items-center">
<button onclick="showUserTicketList()" class="mr-3">