jiaxing.zhou

Merge branch 'dev'

...@@ -7,10 +7,32 @@ export {} ...@@ -7,10 +7,32 @@ export {}
7 7
8 declare module 'vue' { 8 declare module 'vue' {
9 export interface GlobalComponents { 9 export interface GlobalComponents {
10 + ElButton: typeof import('element-plus/es')['ElButton']
11 + ElCard: typeof import('element-plus/es')['ElCard']
12 + ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
13 + ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
14 + ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
15 + ElDialog: typeof import('element-plus/es')['ElDialog']
16 + ElForm: typeof import('element-plus/es')['ElForm']
17 + ElFormItem: typeof import('element-plus/es')['ElFormItem']
18 + ElIcon: typeof import('element-plus/es')['ElIcon']
19 + ElInput: typeof import('element-plus/es')['ElInput']
20 + ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
21 + ElOption: typeof import('element-plus/es')['ElOption']
22 + ElPagination: typeof import('element-plus/es')['ElPagination']
23 + ElRadio: typeof import('element-plus/es')['ElRadio']
24 + ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
25 + ElSelect: typeof import('element-plus/es')['ElSelect']
26 + ElTable: typeof import('element-plus/es')['ElTable']
27 + ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
28 + ElTag: typeof import('element-plus/es')['ElTag']
10 Header: typeof import('./src/components/layout/Header.vue')['default'] 29 Header: typeof import('./src/components/layout/Header.vue')['default']
11 RouterLink: typeof import('vue-router')['RouterLink'] 30 RouterLink: typeof import('vue-router')['RouterLink']
12 RouterView: typeof import('vue-router')['RouterView'] 31 RouterView: typeof import('vue-router')['RouterView']
13 Sidebar: typeof import('./src/components/layout/Sidebar.vue')['default'] 32 Sidebar: typeof import('./src/components/layout/Sidebar.vue')['default']
14 SidebarItem: typeof import('./src/components/layout/SidebarItem.vue')['default'] 33 SidebarItem: typeof import('./src/components/layout/SidebarItem.vue')['default']
15 } 34 }
35 + export interface ComponentCustomProperties {
36 + vLoading: typeof import('element-plus/es')['ElLoadingDirective']
37 + }
16 } 38 }
......
...@@ -147,6 +147,7 @@ const menuItems = ref([ ...@@ -147,6 +147,7 @@ const menuItems = ref([
147 { name: '产品管理', path: '/main/product', icon: '📦' }, 147 { name: '产品管理', path: '/main/product', icon: '📦' },
148 { name: '经销商管理', path: '/main/dealer', icon: '🏢' }, 148 { name: '经销商管理', path: '/main/dealer', icon: '🏢' },
149 { name: '返利管理', path: '/main/rebate', icon: '💰' }, 149 { name: '返利管理', path: '/main/rebate', icon: '💰' },
150 + { name: '异常工单', path: '/main/exception-workorder', icon: '⚠️' },
150 { 151 {
151 name: '系统设置', 152 name: '系统设置',
152 icon: '⚙️', 153 icon: '⚙️',
......
...@@ -153,6 +153,24 @@ const staticRoutes: RouteRecordRaw[] = [ ...@@ -153,6 +153,24 @@ const staticRoutes: RouteRecordRaw[] = [
153 } 153 }
154 }, 154 },
155 { 155 {
156 + path: 'exception-workorder',
157 + name: 'ExceptionWorkorder',
158 + component: () => import('@/views/exceptionWorkorder/index.vue'),
159 + meta: {
160 + title: '异常工单',
161 + requiresAuth: true
162 + }
163 + },
164 + {
165 + path: 'test-menu',
166 + name: 'TestMenu',
167 + component: () => import('@/views/test-menu.vue'),
168 + meta: {
169 + title: '菜单测试',
170 + requiresAuth: true
171 + }
172 + },
173 + {
156 path: 'settings', 174 path: 'settings',
157 name: 'Settings', 175 name: 'Settings',
158 component: () => import('@/views/settings/index.vue'), 176 component: () => import('@/views/settings/index.vue'),
......
...@@ -2,137 +2,73 @@ ...@@ -2,137 +2,73 @@
2 <div class="exception-workorder-container"> 2 <div class="exception-workorder-container">
3 <!-- 搜索区域 --> 3 <!-- 搜索区域 -->
4 <div class="search-section"> 4 <div class="search-section">
5 - <div class="search-form"> 5 + <div class="search-row">
6 - <div class="form-row"> 6 + <div class="search-item">
7 - <div class="form-item">
8 <label>工单编号:</label> 7 <label>工单编号:</label>
9 - <el-input 8 + <input
10 v-model="searchParams.workorderNo" 9 v-model="searchParams.workorderNo"
11 - placeholder="请输入工单编号"
12 - clearable
13 class="search-input" 10 class="search-input"
11 + placeholder="请输入工单编号"
14 /> 12 />
15 </div> 13 </div>
16 - <div class="form-item"> 14 + <div class="search-item">
17 <label>关联订单号:</label> 15 <label>关联订单号:</label>
18 - <el-input 16 + <input
19 v-model="searchParams.orderNo" 17 v-model="searchParams.orderNo"
20 - placeholder="请输入关联订单号"
21 - clearable
22 class="search-input" 18 class="search-input"
19 + placeholder="请输入关联订单号"
23 /> 20 />
24 </div> 21 </div>
25 - <div class="form-item"> 22 + <div class="search-item">
26 <label>经销商编码:</label> 23 <label>经销商编码:</label>
27 - <el-input 24 + <input
28 v-model="searchParams.dealerCode" 25 v-model="searchParams.dealerCode"
29 - placeholder="请输入经销商编码"
30 - clearable
31 class="search-input" 26 class="search-input"
27 + placeholder="请输入经销商编码"
32 /> 28 />
33 </div> 29 </div>
34 - <div class="form-item"> 30 + <div class="search-item">
35 <label>经销商名称:</label> 31 <label>经销商名称:</label>
36 - <el-input 32 + <input
37 v-model="searchParams.dealerName" 33 v-model="searchParams.dealerName"
38 - placeholder="请输入经销商名称"
39 - clearable
40 class="search-input" 34 class="search-input"
35 + placeholder="请输入经销商名称"
41 /> 36 />
42 </div> 37 </div>
43 </div> 38 </div>
44 - <div class="form-row"> 39 + <div class="search-row">
45 - <div class="form-item"> 40 + <div class="search-item">
46 <label>工单状态:</label> 41 <label>工单状态:</label>
47 - <el-select 42 + <select v-model="searchParams.workorderStatus" class="search-select">
48 - v-model="searchParams.workorderStatus" 43 + <option value="">所有</option>
49 - placeholder="请选择工单状态" 44 + <option v-for="(name, value) in WORKORDER_STATUS" :key="value" :value="Number(value)">{{ name }}</option>
50 - clearable 45 + </select>
51 - class="search-select"
52 - >
53 - <el-option
54 - v-for="(name, value) in WORKORDER_STATUS"
55 - :key="value"
56 - :label="name"
57 - :value="Number(value)"
58 - />
59 - </el-select>
60 </div> 46 </div>
61 - <div class="form-item"> 47 + <div class="search-item">
62 <label>异常类型:</label> 48 <label>异常类型:</label>
63 - <el-select 49 + <select v-model="searchParams.exceptionType" class="search-select">
64 - v-model="searchParams.exceptionType" 50 + <option value="">所有</option>
65 - placeholder="请选择异常类型" 51 + <option v-for="(name, value) in EXCEPTION_TYPE" :key="value" :value="Number(value)">{{ name }}</option>
66 - clearable 52 + </select>
67 - class="search-select"
68 - >
69 - <el-option
70 - v-for="(name, value) in EXCEPTION_TYPE"
71 - :key="value"
72 - :label="name"
73 - :value="Number(value)"
74 - />
75 - </el-select>
76 </div> 53 </div>
77 - <div class="form-item"> 54 + <div class="search-item">
78 <label>严重程度:</label> 55 <label>严重程度:</label>
79 - <el-select 56 + <select v-model="searchParams.severityLevel" class="search-select">
80 - v-model="searchParams.severityLevel" 57 + <option value="">所有</option>
81 - placeholder="请选择严重程度" 58 + <option v-for="(name, value) in SEVERITY_LEVEL" :key="value" :value="Number(value)">{{ name }}</option>
82 - clearable 59 + </select>
83 - class="search-select"
84 - >
85 - <el-option
86 - v-for="(name, value) in SEVERITY_LEVEL"
87 - :key="value"
88 - :label="name"
89 - :value="Number(value)"
90 - />
91 - </el-select>
92 </div> 60 </div>
93 - <div class="form-item"> 61 + <div class="search-item">
94 <label>处理人:</label> 62 <label>处理人:</label>
95 - <el-input 63 + <input
96 v-model="searchParams.handlerUser" 64 v-model="searchParams.handlerUser"
97 - placeholder="请输入处理人"
98 - clearable
99 class="search-input" 65 class="search-input"
66 + placeholder="请输入处理人"
100 /> 67 />
101 </div> 68 </div>
102 - </div> 69 + <div class="search-actions">
103 - <div class="form-row"> 70 + <button @click="handleSearch" class="search-btn">🔍 搜索</button>
104 - <div class="form-item"> 71 + <button @click="handleReset" class="reset-btn">🔄 重置</button>
105 - <label>开始日期:</label>
106 - <el-date-picker
107 - v-model="searchParams.startTime"
108 - type="datetime"
109 - placeholder="选择开始日期"
110 - format="YYYY-MM-DD HH:mm:ss"
111 - value-format="YYYY-MM-DD HH:mm:ss"
112 - class="search-date"
113 - />
114 - </div>
115 - <div class="form-item">
116 - <label>结束日期:</label>
117 - <el-date-picker
118 - v-model="searchParams.endTime"
119 - type="datetime"
120 - placeholder="选择结束日期"
121 - format="YYYY-MM-DD HH:mm:ss"
122 - value-format="YYYY-MM-DD HH:mm:ss"
123 - class="search-date"
124 - />
125 - </div>
126 - <div class="form-item">
127 - <el-button type="primary" @click="handleSearch" class="search-btn">
128 - <el-icon><Search /></el-icon>
129 - 搜索
130 - </el-button>
131 - <el-button @click="handleReset" class="reset-btn">
132 - <el-icon><Refresh /></el-icon>
133 - 重置
134 - </el-button>
135 - </div>
136 </div> 72 </div>
137 </div> 73 </div>
138 </div> 74 </div>
...@@ -140,99 +76,136 @@ ...@@ -140,99 +76,136 @@
140 <!-- 操作按钮区域 --> 76 <!-- 操作按钮区域 -->
141 <div class="action-section"> 77 <div class="action-section">
142 <div class="action-buttons"> 78 <div class="action-buttons">
143 - <el-button type="warning" @click="handleAdd" class="add-btn"> 79 + <button @click="handleAdd" class="action-btn primary">✨ 新增</button>
144 - <el-icon><Plus /></el-icon> 80 + <button @click="handleBatchProcess" class="action-btn success">🔧 批量处理</button>
145 - 新增数据 81 + <button @click="handleExport" class="action-btn secondary">📋 导出</button>
146 - </el-button>
147 - <el-button type="success" @click="handleBatchProcess" class="batch-btn">
148 - <el-icon><Operation /></el-icon>
149 - 批量处理
150 - </el-button>
151 - <el-button @click="handleExport" class="export-btn">
152 - <el-icon><Download /></el-icon>
153 - 导出
154 - </el-button>
155 </div> 82 </div>
156 </div> 83 </div>
157 84
158 <!-- 数据表格 --> 85 <!-- 数据表格 -->
159 <div class="table-section"> 86 <div class="table-section">
160 - <el-table 87 + <div class="table-header">
161 - :data="workorderList" 88 + <div class="table-controls">
162 - v-loading="loading" 89 + <button @click="handleTableSearch" class="control-btn">🔍</button>
163 - @selection-change="handleSelectionChange" 90 + <button @click="handleTableRefresh" class="control-btn">🔄</button>
164 - class="data-table" 91 + <button @click="handleTableExport" class="control-btn">📋</button>
165 - stripe 92 + <button @click="handleTableViewToggle" class="control-btn">⊞</button>
166 - border 93 + </div>
167 - > 94 + </div>
168 - <el-table-column type="selection" width="55" /> 95 +
169 - <el-table-column prop="workorderId" label="工单ID" width="120" /> 96 + <div class="table-container">
170 - <el-table-column prop="workorderNo" label="工单编号" width="180" /> 97 + <div v-if="loading" class="loading-overlay">
171 - <el-table-column prop="orderNo" label="关联订单号" width="180" /> 98 + <div class="loading-spinner">加载中...</div>
172 - <el-table-column prop="dealerName" label="经销商名称" width="150" /> 99 + </div>
173 - <el-table-column prop="workorderStatusName" label="工单状态" width="100"> 100 + <table class="data-table">
174 - <template #default="{ row }"> 101 + <thead>
175 - <el-tag :color="getWorkorderStatusColor(row.workorderStatus)"> 102 + <tr>
176 - {{ row.workorderStatusName }} 103 + <th>
177 - </el-tag> 104 + <input
178 - </template> 105 + type="checkbox"
179 - </el-table-column> 106 + class="select-all"
180 - <el-table-column prop="exceptionTypeName" label="异常类型" width="120" /> 107 + v-model="selectAll"
181 - <el-table-column prop="severityLevelName" label="严重程度" width="100"> 108 + @change="handleSelectAll"
182 - <template #default="{ row }"> 109 + />
183 - <el-tag :color="getSeverityLevelColor(row.severityLevel)"> 110 + </th>
184 - {{ row.severityLevelName }} 111 + <th>工单ID</th>
185 - </el-tag> 112 + <th class="sortable">工单编号 ↕️</th>
186 - </template> 113 + <th>关联订单号</th>
187 - </el-table-column> 114 + <th>经销商名称</th>
188 - <el-table-column prop="createTime" label="日期" width="180" sortable> 115 + <th>工单状态</th>
189 - <template #default="{ row }"> 116 + <th>异常类型</th>
190 - {{ formatDateTime(row.createTime) }} 117 + <th>严重程度</th>
191 - </template> 118 + <th class="sortable">日期 ↕️</th>
192 - </el-table-column> 119 + <th>操作</th>
193 - <el-table-column label="操作" width="200" fixed="right"> 120 + </tr>
194 - <template #default="{ row }"> 121 + </thead>
195 - <el-button 122 + <tbody>
196 - type="primary" 123 + <tr v-for="workorder in workorderList" :key="workorder.workorderId">
197 - size="small" 124 + <td>
198 - @click="handleEditStatus(row)" 125 + <input
199 - class="action-btn" 126 + type="checkbox"
200 - > 127 + class="row-select"
201 - 编辑状态 128 + :value="workorder"
202 - </el-button> 129 + v-model="selectedWorkorders"
203 - <el-button 130 + />
204 - type="info" 131 + </td>
205 - size="small" 132 + <td>{{ workorder.workorderId }}</td>
206 - @click="handleViewLogs(row)" 133 + <td>{{ workorder.workorderNo }}</td>
207 - class="action-btn" 134 + <td>{{ workorder.orderNo }}</td>
135 + <td>{{ workorder.dealerName }}</td>
136 + <td>
137 + <span
138 + class="status-badge"
139 + :class="getWorkorderStatusClass(workorder.workorderStatus)"
208 > 140 >
209 - 处理日志 141 + {{ workorder.workorderStatusName }}
210 - </el-button> 142 + </span>
211 - <el-button 143 + </td>
212 - type="success" 144 + <td>{{ workorder.exceptionTypeName }}</td>
213 - size="small" 145 + <td>
214 - @click="handleViewDetail(row)" 146 + <span
215 - class="action-btn" 147 + class="severity-badge"
148 + :class="getSeverityLevelClass(workorder.severityLevel)"
216 > 149 >
217 - 详情 150 + {{ workorder.severityLevelName }}
218 - </el-button> 151 + </span>
219 - </template> 152 + </td>
220 - </el-table-column> 153 + <td>{{ formatDateTime(workorder.createTime) }}</td>
221 - </el-table> 154 + <td>
155 + <div class="table-actions">
156 + <button @click="handleEditStatus(workorder)" class="table-btn edit">编辑状态</button>
157 + <button @click="handleViewLogs(workorder)" class="table-btn info">处理日志</button>
158 + <button @click="handleViewDetail(workorder)" class="table-btn view">详情</button>
159 + </div>
160 + </td>
161 + </tr>
162 + </tbody>
163 + </table>
164 + </div>
222 </div> 165 </div>
223 166
224 <!-- 分页 --> 167 <!-- 分页 -->
225 <div class="pagination-section"> 168 <div class="pagination-section">
226 - <el-pagination 169 + <div class="pagination-info">
227 - v-model:current-page="pagination.pageNum" 170 + <span>共 {{ pagination.total }} 条</span>
228 - v-model:page-size="pagination.pageSize" 171 + <select v-model="pagination.pageSize" @change="handlePageSizeChange" class="page-size-select">
229 - :page-sizes="[10, 20, 50, 100]" 172 + <option value="10">10条/页</option>
230 - :total="pagination.total" 173 + <option value="20">20条/页</option>
231 - layout="total, sizes, prev, pager, next, jumper" 174 + <option value="50">50条/页</option>
232 - @size-change="handleSizeChange" 175 + <option value="100">100条/页</option>
233 - @current-change="handleCurrentChange" 176 + </select>
234 - class="pagination" 177 + </div>
178 + <div class="pagination-controls">
179 + <button
180 + @click="handleCurrentChange(1)"
181 + :disabled="pagination.pageNum === 1"
182 + class="page-btn"
183 + >首页</button>
184 + <button
185 + @click="handleCurrentChange(pagination.pageNum - 1)"
186 + :disabled="pagination.pageNum === 1"
187 + class="page-btn"
188 + >上一页</button>
189 + <span class="page-info">{{ pagination.pageNum }} / {{ Math.ceil(pagination.total / pagination.pageSize) }}</span>
190 + <button
191 + @click="handleCurrentChange(pagination.pageNum + 1)"
192 + :disabled="pagination.pageNum >= Math.ceil(pagination.total / pagination.pageSize)"
193 + class="page-btn"
194 + >下一页</button>
195 + <button
196 + @click="handleCurrentChange(Math.ceil(pagination.total / pagination.pageSize))"
197 + :disabled="pagination.pageNum >= Math.ceil(pagination.total / pagination.pageSize)"
198 + class="page-btn"
199 + >末页</button>
200 + <span>跳至</span>
201 + <input
202 + v-model="jumpPage"
203 + @keyup.enter="handleJumpPage"
204 + class="jump-input"
205 + placeholder="页码"
235 /> 206 />
207 + <span>页</span>
208 + </div>
236 </div> 209 </div>
237 210
238 <!-- 新增/编辑对话框 --> 211 <!-- 新增/编辑对话框 -->
...@@ -513,6 +486,8 @@ const workorderList = ref<ExceptionWorkorderInfo[]>([]) ...@@ -513,6 +486,8 @@ const workorderList = ref<ExceptionWorkorderInfo[]>([])
513 const selectedWorkorders = ref<ExceptionWorkorderInfo[]>([]) 486 const selectedWorkorders = ref<ExceptionWorkorderInfo[]>([])
514 const workorderDetail = ref<ExceptionWorkorderInfo | null>(null) 487 const workorderDetail = ref<ExceptionWorkorderInfo | null>(null)
515 const workorderLogs = ref<any[]>([]) 488 const workorderLogs = ref<any[]>([])
489 +const selectAll = ref(false)
490 +const jumpPage = ref<number | string>('')
516 491
517 // 分页数据 492 // 分页数据
518 const pagination = reactive({ 493 const pagination = reactive({
...@@ -588,6 +563,27 @@ const statusFormRules = { ...@@ -588,6 +563,27 @@ const statusFormRules = {
588 ] 563 ]
589 } 564 }
590 565
566 +// 获取工单状态类型
567 +const getWorkorderStatusType = (status: number) => {
568 + switch (status) {
569 + case 1: return 'warning' // 待处理
570 + case 2: return 'primary' // 处理中
571 + case 3: return 'success' // 已解决
572 + case 4: return 'info' // 已关闭
573 + default: return 'info'
574 + }
575 +}
576 +
577 +// 获取严重程度类型
578 +const getSeverityLevelType = (level: number) => {
579 + switch (level) {
580 + case 1: return 'danger' // 高
581 + case 2: return 'warning' // 中
582 + case 3: return 'success' // 低
583 + default: return 'info'
584 + }
585 +}
586 +
591 // 获取异常工单列表 587 // 获取异常工单列表
592 const fetchWorkorders = async () => { 588 const fetchWorkorders = async () => {
593 try { 589 try {
...@@ -603,6 +599,10 @@ const fetchWorkorders = async () => { ...@@ -603,6 +599,10 @@ const fetchWorkorders = async () => {
603 if (response && response.records) { 599 if (response && response.records) {
604 workorderList.value = response.records 600 workorderList.value = response.records
605 pagination.total = response.total 601 pagination.total = response.total
602 + } else if (response && Array.isArray(response)) {
603 + // 如果直接返回数组
604 + workorderList.value = response
605 + pagination.total = response.length
606 } else { 606 } else {
607 workorderList.value = [] 607 workorderList.value = []
608 pagination.total = 0 608 pagination.total = 0
...@@ -797,9 +797,70 @@ const handleDownload = (url: string) => { ...@@ -797,9 +797,70 @@ const handleDownload = (url: string) => {
797 797
798 // 格式化日期时间 798 // 格式化日期时间
799 const formatDateTime = (dateTime: string) => { 799 const formatDateTime = (dateTime: string) => {
800 + if (!dateTime) return '-'
800 return dayjs(dateTime).format('YYYY-MM-DD HH:mm:ss') 801 return dayjs(dateTime).format('YYYY-MM-DD HH:mm:ss')
801 } 802 }
802 803
804 +// 获取工单状态样式类
805 +const getWorkorderStatusClass = (status: number) => {
806 + switch (status) {
807 + case 1: return 'pending' // 待处理
808 + case 2: return 'processing' // 处理中
809 + case 3: return 'resolved' // 已解决
810 + case 4: return 'closed' // 已关闭
811 + default: return 'unknown'
812 + }
813 +}
814 +
815 +// 获取严重程度样式类
816 +const getSeverityLevelClass = (level: number) => {
817 + switch (level) {
818 + case 1: return 'high' // 高
819 + case 2: return 'medium' // 中
820 + case 3: return 'low' // 低
821 + default: return 'unknown'
822 + }
823 +}
824 +
825 +// 表格操作方法
826 +const handleSelectAll = () => {
827 + if (selectAll.value) {
828 + selectedWorkorders.value = [...workorderList.value]
829 + } else {
830 + selectedWorkorders.value = []
831 + }
832 +}
833 +
834 +const handleTableSearch = () => {
835 + handleSearch()
836 +}
837 +
838 +const handleTableRefresh = () => {
839 + fetchWorkorders()
840 +}
841 +
842 +const handleTableExport = () => {
843 + handleExport()
844 +}
845 +
846 +const handleTableViewToggle = () => {
847 + // 表格视图切换逻辑
848 + console.log('表格视图切换')
849 +}
850 +
851 +const handleJumpPage = () => {
852 + const page = Number(jumpPage.value)
853 + if (page && page > 0 && page <= Math.ceil(pagination.total / pagination.pageSize)) {
854 + handleCurrentChange(page)
855 + jumpPage.value = ''
856 + }
857 +}
858 +
859 +const handlePageSizeChange = () => {
860 + pagination.pageNum = 1
861 + fetchWorkorders()
862 +}
863 +
803 // 组件挂载 864 // 组件挂载
804 onMounted(() => { 865 onMounted(() => {
805 fetchWorkorders() 866 fetchWorkorders()
...@@ -808,93 +869,400 @@ onMounted(() => { ...@@ -808,93 +869,400 @@ onMounted(() => {
808 869
809 <style scoped> 870 <style scoped>
810 .exception-workorder-container { 871 .exception-workorder-container {
811 - padding: 20px; 872 + padding: 0px;
812 background: #f5f5f5; 873 background: #f5f5f5;
813 min-height: 100vh; 874 min-height: 100vh;
814 } 875 }
815 876
877 +/* 搜索区域样式 */
816 .search-section { 878 .search-section {
817 background: white; 879 background: white;
818 - padding: 20px; 880 + padding: 16px 20px;
819 - border-radius: 8px; 881 + border-bottom: 1px solid #e0e0e0;
820 - margin-bottom: 20px;
821 - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
822 -}
823 -
824 -.search-form {
825 - display: flex;
826 - flex-direction: column;
827 - gap: 15px;
828 } 882 }
829 883
830 -.form-row { 884 +.search-row {
831 display: flex; 885 display: flex;
832 - gap: 20px; 886 + gap: 25px;
833 align-items: center; 887 align-items: center;
834 flex-wrap: wrap; 888 flex-wrap: wrap;
889 + margin-bottom: 12px;
835 } 890 }
836 891
837 -.form-item { 892 +.search-row:last-child {
893 + margin-bottom: 0;
894 +}
895 +
896 +.search-item {
838 display: flex; 897 display: flex;
839 align-items: center; 898 align-items: center;
840 gap: 8px; 899 gap: 8px;
841 - min-width: 200px; 900 + flex: 0 0 auto;
842 } 901 }
843 902
844 -.form-item label { 903 +.search-item label {
845 - font-weight: 500; 904 + color: #666;
846 - color: #333; 905 + font-size: 14px;
906 + width: 90px;
847 white-space: nowrap; 907 white-space: nowrap;
848 - min-width: 80px; 908 + text-align: right;
909 +}
910 +
911 +.search-input {
912 + width: 180px;
913 + height: 32px;
914 + border: 1px solid #ddd;
915 + border-radius: 4px;
916 + padding: 0 8px;
917 + font-size: 14px;
849 } 918 }
850 919
851 -.search-input, 920 +.search-select {
852 -.search-select, 921 + width: 160px;
853 -.search-date { 922 + height: 32px;
854 - width: 200px; 923 + border: 1px solid #ddd;
924 + border-radius: 4px;
925 + padding: 0 8px;
926 + font-size: 14px;
927 + background: white;
928 +}
929 +
930 +.search-actions {
931 + margin-left: auto;
932 + display: flex;
933 + gap: 10px;
934 +}
935 +
936 +.search-btn, .reset-btn {
937 + padding: 6px 16px;
938 + border: none;
939 + border-radius: 4px;
940 + cursor: pointer;
941 + font-size: 14px;
942 + height: 32px;
943 +}
944 +
945 +.search-btn {
946 + background: #007bff;
947 + color: white;
855 } 948 }
856 949
857 -.search-btn,
858 .reset-btn { 950 .reset-btn {
859 - margin-left: 10px; 951 + background: #6c757d;
952 + color: white;
860 } 953 }
861 954
955 +/* 操作按钮区域样式 */
862 .action-section { 956 .action-section {
863 background: white; 957 background: white;
864 - padding: 15px 20px; 958 + padding: 12px 20px 12px 20px;
865 - border-radius: 8px; 959 + border-bottom: 1px solid #e0e0e0;
866 - margin-bottom: 20px;
867 - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
868 } 960 }
869 961
870 -.action-buttons { 962 +.action-section .action-buttons {
871 display: flex; 963 display: flex;
872 gap: 10px; 964 gap: 10px;
965 + justify-content: flex-start;
966 + align-items: center;
967 + margin: 0;
968 + padding: 0;
969 +}
970 +
971 +.action-btn {
972 + padding: 6px 16px;
973 + border: none;
974 + border-radius: 4px;
975 + cursor: pointer;
976 + font-size: 14px;
977 + height: 32px;
978 + font-weight: 500;
873 } 979 }
874 980
981 +.action-btn.primary {
982 + background: #007bff;
983 + color: white;
984 +}
985 +
986 +.action-btn.success {
987 + background: #28a745;
988 + color: white;
989 +}
990 +
991 +.action-btn.secondary {
992 + background: #6c757d;
993 + color: white;
994 +}
995 +
996 +/* 表格区域样式 */
875 .table-section { 997 .table-section {
876 background: white; 998 background: white;
877 - border-radius: 8px; 999 + margin-bottom: 0;
878 - overflow: hidden; 1000 +}
879 - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); 1001 +
880 - margin-bottom: 20px; 1002 +.table-header {
1003 + padding: 10px 20px;
1004 + border-bottom: 1px solid #eee;
1005 + display: flex;
1006 + justify-content: flex-end;
1007 +}
1008 +
1009 +.table-controls {
1010 + display: flex;
1011 + gap: 5px;
1012 +}
1013 +
1014 +.control-btn {
1015 + padding: 4px 8px;
1016 + border: 1px solid #ddd;
1017 + background: white;
1018 + border-radius: 4px;
1019 + cursor: pointer;
1020 + font-size: 12px;
1021 +}
1022 +
1023 +.table-container {
1024 + position: relative;
1025 + overflow-x: auto;
1026 +}
1027 +
1028 +.loading-overlay {
1029 + position: absolute;
1030 + top: 0;
1031 + left: 0;
1032 + right: 0;
1033 + bottom: 0;
1034 + background: rgba(255, 255, 255, 0.8);
1035 + display: flex;
1036 + align-items: center;
1037 + justify-content: center;
1038 + z-index: 10;
1039 +}
1040 +
1041 +.loading-spinner {
1042 + padding: 20px;
1043 + font-size: 16px;
1044 + color: #666;
881 } 1045 }
882 1046
883 .data-table { 1047 .data-table {
884 width: 100%; 1048 width: 100%;
1049 + border-collapse: collapse;
1050 + font-size: 14px;
1051 +}
1052 +
1053 +.data-table th {
1054 + background: #f8f9fa;
1055 + border: 1px solid #ddd;
1056 + padding: 12px 8px;
1057 + text-align: left;
1058 + font-weight: 600;
1059 + color: #333;
1060 + white-space: nowrap;
1061 +}
1062 +
1063 +.data-table td {
1064 + border: 1px solid #ddd;
1065 + padding: 12px 8px;
1066 + vertical-align: middle;
1067 +}
1068 +
1069 +.data-table tbody tr:nth-child(even) {
1070 + background: #f8f9fa;
1071 +}
1072 +
1073 +.data-table tbody tr:hover {
1074 + background: #e9ecef;
1075 +}
1076 +
1077 +.sortable {
1078 + cursor: pointer;
1079 + user-select: none;
885 } 1080 }
886 1081
1082 +.select-all, .row-select {
1083 + margin: 0;
1084 +}
1085 +
1086 +.status-badge, .severity-badge {
1087 + padding: 2px 8px;
1088 + border-radius: 12px;
1089 + font-size: 12px;
1090 + font-weight: 500;
1091 + display: inline-block;
1092 +}
1093 +
1094 +.status-badge.pending {
1095 + background: #fff3cd;
1096 + color: #856404;
1097 +}
1098 +
1099 +.status-badge.processing {
1100 + background: #d1ecf1;
1101 + color: #0c5460;
1102 +}
1103 +
1104 +.status-badge.resolved {
1105 + background: #d4edda;
1106 + color: #155724;
1107 +}
1108 +
1109 +.status-badge.closed {
1110 + background: #f8d7da;
1111 + color: #721c24;
1112 +}
1113 +
1114 +.severity-badge.high {
1115 + background: #f8d7da;
1116 + color: #721c24;
1117 +}
1118 +
1119 +.severity-badge.medium {
1120 + background: #fff3cd;
1121 + color: #856404;
1122 +}
1123 +
1124 +.severity-badge.low {
1125 + background: #d4edda;
1126 + color: #155724;
1127 +}
1128 +
1129 +.table-actions {
1130 + display: flex;
1131 + gap: 4px;
1132 + flex-wrap: wrap;
1133 +}
1134 +
1135 +.table-btn {
1136 + padding: 2px 8px;
1137 + border: none;
1138 + border-radius: 4px;
1139 + cursor: pointer;
1140 + font-size: 12px;
1141 + font-weight: 500;
1142 +}
1143 +
1144 +.table-btn.edit {
1145 + background: #007bff;
1146 + color: white;
1147 +}
1148 +
1149 +.table-btn.info {
1150 + background: #6c757d;
1151 + color: white;
1152 +}
1153 +
1154 +.table-btn.view {
1155 + background: #28a745;
1156 + color: white;
1157 +}
1158 +
1159 +/* 状态标签样式 */
1160 +.status-tag {
1161 + font-weight: 500;
1162 + border-radius: 4px;
1163 +}
1164 +
1165 +.severity-tag {
1166 + font-weight: 500;
1167 + border-radius: 4px;
1168 +}
1169 +
1170 +/* 表格内操作按钮容器 */
1171 +.table-actions {
1172 + display: flex;
1173 + gap: 8px;
1174 + justify-content: center;
1175 + align-items: center;
1176 + flex-wrap: wrap;
1177 + padding: 0 4px;
1178 +}
1179 +
1180 +/* 操作按钮样式 */
887 .action-btn { 1181 .action-btn {
888 - margin-right: 5px; 1182 + padding: 4px 8px;
1183 + font-size: 12px;
1184 + border-radius: 4px;
1185 + font-weight: 500;
1186 + min-width: 60px;
1187 + height: 28px;
1188 + display: inline-flex;
1189 + align-items: center;
1190 + justify-content: center;
1191 + white-space: nowrap;
889 } 1192 }
890 1193
1194 +.action-btn:hover {
1195 + transform: translateY(-1px);
1196 + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
1197 +}
1198 +
1199 +/* 分页区域样式 */
891 .pagination-section { 1200 .pagination-section {
1201 + background: white;
1202 + padding: 12px 20px;
1203 + border-top: 1px solid #e0e0e0;
892 display: flex; 1204 display: flex;
893 - justify-content: center; 1205 + justify-content: space-between;
1206 + align-items: center;
1207 +}
1208 +
1209 +.pagination-info {
1210 + display: flex;
1211 + align-items: center;
1212 + gap: 10px;
1213 + font-size: 14px;
1214 + color: #666;
1215 +}
1216 +
1217 +.page-size-select {
1218 + height: 28px;
1219 + border: 1px solid #ddd;
1220 + border-radius: 4px;
1221 + padding: 0 8px;
1222 + font-size: 14px;
1223 +}
1224 +
1225 +.pagination-controls {
1226 + display: flex;
1227 + align-items: center;
1228 + gap: 8px;
1229 + font-size: 14px;
1230 +}
1231 +
1232 +.page-btn {
1233 + padding: 4px 12px;
1234 + border: 1px solid #ddd;
894 background: white; 1235 background: white;
895 - padding: 20px; 1236 + border-radius: 4px;
896 - border-radius: 8px; 1237 + cursor: pointer;
897 - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); 1238 + font-size: 14px;
1239 +}
1240 +
1241 +.page-btn:disabled {
1242 + background: #f8f9fa;
1243 + color: #6c757d;
1244 + cursor: not-allowed;
1245 +}
1246 +
1247 +.page-btn:not(:disabled):hover {
1248 + background: #007bff;
1249 + color: white;
1250 + border-color: #007bff;
1251 +}
1252 +
1253 +.page-info {
1254 + margin: 0 8px;
1255 + color: #666;
1256 +}
1257 +
1258 +.jump-input {
1259 + width: 50px;
1260 + height: 28px;
1261 + border: 1px solid #ddd;
1262 + border-radius: 4px;
1263 + padding: 0 8px;
1264 + text-align: center;
1265 + font-size: 14px;
898 } 1266 }
899 1267
900 .add-dialog, 1268 .add-dialog,
......