|
@@ -1,23 +1,37 @@
|
|
|
<template>
|
|
<template>
|
|
|
- <el-dialog v-model="dialogShow" title="举报审核" width="780px" @close="handleClose">
|
|
|
|
|
- <el-descriptions :column="2" border class="review-descriptions">
|
|
|
|
|
- <el-descriptions-item label="律师姓名">
|
|
|
|
|
- {{ detailData.reportedUserName || "--" }}
|
|
|
|
|
- </el-descriptions-item>
|
|
|
|
|
|
|
+ <el-dialog v-model="dialogShow" title="申诉审核" width="70%" class="appeal-review-dialog" @close="handleClose">
|
|
|
|
|
+ <el-descriptions border :column="1" label-width="140px" class="review-descriptions">
|
|
|
<el-descriptions-item label="订单编号">
|
|
<el-descriptions-item label="订单编号">
|
|
|
- {{ detailData.orderNumber || "--" }}
|
|
|
|
|
|
|
+ {{ detailData.orderNumber }}
|
|
|
</el-descriptions-item>
|
|
</el-descriptions-item>
|
|
|
- <el-descriptions-item label="举报人姓名">
|
|
|
|
|
- {{ detailData.nickname || "--" }}
|
|
|
|
|
|
|
+ <el-descriptions-item label="用户名称">
|
|
|
|
|
+ {{ detailData.userName }}
|
|
|
</el-descriptions-item>
|
|
</el-descriptions-item>
|
|
|
- <el-descriptions-item label="举报类型">
|
|
|
|
|
- {{ violationDisplay }}
|
|
|
|
|
|
|
+ <el-descriptions-item label="用户电话">
|
|
|
|
|
+ {{ detailData.userPhone }}
|
|
|
</el-descriptions-item>
|
|
</el-descriptions-item>
|
|
|
- <el-descriptions-item label="举报时间">
|
|
|
|
|
- {{ detailData.createdTime || "--" }}
|
|
|
|
|
|
|
+ <el-descriptions-item label="用户评价">
|
|
|
|
|
+ {{ detailData.reviewContent }}
|
|
|
</el-descriptions-item>
|
|
</el-descriptions-item>
|
|
|
- <el-descriptions-item v-if="detailData.processingTime" label="处理时间">
|
|
|
|
|
- {{ detailData.processingTime || "--" }}
|
|
|
|
|
|
|
+ <el-descriptions-item label="评价图片">
|
|
|
|
|
+ <div class="image-grid">
|
|
|
|
|
+ <el-image
|
|
|
|
|
+ v-for="(img, index) in detailData.reviewImgList"
|
|
|
|
|
+ :key="`${detailData.id}-${index}`"
|
|
|
|
|
+ :src="img"
|
|
|
|
|
+ :preview-src-list="detailData.reviewImgList"
|
|
|
|
|
+ fit="cover"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="律师姓名">
|
|
|
|
|
+ {{ detailData.lawyerName }}
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="律师电话">
|
|
|
|
|
+ {{ detailData.lawyerPhone || "--" }}
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="申诉理由">
|
|
|
|
|
+ {{ detailData.appealReason }}
|
|
|
</el-descriptions-item>
|
|
</el-descriptions-item>
|
|
|
<el-descriptions-item label="当前状态">
|
|
<el-descriptions-item label="当前状态">
|
|
|
<el-tag v-if="currentStatus" :type="currentStatus.tagType">
|
|
<el-tag v-if="currentStatus" :type="currentStatus.tagType">
|
|
@@ -25,138 +39,95 @@
|
|
|
</el-tag>
|
|
</el-tag>
|
|
|
<span v-else> -- </span>
|
|
<span v-else> -- </span>
|
|
|
</el-descriptions-item>
|
|
</el-descriptions-item>
|
|
|
- <el-descriptions-item label="举报描述" :span="2">
|
|
|
|
|
- {{ detailData.otherReasonContent || "暂无" }}
|
|
|
|
|
|
|
+ <el-descriptions-item label="申诉图片">
|
|
|
|
|
+ <div class="image-grid">
|
|
|
|
|
+ <el-image
|
|
|
|
|
+ v-for="(img, index) in detailData.imgList"
|
|
|
|
|
+ :key="`${img}-${index}`"
|
|
|
|
|
+ :src="img"
|
|
|
|
|
+ :preview-src-list="detailData.imgList"
|
|
|
|
|
+ fit="cover"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="申诉时间">
|
|
|
|
|
+ {{ detailData.appealTime }}
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item v-if="detailData.appealReviewTime" label="审核时间">
|
|
|
|
|
+ {{ detailData.appealReviewTime }}
|
|
|
</el-descriptions-item>
|
|
</el-descriptions-item>
|
|
|
</el-descriptions>
|
|
</el-descriptions>
|
|
|
|
|
|
|
|
- <div class="evidence-block" v-if="evidenceList.length">
|
|
|
|
|
- <div class="block-title">举报凭证</div>
|
|
|
|
|
- <div class="image-grid">
|
|
|
|
|
- <el-image
|
|
|
|
|
- v-for="(img, index) in evidenceList"
|
|
|
|
|
- :key="`${detailData.id}-${index}`"
|
|
|
|
|
- :src="img"
|
|
|
|
|
- :preview-src-list="evidenceList"
|
|
|
|
|
- fit="cover"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <el-form ref="formRef" :model="reviewForm" :rules="rules" label-width="90px" class="review-form">
|
|
|
|
|
- <el-form-item label="处理结果" prop="processingStatus">
|
|
|
|
|
- <el-radio-group v-model="reviewForm.processingStatus">
|
|
|
|
|
- <el-radio :value="1"> 违规 </el-radio>
|
|
|
|
|
- <el-radio :value="2"> 未违规 </el-radio>
|
|
|
|
|
- </el-radio-group>
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- <el-form-item label="处理说明" prop="reportResult">
|
|
|
|
|
- <el-input
|
|
|
|
|
- v-model="reviewForm.reportResult"
|
|
|
|
|
- type="textarea"
|
|
|
|
|
- :rows="3"
|
|
|
|
|
- maxlength="200"
|
|
|
|
|
- show-word-limit
|
|
|
|
|
- placeholder="请输入处理说明"
|
|
|
|
|
- />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-form>
|
|
|
|
|
-
|
|
|
|
|
<template #footer>
|
|
<template #footer>
|
|
|
<span class="dialog-footer">
|
|
<span class="dialog-footer">
|
|
|
- <el-button @click="handleClose">取消</el-button>
|
|
|
|
|
- <el-button type="primary" @click="handleSubmit">提交</el-button>
|
|
|
|
|
|
|
+ <el-button type="primary" @click="handleApprove"> 同意 </el-button>
|
|
|
|
|
+ <el-button type="danger" @click="handleReject"> 驳回 </el-button>
|
|
|
|
|
+ <el-button @click="handleClose"> 取消 </el-button>
|
|
|
</span>
|
|
</span>
|
|
|
</template>
|
|
</template>
|
|
|
</el-dialog>
|
|
</el-dialog>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
-import { computed, reactive, ref } from "vue";
|
|
|
|
|
-import type { FormInstance, FormRules } from "element-plus";
|
|
|
|
|
|
|
+import { computed, ref } from "vue";
|
|
|
|
|
+import { ElMessageBox } from "element-plus";
|
|
|
|
|
|
|
|
const dialogShow = ref(false);
|
|
const dialogShow = ref(false);
|
|
|
const detailData = ref<Record<string, any>>({});
|
|
const detailData = ref<Record<string, any>>({});
|
|
|
-const formRef = ref<FormInstance>();
|
|
|
|
|
|
|
|
|
|
const statusMeta = [
|
|
const statusMeta = [
|
|
|
- { value: 0, label: "未处理", tagType: "info" },
|
|
|
|
|
- { value: 1, label: "违规", tagType: "danger" },
|
|
|
|
|
- { value: 2, label: "未违规", tagType: "success" }
|
|
|
|
|
|
|
+ { value: 0, label: "审核中", tagType: "info" },
|
|
|
|
|
+ { value: 1, label: "已通过", tagType: "success" },
|
|
|
|
|
+ { value: 2, label: "已驳回", tagType: "danger" }
|
|
|
] as const;
|
|
] as const;
|
|
|
|
|
|
|
|
-const violationTypeMeta = [
|
|
|
|
|
- { value: 1, label: "服务态度差" },
|
|
|
|
|
- { value: 2, label: "专业能力差" },
|
|
|
|
|
- { value: 3, label: "响应时间超过24小时" },
|
|
|
|
|
- { value: 4, label: "其他原因" }
|
|
|
|
|
-] as const;
|
|
|
|
|
|
|
+const APPROVE_STATUS = 1;
|
|
|
|
|
+const REJECT_STATUS = 2;
|
|
|
|
|
|
|
|
-const getStatusMeta = (status?: number) => statusMeta.find(item => item.value == status);
|
|
|
|
|
-const getViolationMeta = (type?: number | string) => {
|
|
|
|
|
- const value = typeof type === "string" ? Number(type) : type;
|
|
|
|
|
- return violationTypeMeta.find(item => item.value === value);
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-const parseEvidenceImages = (value: string | string[] | null | undefined) => {
|
|
|
|
|
- if (!value) return [];
|
|
|
|
|
- if (Array.isArray(value)) return value.filter(Boolean);
|
|
|
|
|
- return value
|
|
|
|
|
- .split(",")
|
|
|
|
|
- .map(url => url.trim())
|
|
|
|
|
- .filter(Boolean);
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-const evidenceList = computed(() => parseEvidenceImages(detailData.value.reportEvidenceImg));
|
|
|
|
|
-const currentStatus = computed(() => getStatusMeta(detailData.value.processingStatus));
|
|
|
|
|
-const violationDisplay = computed(() => {
|
|
|
|
|
- if (detailData.value.violationReason == 4) return detailData.value.otherReasonContent || "其他原因";
|
|
|
|
|
- return getViolationMeta(detailData.value.violationReason)?.label || "--";
|
|
|
|
|
-});
|
|
|
|
|
-
|
|
|
|
|
-const reviewForm = reactive({
|
|
|
|
|
- processingStatus: 1,
|
|
|
|
|
- reportResult: ""
|
|
|
|
|
|
|
+const currentStatus = computed(() => {
|
|
|
|
|
+ const rawStatus = detailData.value?.status;
|
|
|
|
|
+ return statusMeta.find(item => item.value == rawStatus);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-const rules: FormRules = {
|
|
|
|
|
- processingStatus: [{ required: true, message: "请选择处理结果", trigger: "change" }],
|
|
|
|
|
- reportResult: [{ required: true, message: "请输入处理说明", trigger: "blur" }]
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
const emit = defineEmits<{
|
|
const emit = defineEmits<{
|
|
|
- submit: [{ processingStatus: number; reportResult: string }];
|
|
|
|
|
|
|
+ submit: [{ status: number; reviewReasons: string }];
|
|
|
close: [];
|
|
close: [];
|
|
|
}>();
|
|
}>();
|
|
|
|
|
|
|
|
-const resetForm = () => {
|
|
|
|
|
- reviewForm.processingStatus = 1;
|
|
|
|
|
- reviewForm.reportResult = "";
|
|
|
|
|
- formRef.value?.clearValidate();
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
const open = (data: any) => {
|
|
const open = (data: any) => {
|
|
|
detailData.value = { ...data };
|
|
detailData.value = { ...data };
|
|
|
- reviewForm.processingStatus = data?.processingStatus ?? 1;
|
|
|
|
|
- reviewForm.reportResult = data?.reportResult || "";
|
|
|
|
|
dialogShow.value = true;
|
|
dialogShow.value = true;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-const handleSubmit = async () => {
|
|
|
|
|
- if (!formRef.value) return;
|
|
|
|
|
- await formRef.value.validate(async valid => {
|
|
|
|
|
- if (!valid) return;
|
|
|
|
|
- emit("submit", {
|
|
|
|
|
- processingStatus: reviewForm.processingStatus,
|
|
|
|
|
- reportResult: reviewForm.reportResult.trim()
|
|
|
|
|
|
|
+const handleApprove = async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ await ElMessageBox.confirm("确认同意该申诉吗?", "确认操作", {
|
|
|
|
|
+ confirmButtonText: "确认同意",
|
|
|
|
|
+ cancelButtonText: "取消",
|
|
|
|
|
+ type: "success"
|
|
|
});
|
|
});
|
|
|
- });
|
|
|
|
|
|
|
+ emit("submit", { status: APPROVE_STATUS, reviewReasons: "" });
|
|
|
|
|
+ } catch (error) {}
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const handleReject = async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const { value } = await ElMessageBox.prompt("请输入驳回原因", "驳回确认", {
|
|
|
|
|
+ inputPlaceholder: "请输入驳回原因",
|
|
|
|
|
+ confirmButtonText: "确认驳回",
|
|
|
|
|
+ cancelButtonText: "取消",
|
|
|
|
|
+ inputValidator: val => {
|
|
|
|
|
+ if (!val || !val.trim()) return "请输入驳回原因";
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ emit("submit", { status: REJECT_STATUS, reviewReasons: value.trim() });
|
|
|
|
|
+ } catch (error) {}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const handleClose = () => {
|
|
const handleClose = () => {
|
|
|
dialogShow.value = false;
|
|
dialogShow.value = false;
|
|
|
emit("close");
|
|
emit("close");
|
|
|
- resetForm();
|
|
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
defineExpose({
|
|
defineExpose({
|
|
@@ -166,27 +137,15 @@ defineExpose({
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
<style scoped lang="scss">
|
|
|
-.review-descriptions {
|
|
|
|
|
- margin-bottom: 16px;
|
|
|
|
|
-}
|
|
|
|
|
-.block-title {
|
|
|
|
|
- margin-bottom: 8px;
|
|
|
|
|
- font-weight: 600;
|
|
|
|
|
- color: #303133;
|
|
|
|
|
-}
|
|
|
|
|
.image-grid {
|
|
.image-grid {
|
|
|
display: grid;
|
|
display: grid;
|
|
|
- grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
|
|
|
|
- gap: 8px;
|
|
|
|
|
- margin-bottom: 20px;
|
|
|
|
|
|
|
+ grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
|
|
|
|
|
+ gap: 12px;
|
|
|
}
|
|
}
|
|
|
.image-grid :deep(.el-image) {
|
|
.image-grid :deep(.el-image) {
|
|
|
- width: 100%;
|
|
|
|
|
- height: 100%;
|
|
|
|
|
|
|
+ width: 80px;
|
|
|
|
|
+ height: 80px;
|
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
|
border-radius: 8px;
|
|
border-radius: 8px;
|
|
|
}
|
|
}
|
|
|
-.review-form {
|
|
|
|
|
- padding-top: 8px;
|
|
|
|
|
-}
|
|
|
|
|
</style>
|
|
</style>
|