261 lines
7.8 KiB
Markdown
261 lines
7.8 KiB
Markdown
# 反馈管理页面设计文档
|
||
|
||
## 1. 页面概述
|
||
|
||
反馈管理页面是管理员和主管处理用户提交的环境问题报告、建议或其他反馈的核心平台。此页面旨在提供一个高效的工作流程,用于审查、分类、回复和跟踪所有用户反馈,确保问题得到及时响应和解决。
|
||
|
||
## 2. 页面布局
|
||
|
||

|
||
|
||
### 2.1 布局结构
|
||
|
||
页面布局与任务管理页面类似,遵循标准的后台管理界面设计:
|
||
- **顶部**: 筛选区域,允许管理员按反馈状态(待处理、已处理)、反馈类型或提交时间进行过滤。
|
||
- **中部**: 反馈列表,以表格或卡片列表的形式展示反馈信息。
|
||
- **底部**: 分页控件。
|
||
|
||
### 2.2 响应式设计
|
||
|
||
- **桌面端**: 使用多列数据表格,清晰展示反馈的各项信息。
|
||
- **移动端**: 转换为卡片式列表,每张卡片突出显示反馈标题、提交人和状态,并提供点击查看详情的入口。
|
||
|
||
## 3. 组件结构
|
||
|
||
```vue
|
||
<template>
|
||
<div class="feedback-management-page">
|
||
<el-page-header title="反馈管理" content="用户反馈列表" />
|
||
|
||
<el-card class="page-container">
|
||
<!-- 筛选区域 -->
|
||
<div class="filter-container">
|
||
<el-form :model="filters" inline>
|
||
<el-form-item label="处理状态">
|
||
<el-select v-model="filters.status" placeholder="请选择状态" clearable>
|
||
<el-option label="待处理" value="PENDING" />
|
||
<el-option label="已处理" value="RESOLVED" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="提交人">
|
||
<el-input v-model="filters.submitter" placeholder="输入提交人姓名/ID" clearable />
|
||
</el-form-item>
|
||
<el-form-item>
|
||
<el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
|
||
<!-- 反馈表格 -->
|
||
<el-table :data="feedbackList" v-loading="loading" stripe>
|
||
<el-table-column prop="title" label="反馈标题" min-width="200" />
|
||
<el-table-column prop="submitterName" label="提交人" width="120" />
|
||
<el-table-column prop="createdAt" label="提交时间" width="180" sortable />
|
||
<el-table-column prop="status" label="状态" width="100">
|
||
<template #default="{ row }">
|
||
<el-tag :type="row.status === 'PENDING' ? 'warning' : 'success'">
|
||
{{ row.status === 'PENDING' ? '待处理' : '已处理' }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="150" fixed="right">
|
||
<template #default="{ row }">
|
||
<el-button link type="primary" @click="handleViewDetails(row)">查看详情</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<!-- 分页 -->
|
||
<el-pagination
|
||
v-if="total > 0"
|
||
class="pagination-container"
|
||
:current-page="pagination.page"
|
||
:page-size="pagination.pageSize"
|
||
:total="total"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
@size-change="handleSizeChange"
|
||
@current-change="handleCurrentChange"
|
||
/>
|
||
</el-card>
|
||
|
||
<!-- 反馈详情对话框 -->
|
||
<FeedbackDetailDialog
|
||
v-model="dialogVisible"
|
||
:feedback-id="selectedFeedbackId"
|
||
@processed="handleProcessed"
|
||
/>
|
||
</div>
|
||
</template>
|
||
```
|
||
|
||
## 4. 数据结构
|
||
|
||
```typescript
|
||
// 反馈筛选条件
|
||
interface FeedbackFilters {
|
||
status?: 'PENDING' | 'RESOLVED';
|
||
submitter?: string;
|
||
}
|
||
|
||
// 反馈列表项
|
||
interface FeedbackListItem {
|
||
id: number;
|
||
title: string;
|
||
submitterName: string;
|
||
createdAt: string;
|
||
status: 'PENDING' | 'RESOLVED';
|
||
}
|
||
|
||
// 反馈详情 (用于对话框)
|
||
interface FeedbackDetail extends FeedbackListItem {
|
||
content: string;
|
||
images: string[]; // 图片 URL 列表
|
||
location: string;
|
||
contact: string;
|
||
handlerNotes?: string; // 处理备注
|
||
}
|
||
```
|
||
|
||
## 5. 状态管理
|
||
|
||
```typescript
|
||
// 组件内状态
|
||
const filters = ref<FeedbackFilters>({});
|
||
const pagination = ref({ page: 1, pageSize: 10 });
|
||
const dialogVisible = ref(false);
|
||
const selectedFeedbackId = ref<number | null>(null);
|
||
|
||
// 全局状态 (Pinia Store)
|
||
const feedbackStore = useFeedbackStore();
|
||
const { feedbackList, total, loading } = storeToRefs(feedbackStore);
|
||
```
|
||
|
||
## 6. 交互逻辑
|
||
|
||
### 6.1 数据获取与筛选
|
||
|
||
```typescript
|
||
const fetchFeedback = () => {
|
||
feedbackStore.fetchFeedbackList({ ...filters.value, ...pagination.value });
|
||
};
|
||
|
||
onMounted(fetchFeedback);
|
||
|
||
const handleSearch = () => {
|
||
pagination.value.page = 1;
|
||
fetchFeedback();
|
||
};
|
||
|
||
// 分页逻辑 (handleSizeChange, handleCurrentChange) 与任务管理页面类似
|
||
```
|
||
|
||
### 6.2 查看详情与处理
|
||
|
||
```typescript
|
||
const handleViewDetails = (feedback: FeedbackListItem) => {
|
||
selectedFeedbackId.value = feedback.id;
|
||
dialogVisible.value = true;
|
||
};
|
||
|
||
// 当详情对话框中完成处理后被调用
|
||
const handleProcessed = () => {
|
||
dialogVisible.value = false;
|
||
fetchFeedback(); // 刷新列表以更新状态
|
||
};
|
||
```
|
||
|
||
## 7. API 调用
|
||
|
||
### 7.1 反馈管理 API
|
||
|
||
```typescript
|
||
// api/feedback.ts
|
||
export const feedbackApi = {
|
||
getFeedbackList: (params) => apiClient.get('/management/feedback', { params }),
|
||
getFeedbackDetail: (id: number) => apiClient.get(`/management/feedback/${id}`),
|
||
processFeedback: (id: number, data: { notes: string }) => apiClient.post(`/management/feedback/${id}/process`, data),
|
||
};
|
||
```
|
||
|
||
### 7.2 Pinia Store
|
||
|
||
```typescript
|
||
// stores/feedback.ts
|
||
export const useFeedbackStore = defineStore('feedback', {
|
||
state: () => ({
|
||
feedbackList: [] as FeedbackListItem[],
|
||
total: 0,
|
||
loading: false,
|
||
currentFeedbackDetail: null as FeedbackDetail | null,
|
||
}),
|
||
actions: {
|
||
async fetchFeedbackList(params) {
|
||
this.loading = true;
|
||
try {
|
||
const { data } = await feedbackApi.getFeedbackList(params);
|
||
this.feedbackList = data.items;
|
||
this.total = data.total;
|
||
} finally {
|
||
this.loading = false;
|
||
}
|
||
},
|
||
async fetchFeedbackDetail(id: number) {
|
||
const { data } = await feedbackApi.getFeedbackDetail(id);
|
||
this.currentFeedbackDetail = data;
|
||
},
|
||
async processFeedback(payload: { id: number; notes: string }) {
|
||
await feedbackApi.processFeedback(payload.id, { notes: payload.notes });
|
||
}
|
||
}
|
||
});
|
||
```
|
||
|
||
## 8. 样式设计
|
||
|
||
```scss
|
||
.feedback-management-page {
|
||
padding: 24px;
|
||
|
||
.page-container {
|
||
margin-top: 24px;
|
||
padding: 24px;
|
||
border-radius: 8px;
|
||
border: none;
|
||
}
|
||
|
||
.filter-container {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.pagination-container {
|
||
margin-top: 24px;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
}
|
||
}
|
||
```
|
||
|
||
## 9. 关联组件
|
||
|
||
### `FeedbackDetailDialog.vue`
|
||
|
||
这是一个关键的子组件,用于显示反馈的完整信息,并提供处理功能。
|
||
- **Props**: `modelValue` (for v-model), `feedbackId`
|
||
- **功能**:
|
||
- 接收 `feedbackId`,在对话框打开时调用 store action 获取反馈详情。
|
||
- 展示反馈的文本内容、联系方式、地理位置和图片(图片可点击放大预览)。
|
||
- 提供一个文本域供管理员填写处理备注。
|
||
- 提供一个"标记为已处理"的按钮,点击后调用 store action 提交处理结果。
|
||
- 操作成功后,emit 一个 `processed` 事件通知父组件刷新列表。
|
||
|
||
## 10. 测试用例
|
||
|
||
1. **单元测试**:
|
||
- 测试 Pinia store 的各个 action 是否能正常工作。
|
||
- 测试 `FeedbackDetailDialog` 组件在接收到 `feedbackId` 后是否能正确加载和显示数据。
|
||
|
||
2. **集成测试**:
|
||
- 测试筛选功能是否能正确过滤反馈列表。
|
||
- 测试分页是否正常。
|
||
- 测试点击"查看详情"按钮是否能打开对话框并加载正确的反馈信息。
|
||
- 测试在详情对话框中提交处理意见后,列表中的反馈状态是否更新。 |