Browse Source

refactor(complaint): 将投诉管理逻辑提取到mixin中以提高代码复用性

yz 5 months ago
parent
commit
7aae76fb43
3 changed files with 500 additions and 494 deletions
  1. 4 4
      src/api/complaint/index.js
  2. 475 0
      src/views/complaint/complaintMixin.js
  3. 21 490
      src/views/complaint/index.vue

+ 4 - 4
src/api/complaint/index.js

@@ -99,7 +99,7 @@ import request from '@/router/axios';
  * @param {number} current - 当前页码
  * @param {number} size - 每页大小
  * @param {ComplaintQueryParams} params - 查询参数
- * @returns {Promise<ApiResponse<PageResult<ComplaintRecord>>>} 分页查询结果
+ * @returns {Promise<AxiosResponse<PageResult<ComplaintRecord>>>} 分页查询结果
  */
 export const getList = (current, size, params) => {
   return request({
@@ -116,7 +116,7 @@ export const getList = (current, size, params) => {
 /**
  * 新增投诉
  * @param {ComplaintForm} row - 投诉表单数据
- * @returns {Promise<ApiResponse<null>>} 操作结果
+ * @returns {Promise<AxiosResponse<null>>} 操作结果
  */
 export const add = (row) => {
   return request({
@@ -129,7 +129,7 @@ export const add = (row) => {
 /**
  * 修改投诉
  * @param {ComplaintForm} row - 投诉表单数据
- * @returns {Promise<ApiResponse<null>>} 操作结果
+ * @returns {Promise<AxiosResponse<null>>} 操作结果
  */
 export const update = (row) => {
   return request({
@@ -202,4 +202,4 @@ export const batchUpdateStatus = (ids, status, closeReason) => {
       closeReason
     }
   })
-}
+}

+ 475 - 0
src/views/complaint/complaintMixin.js

@@ -0,0 +1,475 @@
+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] - 关闭原因
+ */
+
+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
+      }
+    }
+  }
+}

+ 21 - 490
src/views/complaint/index.vue

@@ -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>