|
|
@@ -40,7 +40,7 @@
|
|
|
批量处理
|
|
|
</el-button>
|
|
|
</template>
|
|
|
-
|
|
|
+
|
|
|
<template slot="status" slot-scope="{row}">
|
|
|
<el-tag
|
|
|
:type="getComplaintStatusType(row.status)"
|
|
|
@@ -49,7 +49,7 @@
|
|
|
{{ getComplaintStatusLabel(row.status) }}
|
|
|
</el-tag>
|
|
|
</template>
|
|
|
-
|
|
|
+
|
|
|
<template slot="replyStatus" slot-scope="{row}">
|
|
|
<el-tag
|
|
|
:type="getReplyStatusType(row.replyStatus)"
|
|
|
@@ -58,7 +58,7 @@
|
|
|
{{ getReplyStatusLabel(row.replyStatus) }}
|
|
|
</el-tag>
|
|
|
</template>
|
|
|
-
|
|
|
+
|
|
|
<template slot="complainantType" slot-scope="{row}">
|
|
|
<el-tag
|
|
|
:type="getComplainantTypeType(row.complainantType)"
|
|
|
@@ -67,7 +67,7 @@
|
|
|
{{ getComplainantTypeLabel(row.complainantType) }}
|
|
|
</el-tag>
|
|
|
</template>
|
|
|
-
|
|
|
+
|
|
|
<template slot="menu" slot-scope="{row}">
|
|
|
<el-button
|
|
|
type="text"
|
|
|
@@ -106,7 +106,7 @@
|
|
|
</el-button>
|
|
|
</template>
|
|
|
</avue-crud>
|
|
|
-
|
|
|
+
|
|
|
<!-- 投诉详情对话框 -->
|
|
|
<el-dialog
|
|
|
title="投诉详情"
|
|
|
@@ -133,7 +133,7 @@
|
|
|
</div>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
-
|
|
|
+
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="12">
|
|
|
<div class="detail-item">
|
|
|
@@ -148,7 +148,7 @@
|
|
|
</div>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
-
|
|
|
+
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="12">
|
|
|
<div class="detail-item">
|
|
|
@@ -163,7 +163,7 @@
|
|
|
</div>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
-
|
|
|
+
|
|
|
<el-row :gutter="20" v-if="detailData.customerName">
|
|
|
<el-col :span="12">
|
|
|
<div class="detail-item">
|
|
|
@@ -178,7 +178,7 @@
|
|
|
</div>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
-
|
|
|
+
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="12">
|
|
|
<div class="detail-item">
|
|
|
@@ -197,7 +197,7 @@
|
|
|
</div>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
-
|
|
|
+
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="24">
|
|
|
<div class="detail-item">
|
|
|
@@ -206,7 +206,7 @@
|
|
|
</div>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
-
|
|
|
+
|
|
|
<el-row :gutter="20" v-if="detailData.closeReason">
|
|
|
<el-col :span="24">
|
|
|
<div class="detail-item">
|
|
|
@@ -215,7 +215,7 @@
|
|
|
</div>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
-
|
|
|
+
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="12">
|
|
|
<div class="detail-item">
|
|
|
@@ -231,12 +231,12 @@
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
</div>
|
|
|
-
|
|
|
+
|
|
|
<div slot="footer" class="dialog-footer">
|
|
|
<el-button @click="detailVisible = false">关闭</el-button>
|
|
|
</div>
|
|
|
</el-dialog>
|
|
|
-
|
|
|
+
|
|
|
<!-- 状态处理对话框 -->
|
|
|
<el-dialog
|
|
|
:title="statusDialogTitle"
|
|
|
@@ -262,7 +262,7 @@
|
|
|
></el-input>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
-
|
|
|
+
|
|
|
<div slot="footer" class="dialog-footer">
|
|
|
<el-button @click="statusVisible = false">取消</el-button>
|
|
|
<el-button type="primary" @click="confirmStatusUpdate" :loading="statusLoading">确定</el-button>
|
|
|
@@ -272,494 +272,25 @@
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import { getList, add, update, remove, getDetail, updateStatus, batchUpdateStatus } from '@/api/complaint'
|
|
|
-import { mapGetters } from 'vuex'
|
|
|
-import {
|
|
|
- COMPLAINANT_TYPE_OPTIONS,
|
|
|
- COMPLAINT_TYPE_OPTIONS,
|
|
|
- COMPLAINT_STATUS_OPTIONS,
|
|
|
- REPLY_STATUS_OPTIONS,
|
|
|
- getComplainantTypeLabel,
|
|
|
- getComplaintTypeLabel,
|
|
|
- getComplainantTypeType,
|
|
|
- getComplaintStatusLabel,
|
|
|
- getComplaintStatusType,
|
|
|
- getReplyStatusLabel,
|
|
|
- getReplyStatusType,
|
|
|
- isComplaintEditable,
|
|
|
- // getComplainantTypeText,
|
|
|
- isComplaintProcessable,
|
|
|
- isComplaintClosable,
|
|
|
- isValidComplaintStatus,
|
|
|
- isValidReplyStatus
|
|
|
-} from '@/constants/complaint'
|
|
|
-
|
|
|
-/**
|
|
|
- * 投诉查询参数类型定义
|
|
|
- * @typedef {Object} ComplaintQueryParams
|
|
|
- * @property {string} [complaintNo] - 投诉单号
|
|
|
- * @property {string} [title] - 投诉标题
|
|
|
- * @property {number} [complainantType] - 投诉人类型
|
|
|
- * @property {string} [customerCode] - 客户编码
|
|
|
- * @property {string} [customerName] - 客户名称
|
|
|
- * @property {string} [contactName] - 联系人姓名
|
|
|
- * @property {string} [contactPhone] - 联系人电话
|
|
|
- * @property {string} [complaintType] - 投诉类型
|
|
|
- * @property {number} [status] - 投诉状态
|
|
|
- * @property {number} [replyStatus] - 回复状态
|
|
|
- * @property {string} [submitTimeStart] - 提交时间开始
|
|
|
- * @property {string} [submitTimeEnd] - 提交时间结束
|
|
|
- */
|
|
|
-
|
|
|
-/**
|
|
|
- * 状态更新表单类型定义
|
|
|
- * @typedef {Object} StatusForm
|
|
|
- * @property {number} status - 新状态
|
|
|
- * @property {string} [closeReason] - 关闭原因
|
|
|
- */
|
|
|
+import complaintMixin from './complaintMixin';
|
|
|
|
|
|
export default {
|
|
|
- data() {
|
|
|
- return {
|
|
|
- /** @type {ComplaintRecord[]} */
|
|
|
- data: [],
|
|
|
- /** @type {ComplaintQueryParams} */
|
|
|
- query: {},
|
|
|
- loading: true,
|
|
|
- /** @type {ComplaintForm} */
|
|
|
- form: {},
|
|
|
- /** @type {ComplaintRecord[]} */
|
|
|
- selectionList: [],
|
|
|
- /** @type {Object} */
|
|
|
- page: {
|
|
|
- pageSize: 10,
|
|
|
- currentPage: 1,
|
|
|
- total: 0
|
|
|
- },
|
|
|
- /** @type {ComplaintRecord|null} */
|
|
|
- detailData: null,
|
|
|
- detailVisible: false,
|
|
|
- statusVisible: false,
|
|
|
- statusDialogTitle: '',
|
|
|
- /** @type {StatusForm} */
|
|
|
- statusForm: {
|
|
|
- status: 1,
|
|
|
- closeReason: ''
|
|
|
- },
|
|
|
- statusLoading: false,
|
|
|
- /** @type {string[]} */
|
|
|
- currentIds: [],
|
|
|
- statusRules: {
|
|
|
- status: [
|
|
|
- { required: true, message: '请选择状态', trigger: 'change' }
|
|
|
- ],
|
|
|
- closeReason: [
|
|
|
- { required: true, message: '请输入关闭原因', trigger: 'blur' }
|
|
|
- ]
|
|
|
- },
|
|
|
- option: {
|
|
|
- height: 'auto',
|
|
|
- calcHeight: 30,
|
|
|
- tip: false,
|
|
|
- searchShow: true,
|
|
|
- searchMenuSpan: 6,
|
|
|
- border: true,
|
|
|
- index: true,
|
|
|
- viewBtn: true,
|
|
|
- selection: true,
|
|
|
- dialogClickModal: false,
|
|
|
- column: [
|
|
|
- {
|
|
|
- label: '投诉单号',
|
|
|
- prop: 'complaintNo',
|
|
|
- minWidth: 150,
|
|
|
- search: true
|
|
|
- },
|
|
|
- {
|
|
|
- label: '投诉标题',
|
|
|
- prop: 'title',
|
|
|
- minWidth: 200,
|
|
|
- search: true,
|
|
|
- overHidden: true
|
|
|
- },
|
|
|
- {
|
|
|
- label: '投诉人类型',
|
|
|
- prop: 'complainantType',
|
|
|
- minWidth: 100,
|
|
|
- slot: true,
|
|
|
- search: true,
|
|
|
- type: 'select',
|
|
|
- dicData: COMPLAINANT_TYPE_OPTIONS
|
|
|
- },
|
|
|
- {
|
|
|
- label: '客户名称',
|
|
|
- prop: 'customerName',
|
|
|
- minWidth: 150,
|
|
|
- search: true,
|
|
|
- overHidden: true
|
|
|
- },
|
|
|
- {
|
|
|
- label: '联系人',
|
|
|
- prop: 'contactName',
|
|
|
- minWidth: 100,
|
|
|
- search: true
|
|
|
- },
|
|
|
- {
|
|
|
- label: '联系电话',
|
|
|
- prop: 'contactPhone',
|
|
|
- minWidth: 120,
|
|
|
- search: true
|
|
|
- },
|
|
|
- {
|
|
|
- label: '投诉类型',
|
|
|
- prop: 'complaintType',
|
|
|
- minWidth: 100,
|
|
|
- search: true,
|
|
|
- type: 'select',
|
|
|
- dicData: COMPLAINT_TYPE_OPTIONS
|
|
|
- },
|
|
|
- {
|
|
|
- label: '投诉状态',
|
|
|
- prop: 'status',
|
|
|
- minWidth: 100,
|
|
|
- slot: true,
|
|
|
- search: true,
|
|
|
- type: 'select',
|
|
|
- dicData: COMPLAINT_STATUS_OPTIONS
|
|
|
- },
|
|
|
- {
|
|
|
- label: '回复状态',
|
|
|
- prop: 'replyStatus',
|
|
|
- minWidth: 100,
|
|
|
- slot: true,
|
|
|
- search: true,
|
|
|
- type: 'select',
|
|
|
- dicData: REPLY_STATUS_OPTIONS
|
|
|
- },
|
|
|
- {
|
|
|
- label: '提交时间',
|
|
|
- prop: 'submitTime',
|
|
|
- minWidth: 150,
|
|
|
- type: 'datetime',
|
|
|
- format: 'YYYY-MM-DD HH:mm:ss',
|
|
|
- valueFormat: 'YYYY-MM-DD HH:mm:ss'
|
|
|
- },
|
|
|
- {
|
|
|
- label: '更新时间',
|
|
|
- prop: 'updateTime',
|
|
|
- minWidth: 150,
|
|
|
- type: 'datetime',
|
|
|
- format: 'YYYY-MM-DD HH:mm:ss',
|
|
|
- valueFormat: 'YYYY-MM-DD HH:mm:ss'
|
|
|
- }
|
|
|
- ]
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
- computed: {
|
|
|
- ...mapGetters(['permission']),
|
|
|
- permissionList() {
|
|
|
- return {
|
|
|
- addBtn: this.vaildData(this.permission.complaint_add, false),
|
|
|
- viewBtn: this.vaildData(this.permission.complaint_view, false),
|
|
|
- delBtn: this.vaildData(this.permission.complaint_delete, false),
|
|
|
- editBtn: this.vaildData(this.permission.complaint_edit, false)
|
|
|
- }
|
|
|
- },
|
|
|
- ids() {
|
|
|
- /** @type {string[]} */
|
|
|
- const ids = []
|
|
|
- this.selectionList.forEach(ele => {
|
|
|
- ids.push(ele.id)
|
|
|
- })
|
|
|
- return ids.join(',')
|
|
|
- }
|
|
|
- },
|
|
|
- methods: {
|
|
|
-
|
|
|
- // 导入工具函数
|
|
|
- getComplainantTypeLabel,
|
|
|
- getComplainantTypeType,
|
|
|
- getComplaintTypeLabel,
|
|
|
- getComplaintStatusLabel,
|
|
|
- getComplaintStatusType,
|
|
|
- getReplyStatusLabel,
|
|
|
- getReplyStatusType,
|
|
|
- isComplaintEditable,
|
|
|
- isComplaintProcessable,
|
|
|
- // getComplainantTypeText,
|
|
|
- isComplaintClosable,
|
|
|
-
|
|
|
- /**
|
|
|
- * 行保存
|
|
|
- * @param {ComplaintForm} row - 表单数据
|
|
|
- * @param {Function} done - 完成回调
|
|
|
- * @param {Function} loading - 加载状态回调
|
|
|
- */
|
|
|
- async rowSave(row, done, loading) {
|
|
|
- try {
|
|
|
- loading()
|
|
|
- const res = await add(row)
|
|
|
- if (res.data.success) {
|
|
|
- this.$message.success('操作成功')
|
|
|
- done()
|
|
|
- this.onLoad(this.page)
|
|
|
- } else {
|
|
|
- this.$message.error(res.data.msg || '操作失败')
|
|
|
- loading()
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error('新增投诉失败:', error)
|
|
|
- this.$message.error('操作失败')
|
|
|
- loading()
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 行更新
|
|
|
- * @param {ComplaintForm} row - 表单数据
|
|
|
- * @param {number} index - 行索引
|
|
|
- * @param {Function} done - 完成回调
|
|
|
- * @param {Function} loading - 加载状态回调
|
|
|
- */
|
|
|
- async rowUpdate(row, index, done, loading) {
|
|
|
- try {
|
|
|
- loading()
|
|
|
- const res = await update(row)
|
|
|
- if (res.data.success) {
|
|
|
- this.$message.success('操作成功')
|
|
|
- done()
|
|
|
- this.onLoad(this.page)
|
|
|
- } else {
|
|
|
- this.$message.error(res.data.msg || '操作失败')
|
|
|
- loading()
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error('更新投诉失败:', error)
|
|
|
- this.$message.error('操作失败')
|
|
|
- loading()
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 行删除
|
|
|
- * @param {ComplaintRecord} row - 行数据
|
|
|
- * @param {number} index - 行索引
|
|
|
- */
|
|
|
- async rowDel(row, index) {
|
|
|
- try {
|
|
|
- const res = await remove(row.id)
|
|
|
- if (res.data.success) {
|
|
|
- this.$message.success('操作成功')
|
|
|
- this.onLoad(this.page)
|
|
|
- } else {
|
|
|
- this.$message.error(res.data.msg || '操作失败')
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error('删除投诉失败:', error)
|
|
|
- this.$message.error('操作失败')
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 搜索变化
|
|
|
- * @param {ComplaintQueryParams} params - 搜索参数
|
|
|
- * @param {boolean} done - 完成回调
|
|
|
- */
|
|
|
- searchChange(params, done) {
|
|
|
- this.query = params
|
|
|
- this.onLoad(this.page, params)
|
|
|
- done()
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 搜索重置
|
|
|
- */
|
|
|
- searchReset() {
|
|
|
- this.query = {}
|
|
|
- this.onLoad(this.page)
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 选择变化
|
|
|
- * @param {ComplaintRecord[]} val - 选中的行
|
|
|
- */
|
|
|
- selectionChange(val) {
|
|
|
- this.selectionList = val
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 当前页变化
|
|
|
- * @param {number} currentPage - 当前页
|
|
|
- */
|
|
|
- currentChange(currentPage) {
|
|
|
- this.page.currentPage = currentPage
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 页大小变化
|
|
|
- * @param {number} pageSize - 页大小
|
|
|
- */
|
|
|
- sizeChange(pageSize) {
|
|
|
- this.page.pageSize = pageSize
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 刷新变化
|
|
|
- */
|
|
|
- refreshChange() {
|
|
|
- this.onLoad(this.page, this.query)
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 加载数据
|
|
|
- * @param {Object} page - 分页信息
|
|
|
- * @param {ComplaintQueryParams} [params={}] - 查询参数
|
|
|
- */
|
|
|
- async onLoad(page, params = {}) {
|
|
|
- this.loading = true
|
|
|
- try {
|
|
|
- const res = await getList(page.currentPage, page.pageSize, Object.assign(params, this.query))
|
|
|
- if (res.data.success) {
|
|
|
- const data = res.data.data
|
|
|
- this.data = data.records
|
|
|
- this.page.total = data.total
|
|
|
- } else {
|
|
|
- this.$message.error(res.data.msg || '查询失败')
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error('查询投诉列表失败:', error)
|
|
|
- this.$message.error('查询失败')
|
|
|
- } finally {
|
|
|
- this.loading = false
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 新增投诉
|
|
|
- */
|
|
|
- handleAdd() {
|
|
|
- this.$refs.crud.rowAdd()
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 编辑投诉
|
|
|
- * @param {ComplaintRecord} row - 行数据
|
|
|
- */
|
|
|
- handleEdit(row) {
|
|
|
- this.$refs.crud.rowEdit(row, this.data.indexOf(row))
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 查看详情
|
|
|
- * @param {ComplaintRecord} row - 行数据
|
|
|
- */
|
|
|
- async handleDetail(row) {
|
|
|
- try {
|
|
|
- const res = await getDetail(row.id)
|
|
|
- if (res.data.success) {
|
|
|
- this.detailData = res.data.data
|
|
|
- this.detailVisible = true
|
|
|
- } else {
|
|
|
- this.$message.error(res.data.msg || '获取详情失败')
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error('获取投诉详情失败:', error)
|
|
|
- this.$message.error('获取详情失败')
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 处理投诉
|
|
|
- * @param {ComplaintRecord} row - 行数据
|
|
|
- */
|
|
|
- handleProcess(row) {
|
|
|
- this.statusDialogTitle = '处理投诉'
|
|
|
- this.statusForm = {
|
|
|
- status: 2,
|
|
|
- closeReason: ''
|
|
|
- }
|
|
|
- this.currentIds = [row.id]
|
|
|
- this.statusVisible = true
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 关闭投诉
|
|
|
- * @param {ComplaintRecord} row - 行数据
|
|
|
- */
|
|
|
- handleClose(row) {
|
|
|
- this.statusDialogTitle = '关闭投诉'
|
|
|
- this.statusForm = {
|
|
|
- status: 4,
|
|
|
- closeReason: ''
|
|
|
- }
|
|
|
- this.currentIds = [row.id]
|
|
|
- this.statusVisible = true
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 批量状态处理
|
|
|
- */
|
|
|
- handleBatchStatus() {
|
|
|
- if (this.selectionList.length === 0) {
|
|
|
- this.$message.warning('请选择要处理的投诉')
|
|
|
- return
|
|
|
- }
|
|
|
- this.statusDialogTitle = '批量处理投诉'
|
|
|
- this.statusForm = {
|
|
|
- status: 2,
|
|
|
- closeReason: ''
|
|
|
- }
|
|
|
- this.currentIds = this.selectionList.map(item => item.id)
|
|
|
- this.statusVisible = true
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * 确认状态更新
|
|
|
- */
|
|
|
- async confirmStatusUpdate() {
|
|
|
- try {
|
|
|
- await this.$refs.statusForm.validate()
|
|
|
- this.statusLoading = true
|
|
|
-
|
|
|
- let res
|
|
|
- if (this.currentIds.length === 1) {
|
|
|
- res = await updateStatus(this.currentIds[0], this.statusForm.status, this.statusForm.closeReason)
|
|
|
- } else {
|
|
|
- res = await batchUpdateStatus(this.currentIds, this.statusForm.status, this.statusForm.closeReason)
|
|
|
- }
|
|
|
-
|
|
|
- if (res.data.success) {
|
|
|
- this.$message.success('操作成功')
|
|
|
- this.statusVisible = false
|
|
|
- this.onLoad(this.page, this.query)
|
|
|
- } else {
|
|
|
- this.$message.error(res.data.msg || '操作失败')
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- if (error.message) {
|
|
|
- console.error('状态更新失败:', error)
|
|
|
- this.$message.error('操作失败')
|
|
|
- }
|
|
|
- } finally {
|
|
|
- this.statusLoading = false
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ mixins: [complaintMixin],
|
|
|
}
|
|
|
+
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
.complaint-detail {
|
|
|
.detail-item {
|
|
|
margin-bottom: 15px;
|
|
|
-
|
|
|
+
|
|
|
label {
|
|
|
font-weight: bold;
|
|
|
color: #606266;
|
|
|
margin-right: 10px;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
.content-text {
|
|
|
margin-top: 5px;
|
|
|
padding: 10px;
|
|
|
@@ -770,4 +301,4 @@ export default {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-</style>
|
|
|
+</style>
|