|
@@ -0,0 +1,814 @@
|
|
|
+<template>
|
|
|
+ <div class="app-container">
|
|
|
+ <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
|
|
|
+ <el-form-item label="用户" prop="userId">
|
|
|
+ <el-input
|
|
|
+ v-model="queryParams.userId"
|
|
|
+ placeholder="请输入用户id"
|
|
|
+ clearable
|
|
|
+ size="small"
|
|
|
+ @keyup.enter.native="handleQuery"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="联系方式" prop="phone">
|
|
|
+ <el-input
|
|
|
+ v-model="queryParams.phone"
|
|
|
+ placeholder="请输入联系方式"
|
|
|
+ clearable
|
|
|
+ size="small"
|
|
|
+ @keyup.enter.native="handleQuery"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="处理状态" prop="isHandleStore">
|
|
|
+ <el-select
|
|
|
+ v-model="queryParams.isHandleStore"
|
|
|
+ placeholder="请选择处理状态"
|
|
|
+ clearable
|
|
|
+ size="small"
|
|
|
+ >
|
|
|
+ <el-option label="未处理" value="0"></el-option>
|
|
|
+ <el-option label="已处理" value="1"></el-option>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="投诉时间" prop="complaintTime">
|
|
|
+ <el-date-picker v-model="complaintTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="changeTime"></el-date-picker>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
|
|
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <el-row :gutter="10" class="mb8">
|
|
|
+ <el-col :span="1.5">
|
|
|
+ <el-button
|
|
|
+ type="warning"
|
|
|
+ plain
|
|
|
+ icon="el-icon-download"
|
|
|
+ size="mini"
|
|
|
+ :loading="exportLoading"
|
|
|
+ @click="handleExport"
|
|
|
+ >导出</el-button>
|
|
|
+ </el-col>
|
|
|
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-table border v-loading="loading" :data="complaintList" @selection-change="handleSelectionChange">
|
|
|
+ <el-table-column type="selection" width="55" align="center" />
|
|
|
+ <el-table-column label="id" align="center" prop="id" />
|
|
|
+ <el-table-column label="用户" align="center" prop="nickName" />
|
|
|
+ <el-table-column label="投诉方式" align="center" prop="complaintType" >
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <template v-for="item in complaintTypeOptions">
|
|
|
+ <el-tag v-if="item.dictValue === scope.row.complaintType" :key="item.dictValue">
|
|
|
+ {{ item.dictLabel }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="投诉类型" align="center" prop="type" >
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <dict-tag :options="typeOptions" :value="scope.row.type"/>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="投诉时间" align="center" prop="createTime" />
|
|
|
+ <el-table-column
|
|
|
+ label="店铺是否处理"
|
|
|
+ align="center"
|
|
|
+ prop="isHandlePlatform"
|
|
|
+ :render-header="renderHandleHeader"
|
|
|
+ >
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tag
|
|
|
+ :type="(scope.row.isHandleStore == 1)? 'success' : 'warning'"
|
|
|
+ disable-transitions
|
|
|
+ >
|
|
|
+ {{ formatHandleStatus(scope.row.isHandle) }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="备注" align="center" prop="remarks" />
|
|
|
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-button
|
|
|
+ size="mini"
|
|
|
+ type="text"
|
|
|
+ icon="el-icon-edit"
|
|
|
+ @click="handleUpdate(scope.row)"
|
|
|
+ >投诉详情</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <pagination
|
|
|
+ v-show="total>0"
|
|
|
+ :total="total"
|
|
|
+ :page.sync="queryParams.pageNum"
|
|
|
+ :limit.sync="queryParams.pageSize"
|
|
|
+ @pagination="getList"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 修改用户投诉对话框 -->
|
|
|
+ <el-dialog :title="title" :visible.sync="open" width="900px" append-to-body>
|
|
|
+ <!-- 修改tab-click事件处理器名称 -->
|
|
|
+ <el-tabs v-model="activeTab" type="card" @tab-click="handleClick">
|
|
|
+ <!-- 投诉详情标签页 -->
|
|
|
+ <el-tab-pane label="投诉详情" name="complaint">
|
|
|
+ <el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
|
|
+ <el-form-item label="投诉内容" prop="name">
|
|
|
+ <el-input v-model="form.name" :disabled="true" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="详细内容" v-if="form.content && form.content!=''">
|
|
|
+ <el-input type="textarea" v-model="form.content" :disabled="true"/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="联系方式" prop="phone" v-if="form.phone && form.phone!=''">
|
|
|
+ <el-input v-model="form.phone" :disabled="true"/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="图片" v-if="form.images && form.images!=''">
|
|
|
+ <div v-for="(url, index) in imageUrls(form.images)" :key="index" class="image-container">
|
|
|
+ <el-image :src="url" :preview-src-list="[url]" style="width: 100px; height: 100px;"></el-image>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <!-- <el-form-item label="交易截图" v-if="form.tradeImage && form.tradeImage!=''">
|
|
|
+ <div v-for="(url, index) in imageUrls(form.tradeImage)" :key="index" class="image-container">
|
|
|
+ <el-image :src="url" :preview-src-list="[url]" style="width: 100px; height: 100px;"></el-image>
|
|
|
+ </div>
|
|
|
+ </el-form-item> -->
|
|
|
+ <el-form-item label="用户" prop="nickName">
|
|
|
+ <el-input v-model="form.nickName" :disabled="true"/>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="是否处理" prop="isHandleStore">
|
|
|
+ <el-select v-model="form.isHandleStore" placeholder="请选择处理状态" :disabled="true">
|
|
|
+ <el-option label="未处理" :value="0"></el-option>
|
|
|
+ <el-option label="已处理" :value="1"></el-option>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="备注" prop="remarks" >
|
|
|
+ <el-input type="textarea" v-model="form.remarks" :maxlength="250" :disabled="true"/>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <!-- 回复详情标签页 -->
|
|
|
+ <el-tab-pane label="回复详情" name="replies">
|
|
|
+ <div class="reply-section">
|
|
|
+ <!-- 添加回复表单 -->
|
|
|
+ <el-card class="add-reply-card" shadow="never">
|
|
|
+ <div slot="header">
|
|
|
+ <span>添加回复</span>
|
|
|
+ </div>
|
|
|
+ <el-form :model="replyForm" ref="replyForm" label-width="80px">
|
|
|
+ <el-form-item label="回复内容" prop="content" :rules="[{ required: true, message: '请输入回复内容', trigger: 'blur' }]">
|
|
|
+ <el-input
|
|
|
+ type="textarea"
|
|
|
+ v-model="replyForm.content"
|
|
|
+ placeholder="请输入回复内容"
|
|
|
+ :rows="3"
|
|
|
+ maxlength="500"
|
|
|
+ show-word-limit
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 添加图片上传功能 -->
|
|
|
+ <el-form-item label="上传图片" prop="images">
|
|
|
+ <!-- <div class="image-upload-container">
|
|
|
+ <el-upload
|
|
|
+ ref="imageUpload"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :show-file-list="false"
|
|
|
+ :file-list="replyImageList"
|
|
|
+ :on-success="handleSuccess"
|
|
|
+ :before-upload="beforeUpload"
|
|
|
+ :limit="4"
|
|
|
+ list-type="picture-card"
|
|
|
+ accept="image/*"
|
|
|
+ >
|
|
|
+ <i class="el-icon-plus"></i>
|
|
|
+ <div slot="tip" class="el-upload__tip">
|
|
|
+ 最多上传4张图片,单张图片不超过2MB
|
|
|
+ </div>
|
|
|
+ </el-upload>
|
|
|
+ </div> -->
|
|
|
+ <ImageUpload v-model="replyForm.images" type="image" :num="4" :width="150" :height="150"/>
|
|
|
+
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" size="small" @click="submitReply" :loading="replyLoading">
|
|
|
+ <i class="el-icon-s-promotion"></i> 发送回复
|
|
|
+ </el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <!-- 回复列表 -->
|
|
|
+ <el-card class="reply-list-card" shadow="never">
|
|
|
+ <div slot="header">
|
|
|
+ <span>回复记录 ({{ replyTotal }}条)</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-loading="replyLoading" class="reply-list">
|
|
|
+ <div v-if="replyList.length === 0" class="empty-replies">
|
|
|
+ <el-empty description="暂无回复记录" :image-size="100"></el-empty>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-else>
|
|
|
+ <div v-for="reply in replyList" :key="reply.id" class="reply-item">
|
|
|
+ <div class="reply-header">
|
|
|
+ <div class="reply-user">
|
|
|
+ <el-avatar :size="32" :src="reply.avatar || '/default-avatar.png'">
|
|
|
+ {{ reply.userName ? reply.userName.charAt(0) : 'U' }}
|
|
|
+ </el-avatar>
|
|
|
+ <!-- <span class="user-name">{{ reply.userName || '系统管理员' }}</span> -->
|
|
|
+ <el-tag size="mini" :type="reply.sendType != 1 ? 'success' : 'info'">
|
|
|
+ {{ reply.sendType === 1 ? '用户' : reply.sendType === 2 ? '系统平台':'店铺平台' }}
|
|
|
+ </el-tag>
|
|
|
+ </div>
|
|
|
+ <div class="reply-time">
|
|
|
+ {{ reply.createTime }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="reply-content">
|
|
|
+ {{ reply.content }}
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 显示回复中的图片 -->
|
|
|
+ <div class="reply-images" v-if="reply.images && reply.images !== ''">
|
|
|
+ <div v-for="(url, index) in imageUrls(reply.images)" :key="index" class="reply-image-container">
|
|
|
+ <el-image
|
|
|
+ :src="url"
|
|
|
+ :preview-src-list="imageUrls(reply.images)"
|
|
|
+ style="width: 80px; height: 80px;"
|
|
|
+ fit="cover"
|
|
|
+ ></el-image>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="reply-actions" v-if="reply.userType === 'admin'">
|
|
|
+ <el-button type="text" size="mini" @click="editReply(reply)">
|
|
|
+ <i class="el-icon-edit"></i> 编辑
|
|
|
+ </el-button>
|
|
|
+ <el-button type="text" size="mini" @click="deleteReply(reply)" style="color: #f56c6c;">
|
|
|
+ <i class="el-icon-delete"></i> 删除
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 回复分页 -->
|
|
|
+ <div class="reply-pagination" v-if="replyTotal > 0">
|
|
|
+ <el-pagination
|
|
|
+ @size-change="handleReplySizeChange"
|
|
|
+ @current-change="handleReplyCurrentChange"
|
|
|
+ :current-page="replyQueryParams.pageNum"
|
|
|
+ :page-sizes="[5, 10, 20]"
|
|
|
+ :page-size="replyQueryParams.pageSize"
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
+ :total="replyTotal"
|
|
|
+ small
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
+ <el-button type="primary" @click="submitForm" v-if="activeTab === 'complaint' && form.id==null">确 定</el-button>
|
|
|
+ <el-button @click="cancel">取 消</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+
|
|
|
+ <!-- 编辑回复对话框 -->
|
|
|
+ <el-dialog title="编辑回复" :visible.sync="editReplyVisible" width="500px" append-to-body>
|
|
|
+ <el-form :model="editReplyForm" ref="editReplyForm" label-width="80px">
|
|
|
+ <el-form-item label="回复内容" prop="content" :rules="[{ required: true, message: '请输入回复内容', trigger: 'blur' }]">
|
|
|
+ <el-input
|
|
|
+ type="textarea"
|
|
|
+ v-model="editReplyForm.content"
|
|
|
+ placeholder="请输入回复内容"
|
|
|
+ :rows="4"
|
|
|
+ maxlength="500"
|
|
|
+ show-word-limit
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
+ <el-button type="primary" @click="updateReply" :loading="replyLoading">确 定</el-button>
|
|
|
+ <el-button @click="editReplyVisible = false">取 消</el-button>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { listComplaint, getComplaint, delComplaint, addComplaint, updateComplaint, exportComplaint,listMsg,addMsg } from "@/api/store/complaint";
|
|
|
+import ImageUpload from '@/components/ImageUpload/index';
|
|
|
+export default {
|
|
|
+ name: "Complaint",
|
|
|
+ components: {
|
|
|
+ ImageUpload
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ replyImageList: [],
|
|
|
+ uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
|
|
|
+ complaintId:null,
|
|
|
+ activeName:"0",
|
|
|
+ typeOptions:[
|
|
|
+ {
|
|
|
+ dictValue:'0',
|
|
|
+ dictLabel:'默认'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ dictValue:'1',
|
|
|
+ dictLabel:'店铺'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ dictValue:'2',
|
|
|
+ dictLabel:'商品'
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ complaintTypeOptions:[
|
|
|
+ {
|
|
|
+ dictValue:1,
|
|
|
+ dictLabel:'咨询'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ dictValue:2,
|
|
|
+ dictLabel:'投诉/举报'
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ complaintTime:null,
|
|
|
+ // 遮罩层
|
|
|
+ loading: true,
|
|
|
+ // 导出遮罩层
|
|
|
+ exportLoading: false,
|
|
|
+ // 选中数组
|
|
|
+ ids: [],
|
|
|
+ // 非单个禁用
|
|
|
+ single: true,
|
|
|
+ // 非多个禁用
|
|
|
+ multiple: true,
|
|
|
+ // 显示搜索条件
|
|
|
+ showSearch: true,
|
|
|
+ // 总条数
|
|
|
+ total: 0,
|
|
|
+ // 用户投诉表格数据
|
|
|
+ complaintList: [],
|
|
|
+ // 弹出层标题
|
|
|
+ title: "",
|
|
|
+ // 是否显示弹出层
|
|
|
+ open: false,
|
|
|
+ // 当前激活的标签页
|
|
|
+ activeTab: 'complaint',
|
|
|
+ // 查询参数
|
|
|
+ queryParams: {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ userId: null,
|
|
|
+ userName: null,
|
|
|
+ templateId: null,
|
|
|
+ content: null,
|
|
|
+ phone: null,
|
|
|
+ urls: null,
|
|
|
+ account: null,
|
|
|
+ isHandle: null
|
|
|
+ },
|
|
|
+ // 表单参数
|
|
|
+ form: {},
|
|
|
+ // 表单校验
|
|
|
+ rules: {
|
|
|
+ userId: [
|
|
|
+ { required: true, message: "用户id不能为空", trigger: "blur" }
|
|
|
+ ],
|
|
|
+ templateId: [
|
|
|
+ { required: true, message: "投诉模板id不能为空", trigger: "blur" }
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ // 回复相关数据
|
|
|
+ replyList: [],
|
|
|
+ replyTotal: 0,
|
|
|
+ replyLoading: false,
|
|
|
+ replyQueryParams: {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ complaintId: null
|
|
|
+ },
|
|
|
+ replyForm: {
|
|
|
+ content: '',
|
|
|
+ complaintId: null
|
|
|
+ },
|
|
|
+ // 编辑回复
|
|
|
+ editReplyVisible: false,
|
|
|
+ editReplyForm: {
|
|
|
+ id: null,
|
|
|
+ content: ''
|
|
|
+ }
|
|
|
+ };
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ this.getList();
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ handleClick(tab) {
|
|
|
+ if (tab.name === 'replies') {
|
|
|
+ this.getReplyList();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ renderHandleHeader(h, { column }) {
|
|
|
+ if (column.label === '是否处理') {
|
|
|
+ return h('div', [
|
|
|
+ '是否处理',
|
|
|
+ h('el-tooltip', {
|
|
|
+ props: {
|
|
|
+ content: '仅需要处理投诉/举报类',
|
|
|
+ placement: 'top'
|
|
|
+ }
|
|
|
+ }, [
|
|
|
+ h('i', {
|
|
|
+ class: 'el-icon-question',
|
|
|
+ style: 'margin-left: 5px; cursor: pointer; color: #909399;'
|
|
|
+ })
|
|
|
+ ])
|
|
|
+ ]);
|
|
|
+ } else if (column.label === '店铺是否处理') {
|
|
|
+ return h('div', [
|
|
|
+ '店铺是否处理',
|
|
|
+ h('el-tooltip', {
|
|
|
+ props: {
|
|
|
+ content: '仅需要处理咨询类',
|
|
|
+ placement: 'top'
|
|
|
+ }
|
|
|
+ }, [
|
|
|
+ h('i', {
|
|
|
+ class: 'el-icon-question',
|
|
|
+ style: 'margin-left: 5px; cursor: pointer; color: #909399;'
|
|
|
+ })
|
|
|
+ ])
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ return column.label;
|
|
|
+ },
|
|
|
+ imageUrls(urls) {
|
|
|
+ return String(urls).split(",");
|
|
|
+ },
|
|
|
+ formatHandleStatus(status) {
|
|
|
+ return status == 1 ? '已处理' : '未处理';
|
|
|
+ },
|
|
|
+ /** 查询用户投诉列表 */
|
|
|
+ getList() {
|
|
|
+ this.loading = true;
|
|
|
+ listComplaint(this.queryParams).then(response => {
|
|
|
+ this.complaintList = response.rows;
|
|
|
+ this.total = response.total;
|
|
|
+ this.loading = false;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 取消按钮
|
|
|
+ cancel() {
|
|
|
+ this.open = false;
|
|
|
+ this.reset();
|
|
|
+ this.resetReplyData();
|
|
|
+ },
|
|
|
+ // 表单重置
|
|
|
+ reset() {
|
|
|
+ this.form = {
|
|
|
+ id: null,
|
|
|
+ userId: null,
|
|
|
+ templateId: null,
|
|
|
+ content: null,
|
|
|
+ phone: null,
|
|
|
+ urls: null,
|
|
|
+ account: null,
|
|
|
+ createTime: null,
|
|
|
+ isHandle: 0,
|
|
|
+ remarks:null
|
|
|
+ };
|
|
|
+ this.resetForm("form");
|
|
|
+ },
|
|
|
+ // 重置回复数据
|
|
|
+ resetReplyData() {
|
|
|
+ this.activeTab = 'complaint';
|
|
|
+ this.replyList = [];
|
|
|
+ this.replyTotal = 0;
|
|
|
+ this.replyQueryParams = {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ complaintId: null
|
|
|
+ };
|
|
|
+ this.replyForm = {
|
|
|
+ content: '',
|
|
|
+ complaintId: null,
|
|
|
+ images: '' // 重置图片字段
|
|
|
+ };
|
|
|
+ this.replyImageList = [];
|
|
|
+ this.editReplyImageList = [];
|
|
|
+ },
|
|
|
+ /** 搜索按钮操作 */
|
|
|
+ handleQuery() {
|
|
|
+ this.queryParams.pageNum = 1;
|
|
|
+ this.getList();
|
|
|
+ },
|
|
|
+ /** 重置按钮操作 */
|
|
|
+ resetQuery() {
|
|
|
+ this.complaintTime = null;
|
|
|
+ this.queryParams.complaintsTime=null;
|
|
|
+ this.queryParams.complainteTime=null;
|
|
|
+ this.resetForm("queryForm");
|
|
|
+ this.handleQuery();
|
|
|
+ },
|
|
|
+ // 多选框选中数据
|
|
|
+ handleSelectionChange(selection) {
|
|
|
+ this.ids = selection.map(item => item.id)
|
|
|
+ this.single = selection.length !== 1
|
|
|
+ this.multiple = !selection.length
|
|
|
+ },
|
|
|
+ /** 新增按钮操作 */
|
|
|
+ handleAdd() {
|
|
|
+ this.reset();
|
|
|
+ this.open = true;
|
|
|
+ this.title = "添加用户投诉";
|
|
|
+ },
|
|
|
+ /** 修改按钮操作 */
|
|
|
+ handleUpdate(row) {
|
|
|
+ this.reset();
|
|
|
+ this.resetReplyData();
|
|
|
+ // const id = row.id || this.ids
|
|
|
+ const complaintId = row.id || this.complaintId
|
|
|
+ this.complaintId = complaintId;
|
|
|
+ getComplaint(complaintId).then(response => {
|
|
|
+ this.form = response.data;
|
|
|
+ this.replyForm.complaintId = complaintId;
|
|
|
+ this.replyQueryParams.complaintId = complaintId;
|
|
|
+ this.open = true;
|
|
|
+ this.title = "投诉详情";
|
|
|
+ // 加载回复列表
|
|
|
+ this.getReplyList();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ /** 提交按钮 */
|
|
|
+ submitForm() {
|
|
|
+ this.$refs["form"].validate(valid => {
|
|
|
+ if (valid) {
|
|
|
+ if (this.form.id != null) {
|
|
|
+ updateComplaint(this.form).then(response => {
|
|
|
+ this.msgSuccess("修改成功");
|
|
|
+ this.open = false;
|
|
|
+ this.getList();
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ addComplaint(this.form).then(response => {
|
|
|
+ this.msgSuccess("新增成功");
|
|
|
+ this.open = false;
|
|
|
+ this.getList();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ /** 删除按钮操作 */
|
|
|
+ handleDelete(row) {
|
|
|
+ const ids = row.id || this.ids;
|
|
|
+ this.$confirm('是否确认删除用户投诉编号为"' + ids + '"的数据项?', "警告", {
|
|
|
+ confirmButtonText: "确定",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning"
|
|
|
+ }).then(function() {
|
|
|
+ return delComplaint(ids);
|
|
|
+ }).then(() => {
|
|
|
+ this.getList();
|
|
|
+ this.msgSuccess("删除成功");
|
|
|
+ }).catch(() => {});
|
|
|
+ },
|
|
|
+ /** 导出按钮操作 */
|
|
|
+ handleExport() {
|
|
|
+ const queryParams = this.queryParams;
|
|
|
+ this.$confirm('是否确认导出所有用户投诉数据项?', "警告", {
|
|
|
+ confirmButtonText: "确定",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning"
|
|
|
+ }).then(() => {
|
|
|
+ this.exportLoading = true;
|
|
|
+ return exportComplaint(queryParams);
|
|
|
+ }).then(response => {
|
|
|
+ this.download(response.msg);
|
|
|
+ this.exportLoading = false;
|
|
|
+ }).catch(() => {});
|
|
|
+ },
|
|
|
+ changeTime(){
|
|
|
+ if(this.complaintTime!=null){
|
|
|
+ this.queryParams.complaintsTime=this.complaintTime[0];
|
|
|
+ this.queryParams.complainteTime=this.complaintTime[1];
|
|
|
+ }else{
|
|
|
+ this.queryParams.complaintsTime=null;
|
|
|
+ this.queryParams.complainteTime=null;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 获取回复列表
|
|
|
+ getReplyList() {
|
|
|
+ this.replyLoading = true;
|
|
|
+ // 模拟API调用 - 你需要替换为实际的API
|
|
|
+ setTimeout(() => {
|
|
|
+ // 模拟数据
|
|
|
+ listMsg(this.replyQueryParams).then(response => {
|
|
|
+ this.replyList = response.rows;
|
|
|
+ this.replyTotal = response.total;
|
|
|
+ this.replyLoading = false;
|
|
|
+ });
|
|
|
+ }, 500);
|
|
|
+ },
|
|
|
+ // 提交回复
|
|
|
+ submitReply() {
|
|
|
+ this.$refs.replyForm.validate(valid => {
|
|
|
+ if (valid) {
|
|
|
+ this.replyLoading = true;
|
|
|
+ // const imageUrls = this.replyImageList.map(file => file.url || file.response?.url).filter(url => url);
|
|
|
+ // this.replyForm.images = imageUrls.join(',');
|
|
|
+ // 模拟API调用
|
|
|
+ setTimeout(() => {
|
|
|
+ const newReply = {
|
|
|
+ content: this.replyForm.content,
|
|
|
+ complaintId:this.replyForm.complaintId,
|
|
|
+ images: this.replyForm.images, // 包含图片数据
|
|
|
+ sendType: 2
|
|
|
+ };
|
|
|
+ addMsg(newReply).then(response => {
|
|
|
+ this.replyLoading = false;
|
|
|
+ this.$message.success('回复发送成功');
|
|
|
+ this.replyForm.content = '';
|
|
|
+ this.replyForm.images = ''; // 重置图片字段
|
|
|
+ this.replyImageList = []; // 重置图片列表
|
|
|
+ this.getReplyList()
|
|
|
+ });
|
|
|
+
|
|
|
+ }, 500);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 编辑回复
|
|
|
+ editReply(reply) {
|
|
|
+ this.editReplyForm = {
|
|
|
+ id: reply.id,
|
|
|
+ content: reply.content,
|
|
|
+ images: reply.images || '' // 包含图片数据
|
|
|
+ };
|
|
|
+ this.editReplyImageList = reply.images ?
|
|
|
+ reply.images.split(',').map((url, index) => ({
|
|
|
+ uid: index,
|
|
|
+ name: `image-${index}`,
|
|
|
+ url: url
|
|
|
+ })) : [];
|
|
|
+ this.editReplyVisible = true;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 更新回复
|
|
|
+ updateReply() {
|
|
|
+ this.$refs.editReplyForm.validate(valid => {
|
|
|
+ if (valid) {
|
|
|
+ this.replyLoading = true;
|
|
|
+ // const imageUrls = this.editReplyImageList.map(file => file.url || file.response?.url).filter(url => url);
|
|
|
+ // this.editReplyForm.images = imageUrls.join(',');
|
|
|
+
|
|
|
+ // 模拟API调用
|
|
|
+ setTimeout(() => {
|
|
|
+ const index = this.replyList.findIndex(item => item.id === this.editReplyForm.id);
|
|
|
+ if (index !== -1) {
|
|
|
+ this.replyList[index].content = this.editReplyForm.content;
|
|
|
+ this.replyList[index].images = this.editReplyForm.images; // 更新图片
|
|
|
+ }
|
|
|
+ this.editReplyVisible = false;
|
|
|
+ this.replyLoading = false;
|
|
|
+ this.$message.success('回复更新成功');
|
|
|
+ }, 500);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 删除回复
|
|
|
+ deleteReply(reply) {
|
|
|
+ this.$confirm('确定要删除这条回复吗?', '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ const index = this.replyList.findIndex(item => item.id === reply.id);
|
|
|
+ if (index !== -1) {
|
|
|
+ this.replyList.splice(index, 1);
|
|
|
+ this.replyTotal--;
|
|
|
+ this.$message.success('删除成功');
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 回复分页大小改变
|
|
|
+ handleReplySizeChange(val) {
|
|
|
+ this.replyQueryParams.pageSize = val;
|
|
|
+ this.getReplyList();
|
|
|
+ },
|
|
|
+ // 回复当前页改变
|
|
|
+ handleReplyCurrentChange(val) {
|
|
|
+ this.replyQueryParams.pageNum = val;
|
|
|
+ this.getReplyList();
|
|
|
+ },
|
|
|
+ handleSuccess(res, file) {
|
|
|
+ if(res.code==200){
|
|
|
+ this.form.licenseImages=res.url;
|
|
|
+ this.$forceUpdate()
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ this.msgError(res.msg);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ beforeUpload(file) {
|
|
|
+ const isLt1M = file.size / 1024 / 1024 < 1;
|
|
|
+ if (!isLt1M) {
|
|
|
+ this.$message.error('上传图片大小不能超过 1MB!');
|
|
|
+ }
|
|
|
+ return isLt1M;
|
|
|
+ },
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.reply-section {
|
|
|
+ margin-top: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.add-reply-card {
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.reply-list-card {
|
|
|
+ min-height: 400px;
|
|
|
+}
|
|
|
+
|
|
|
+.reply-list {
|
|
|
+ min-height: 300px;
|
|
|
+}
|
|
|
+
|
|
|
+.empty-replies {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ height: 200px;
|
|
|
+}
|
|
|
+
|
|
|
+.reply-item {
|
|
|
+ border-bottom: 1px solid #f0f0f0;
|
|
|
+ padding: 15px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.reply-item:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+}
|
|
|
+
|
|
|
+.reply-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.reply-user {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.user-name {
|
|
|
+ font-weight: 500;
|
|
|
+ color: #303133;
|
|
|
+}
|
|
|
+
|
|
|
+.reply-time {
|
|
|
+ color: #909399;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.reply-content {
|
|
|
+ background-color: #f8f9fa;
|
|
|
+ padding: 12px;
|
|
|
+ border-radius: 6px;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ line-height: 1.5;
|
|
|
+ color: #606266;
|
|
|
+}
|
|
|
+
|
|
|
+.reply-actions {
|
|
|
+ text-align: right;
|
|
|
+}
|
|
|
+
|
|
|
+.reply-pagination {
|
|
|
+ margin-top: 20px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.image-container {
|
|
|
+ display: inline-block;
|
|
|
+ margin-right: 10px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+</style>
|