debug
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import apiClient from './index';
|
||||
import type { Page, AssigneeInfoDTO, UserInfoDTO, TaskInfoDTO, AttachmentDTO } from './types';
|
||||
import { PollutionType } from './types';
|
||||
import type { AxiosResponse } from 'axios';
|
||||
|
||||
// 导出必要的类型
|
||||
export { PollutionType };
|
||||
@@ -42,11 +41,17 @@ export interface TaskDetail {
|
||||
title: string;
|
||||
description: string;
|
||||
status: string;
|
||||
assignee: AssigneeDTO;
|
||||
assignee?: AssigneeDTO;
|
||||
assignedAt: string | null;
|
||||
completedAt: string | null;
|
||||
history: TaskHistoryDTO[];
|
||||
submissionInfo: SubmissionInfoDTO | null;
|
||||
gridX?: number | null;
|
||||
gridY?: number | null;
|
||||
assignment?: {
|
||||
assignmentTime?: string;
|
||||
remarks?: string;
|
||||
};
|
||||
}
|
||||
// --- End: Copied from TaskDetailView.vue ---
|
||||
|
||||
@@ -97,6 +102,7 @@ export interface FeedbackResponse {
|
||||
user: UserInfoDTO;
|
||||
task: TaskDetail | null; // Task can be null if not assigned
|
||||
attachments: AttachmentDTO[];
|
||||
reporterPhone?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,6 +132,7 @@ export interface FeedbackFilters {
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
keyword?: string;
|
||||
submitterId?: number;
|
||||
page?: number;
|
||||
size?: number;
|
||||
}
|
||||
@@ -183,7 +190,7 @@ export function getFeedbackList(params?: FeedbackFilters): Promise<Page<Feedback
|
||||
* @param id 反馈ID
|
||||
* @returns 反馈详情
|
||||
*/
|
||||
export function getFeedbackDetail(id: number): Promise<AxiosResponse<FeedbackDetail>> {
|
||||
export function getFeedbackDetail(id: number): Promise<FeedbackDetail> {
|
||||
return apiClient.get(`/feedback/${id}`);
|
||||
}
|
||||
|
||||
@@ -193,7 +200,7 @@ export function getFeedbackDetail(id: number): Promise<AxiosResponse<FeedbackDet
|
||||
* @param data 处理数据
|
||||
* @returns 处理结果
|
||||
*/
|
||||
export function processFeedback(id: number, request: { status: string; notes?: string }): Promise<AxiosResponse<FeedbackDetail>> {
|
||||
export function processFeedback(id: number, request: { status: string; notes?: string }): Promise<FeedbackDetail> {
|
||||
return apiClient.post(`/feedback/${id}/process`, request);
|
||||
}
|
||||
|
||||
@@ -287,6 +294,6 @@ export const getFeedbackStats = async () => {
|
||||
* 获取待处理的反馈列表
|
||||
* @returns 待处理的反馈列表
|
||||
*/
|
||||
export function getPendingFeedback(): Promise<AxiosResponse<FeedbackResponse[]>> {
|
||||
export function getPendingFeedback(): Promise<FeedbackResponse[]> {
|
||||
return apiClient.get('/feedback/pending');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
import apiClient from './index';
|
||||
import type { Grid } from './types';
|
||||
import type { Grid, UserAccount } from './types';
|
||||
|
||||
export interface GridData extends Grid {}
|
||||
|
||||
export type GridWorker = UserAccount;
|
||||
|
||||
export interface GridWorkersQuery {
|
||||
unassigned?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* DTO for updating a grid's core properties.
|
||||
@@ -16,8 +24,49 @@ export interface GridUpdateRequest {
|
||||
* @param data - 包含更新数据的对象
|
||||
* @returns 更新后的网格对象
|
||||
*/
|
||||
export const updateGrid = (gridId: number, data: GridUpdateRequest): Promise<Grid> => {
|
||||
return apiClient.patch(`/grids/${gridId}`, data);
|
||||
export function updateGrid(gridId: number, data: GridUpdateRequest): Promise<Grid>;
|
||||
export function updateGrid(grid: GridData & GridUpdateRequest): Promise<Grid>;
|
||||
export function updateGrid(
|
||||
gridOrId: number | (GridData & GridUpdateRequest),
|
||||
data?: GridUpdateRequest
|
||||
): Promise<Grid> {
|
||||
if (typeof gridOrId === 'number') {
|
||||
return apiClient.patch(`/grids/${gridOrId}`, data ?? {});
|
||||
}
|
||||
const payload: GridUpdateRequest = {
|
||||
isObstacle: gridOrId.isObstacle,
|
||||
description: gridOrId.description,
|
||||
};
|
||||
return apiClient.patch(`/grids/${gridOrId.id}`, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有网格
|
||||
*/
|
||||
export const getGrids = (): Promise<GridData[]> => {
|
||||
return apiClient.get('/grids');
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取网格员列表(可选:仅未分配)
|
||||
*/
|
||||
export const getGridWorkers = async (params?: GridWorkersQuery): Promise<GridWorker[]> => {
|
||||
const response = await apiClient.get('/personnel/users', {
|
||||
params: { role: 'GRID_WORKER' },
|
||||
});
|
||||
let workers: GridWorker[] = Array.isArray(response) ? response : (response as any).content || [];
|
||||
|
||||
if (params?.unassigned) {
|
||||
workers = workers.filter(worker =>
|
||||
worker.gridX === null ||
|
||||
worker.gridY === null ||
|
||||
worker.gridX === undefined ||
|
||||
worker.gridY === undefined ||
|
||||
worker.gridX === -1 ||
|
||||
worker.gridY === -1
|
||||
);
|
||||
}
|
||||
return workers;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -39,4 +88,8 @@ export const assignWorkerByCoordinates = (gridX: number, gridY: number, userId:
|
||||
*/
|
||||
export const unassignWorkerByCoordinates = (gridX: number, gridY: number): Promise<void> => {
|
||||
return apiClient.post(`/grids/coordinates/${gridX}/${gridY}/unassign`);
|
||||
};
|
||||
};
|
||||
|
||||
// Aliases for compatibility with existing usage
|
||||
export const assignGridWorkerByCoordinates = assignWorkerByCoordinates;
|
||||
export const removeGridWorkerByCoordinates = unassignWorkerByCoordinates;
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
import axios from 'axios';
|
||||
import axios, { type AxiosInstance, type AxiosRequestConfig } from 'axios';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
|
||||
interface ApiClient extends AxiosInstance {
|
||||
request<T = any, R = T>(config: AxiosRequestConfig): Promise<R>;
|
||||
get<T = any, R = T>(url: string, config?: AxiosRequestConfig): Promise<R>;
|
||||
delete<T = any, R = T>(url: string, config?: AxiosRequestConfig): Promise<R>;
|
||||
head<T = any, R = T>(url: string, config?: AxiosRequestConfig): Promise<R>;
|
||||
options<T = any, R = T>(url: string, config?: AxiosRequestConfig): Promise<R>;
|
||||
post<T = any, R = T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
|
||||
put<T = any, R = T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
|
||||
patch<T = any, R = T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
|
||||
}
|
||||
|
||||
// 创建 Axios 实例
|
||||
const apiClient = axios.create({
|
||||
baseURL: import.meta.env.VITE_API_BASE_URL || '/api', // 从环境变量或默认值设置基础URL
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
}) as ApiClient;
|
||||
|
||||
// 添加请求拦截器
|
||||
apiClient.interceptors.request.use(
|
||||
@@ -47,4 +58,4 @@ apiClient.interceptors.response.use(
|
||||
}
|
||||
);
|
||||
|
||||
export default apiClient;
|
||||
export default apiClient;
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import type { AxiosResponse, AxiosError } from 'axios';
|
||||
import apiClient from './index';
|
||||
import type { UserAccount } from './types';
|
||||
|
||||
export const getAvailableGridWorkers = (): Promise<UserAccount[]> => {
|
||||
// 根据TaskAssignmentController的路径应为/tasks/grid-workers
|
||||
return apiClient.get<UserAccount[]>('/tasks/grid-workers')
|
||||
.then((response: AxiosResponse<UserAccount[]>) => response.data)
|
||||
.catch((error: AxiosError) => {
|
||||
.catch((error: any) => {
|
||||
console.error('获取可用网格员API错误:', error);
|
||||
// 如果API调用失败,返回空数组而不是模拟数据
|
||||
return [];
|
||||
@@ -34,4 +32,4 @@ export const approveTask = (taskId: number): Promise<any> => {
|
||||
*/
|
||||
export const rejectTask = (taskId: number, reason: string): Promise<any> => {
|
||||
return apiClient.post(`/management/tasks/${taskId}/reject`, { reason });
|
||||
};
|
||||
};
|
||||
|
||||
@@ -263,6 +263,7 @@ export interface UserInfoDTO {
|
||||
name: string;
|
||||
phone: string;
|
||||
email: string;
|
||||
role?: string;
|
||||
}
|
||||
|
||||
export interface TaskInfoDTO {
|
||||
@@ -304,4 +305,4 @@ export interface OperationLog {
|
||||
/**
|
||||
* Task Summary DTO for supervisor view.
|
||||
* This should match `TaskSummaryDTO` from the backend.
|
||||
*/
|
||||
*/
|
||||
|
||||
@@ -50,8 +50,8 @@ export function updateUserProfile(userId: number, data: UserUpdateRequest): Prom
|
||||
console.log(`API调用: 更新用户资料, userId=${userId}`, data);
|
||||
return apiClient.patch(`/personnel/users/${userId}`, data)
|
||||
.then(response => {
|
||||
console.log('更新用户资料API调用成功:', response.data);
|
||||
return response.data;
|
||||
console.log('更新用户资料API调用成功:', response);
|
||||
return response;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('更新用户资料API调用失败:', error);
|
||||
@@ -70,5 +70,5 @@ export function updateUserProfile(userId: number, data: UserUpdateRequest): Prom
|
||||
*/
|
||||
export function updateUserRole(userId: number, role: string, gridX?: number, gridY?: number): Promise<GridWorker> {
|
||||
const data = { role, gridX, gridY };
|
||||
return apiClient.put(`/personnel/users/${userId}/role`, data).then(response => response.data);
|
||||
}
|
||||
return apiClient.put(`/personnel/users/${userId}/role`, data);
|
||||
}
|
||||
|
||||
@@ -425,7 +425,7 @@ const formatDate = (dateStr: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
const formatRole = (role: string) => {
|
||||
const formatRole = (role?: string) => {
|
||||
const map: Record<string, string> = {
|
||||
'ADMIN': '管理员',
|
||||
'DECISION_MAKER': '决策人',
|
||||
@@ -433,6 +433,7 @@ const formatRole = (role: string) => {
|
||||
'GRID_WORKER': '网格员',
|
||||
'PUBLIC_SUPERVISOR': '公众监督员'
|
||||
};
|
||||
if (!role) return '未知';
|
||||
return map[role] || role;
|
||||
};
|
||||
|
||||
@@ -604,4 +605,4 @@ const handleRejectFeedback = async () => {
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -13,7 +13,7 @@ const app = createApp(App)
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
app.use(ElementPlus, {
|
||||
const elementPlusOptions = {
|
||||
locale: zhCn,
|
||||
zIndex: 3000,
|
||||
popperOptions: {
|
||||
@@ -26,6 +26,8 @@ app.use(ElementPlus, {
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
} as any;
|
||||
|
||||
app.use(ElementPlus as any, elementPlusOptions)
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
4
ems-frontend/ems-monitoring-system/src/shims-element-plus.d.ts
vendored
Normal file
4
ems-frontend/ems-monitoring-system/src/shims-element-plus.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
declare module 'element-plus/dist/locale/zh-cn.mjs' {
|
||||
const locale: any;
|
||||
export default locale;
|
||||
}
|
||||
@@ -15,8 +15,7 @@ import {
|
||||
import type {
|
||||
FeedbackResponse,
|
||||
FeedbackDetail,
|
||||
FeedbackFilters,
|
||||
Page
|
||||
FeedbackFilters
|
||||
} from '@/api/feedback';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { useAuthStore } from '../stores/auth';
|
||||
@@ -121,4 +120,4 @@ export const useFeedbackStore = defineStore('feedback', {
|
||||
// async process(id: number, data: ProcessFeedbackRequest) { ... }
|
||||
// async assign(id: number, data: AssignFeedbackRequest) { ... }
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -80,13 +80,13 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import type { FormInstance, FormRules } from 'element-plus';
|
||||
import type { FormInstance, FormRules, UploadFile } from 'element-plus';
|
||||
import { PollutionType, SeverityLevel } from '@/api/feedback';
|
||||
import { submitPublicFeedback } from '@/api/public'; // Assuming the function will be in a new api/public.ts
|
||||
|
||||
const feedbackForm = ref<FormInstance>();
|
||||
const loading = ref(false);
|
||||
const fileList = ref([]);
|
||||
const fileList = ref<UploadFile[]>([]);
|
||||
const rating = ref(2);
|
||||
|
||||
interface PublicFeedbackForm {
|
||||
@@ -131,11 +131,11 @@ const rules = reactive<FormRules>({
|
||||
gridY: [{ required: true, type: 'number', message: '网格Y必须为数字' }],
|
||||
});
|
||||
|
||||
const handleRemove = (file, fileListUpdated) => {
|
||||
const handleRemove = (file: UploadFile, fileListUpdated: UploadFile[]) => {
|
||||
fileList.value = fileListUpdated;
|
||||
};
|
||||
|
||||
const handleChange = (file, fileListUpdated) => {
|
||||
const handleChange = (file: UploadFile, fileListUpdated: UploadFile[]) => {
|
||||
fileList.value = fileListUpdated;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,9 @@ const submitForm = async () => {
|
||||
formData.append('feedback', new Blob([JSON.stringify(submissionData)], { type: 'application/json' }));
|
||||
|
||||
fileList.value.forEach(file => {
|
||||
formData.append('files', file.raw);
|
||||
if (file.raw) {
|
||||
formData.append('files', file.raw);
|
||||
}
|
||||
});
|
||||
|
||||
await submitPublicFeedback(formData);
|
||||
@@ -201,4 +203,4 @@ const resetForm = () => {
|
||||
color: #666;
|
||||
margin-top: 5px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import type { FormInstance, FormRules } from 'element-plus';
|
||||
import type { FormInstance, FormRules, UploadFile } from 'element-plus';
|
||||
import { useFeedbackStore } from '@/store/feedback';
|
||||
import { PollutionType } from '@/api/types';
|
||||
import { SeverityLevel } from '@/api/feedback';
|
||||
@@ -84,7 +84,7 @@ import type { FeedbackSubmissionRequest, LocationInfo } from '@/api/feedback';
|
||||
|
||||
const feedbackForm = ref<FormInstance>();
|
||||
const loading = ref(false);
|
||||
const fileList = ref([]);
|
||||
const fileList = ref<UploadFile[]>([]);
|
||||
const rating = ref(2); // For el-rate which uses a number. 1=LOW, 2=MEDIUM, 3=HIGH
|
||||
|
||||
const form = reactive<Omit<FeedbackSubmissionRequest, 'severityLevel'>>({
|
||||
@@ -121,15 +121,15 @@ const rules = reactive<FormRules>({
|
||||
|
||||
const feedbackStore = useFeedbackStore();
|
||||
|
||||
const handleRemove = (file, fileListUpdated) => {
|
||||
const handleRemove = (file: UploadFile, fileListUpdated: UploadFile[]) => {
|
||||
fileList.value = fileListUpdated;
|
||||
};
|
||||
|
||||
const handlePreview = (file) => {
|
||||
const handlePreview = (file: UploadFile) => {
|
||||
console.log(file);
|
||||
};
|
||||
|
||||
const handleChange = (file, fileListUpdated) => {
|
||||
const handleChange = (file: UploadFile, fileListUpdated: UploadFile[]) => {
|
||||
fileList.value = fileListUpdated;
|
||||
}
|
||||
|
||||
@@ -157,7 +157,9 @@ const submitForm = async () => {
|
||||
formData.append('feedback', new Blob([JSON.stringify(submissionData)], { type: 'application/json' }));
|
||||
|
||||
fileList.value.forEach(file => {
|
||||
formData.append('files', file.raw);
|
||||
if (file.raw) {
|
||||
formData.append('files', file.raw);
|
||||
}
|
||||
});
|
||||
|
||||
await feedbackStore.submitFeedback(formData);
|
||||
@@ -187,4 +189,4 @@ const resetForm = () => {
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -33,18 +33,18 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import type { Feedback } from '@/api/types';
|
||||
import type { FeedbackResponse } from '@/api/feedback';
|
||||
import { getPendingFeedback, processFeedback } from '@/api/feedback'; // Assuming processFeedback exists
|
||||
import { formatDateTime } from '@/utils/formatter';
|
||||
|
||||
const pendingFeedback = ref<Feedback[]>([]);
|
||||
const pendingFeedback = ref<FeedbackResponse[]>([]);
|
||||
const loading = ref(false);
|
||||
|
||||
const fetchPendingFeedback = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const response = await getPendingFeedback();
|
||||
pendingFeedback.value = response.data;
|
||||
pendingFeedback.value = response;
|
||||
} catch (error) {
|
||||
ElMessage.error('获取待审核反馈失败');
|
||||
console.error(error);
|
||||
@@ -53,13 +53,13 @@ const fetchPendingFeedback = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreateTask = (feedback: Feedback) => {
|
||||
const handleCreateTask = (feedback: FeedbackResponse) => {
|
||||
// TODO: Implement task creation logic
|
||||
console.log('Create task from feedback:', feedback.id);
|
||||
ElMessage.info(`准备为反馈 #${feedback.id} 创建任务`);
|
||||
};
|
||||
|
||||
const handleRejectFeedback = async (feedback: Feedback) => {
|
||||
const handleRejectFeedback = async (feedback: FeedbackResponse) => {
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定要拒绝这条反馈吗? (ID: ${feedback.id})`, '确认操作', {
|
||||
confirmButtonText: '确定',
|
||||
|
||||
@@ -171,8 +171,8 @@ const isSubmitDialogVisible = ref(false);
|
||||
const fetchTaskDetails = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const response = await apiClient.get(`/worker/${taskId.value}`);
|
||||
task.value = response as TaskDetail;
|
||||
const response = await apiClient.get<TaskDetail>(`/worker/${taskId.value}`);
|
||||
task.value = response;
|
||||
} catch (error) {
|
||||
console.error(`获取任务详情失败 (ID: ${taskId.value}):`, error);
|
||||
ElMessage.error('获取任务详情失败');
|
||||
@@ -286,4 +286,4 @@ onMounted(() => {
|
||||
margin-top: 20px;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -110,7 +110,7 @@ const fetchAllGrids = async () => {
|
||||
gridData.value = Array.isArray(response) ? response : (response as any).content || [];
|
||||
} catch (e: any) {
|
||||
error.value = e.message || '获取网格数据时发生未知错误';
|
||||
ElMessage.error(error.value);
|
||||
ElMessage.error(error.value || '获取网格数据时发生未知错误');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
@@ -334,4 +334,4 @@ const selectGrid = (grid: DisplayGrid) => {
|
||||
color: #303133;
|
||||
margin-right: 8px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user