ZN
12 小时以前 2307a3125c23ad79ee92306603a418085cee194d
src/views/customerService/feedbackRegistration/index.vue
@@ -1,38 +1,127 @@
<template>
   <div class="app-container">
      <div class="search_form">
         <div>
            <span class="search_title">反馈日期:</span>
            <el-date-picker
               v-model="searchForm.feedbackDate"
               value-format="YYYY-MM-DD"
               format="YYYY-MM-DD"
               type="date"
               placeholder="请选择"
               clearable
               @change="handleQuery"
            />
        <span style="margin-left: 10px;" class="search_title">处理状态:</span>
        <el-select v-model="searchForm.status" placeholder="请选择状态" @change="handleQuery" style="width: 140px" clearable>
          <el-option label="待处理" :value="1"></el-option>
          <el-option label="已处理" :value="2"></el-option>
        </el-select>
            <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
            >搜索</el-button
    <div class="workorder-stats">
      <div
          v-for="(item, index) in statsList"
          :key="index"
          class="stat-card"
            >
        <div class="stat-icon" :style="{ backgroundColor: item.bgColor }">
          <el-icon :color="item.color" :size="20">
            <component :is="item.icon" />
          </el-icon>
        </div>
        <div class="stat-info">
          <div class="stat-number">{{ item.count }}</div>
          <div class="stat-label">{{ item.label }}</div>
        </div>
      </div>
    </div>
    <div class="search-wrapper">
      <el-form
          :model="searchForm"
          class="demo-form-inline"
      >
        <el-row :gutter="20">
          <el-col :span="4">
            <el-form-item>
              <el-input
                  v-model="searchForm.afterSalesServiceNo"
                  placeholder="请输入工单编号"
                  clearable
              />
            </el-form-item>
          </el-col>
          <el-col :span="4">
            <el-form-item>
              <el-select
                  v-model="searchForm.status"
                  placeholder="请选择工单状态"
                  clearable
              >
                <el-option
                    v-for="dict in workOrderStatusOptions"
                    :key="dict.value"
                    :label="dict.label"
                    :value="dict.value"
                />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="4">
            <el-form-item>
              <el-select
                  v-model="searchForm.urgency"
                  placeholder="请选择紧急程度"
                  clearable
              >
                <el-option
                    v-for="dict in degreeOfUrgencyOptions"
                    :key="dict.value"
                    :label="dict.label"
                    :value="dict.value"
                />
              </el-select>
            </el-form-item>
          </el-col>
           <el-col :span="4">
            <el-form-item>
              <el-select
                  v-model="searchForm.serviceType"
                  placeholder="请选择售后类型"
                  clearable
              >
                <el-option
                    v-for="dict in classificationOptions"
                    :key="dict.value"
                    :label="dict.label"
                    :value="dict.value"
                />
              </el-select>
            </el-form-item>
          </el-col>
            <el-col :span="4">
              <el-form-item>
                <el-input
                    v-model="searchForm.orderNo"
                    placeholder="请输入销售单号"
                    clearable
                />
              </el-form-item>
            </el-col>
          <!-- 按钮 -->
          <el-col :span="4">
            <el-form-item>
              <el-button type="primary" @click="handleQuery">
                搜索
              </el-button>
              <el-button @click="handleReset">
                重置
              </el-button>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </div>
    <div class="table_list">
      <div class="table_header" style="display: flex; justify-content: space-between; align-items: center;">
        <div>
          <el-button type="primary" @click="openForm('add')">新增售后单</el-button>
         </div>
         <div>
            <el-button type="primary" @click="openForm('add')">新增</el-button>
            <el-button @click="handleOut">导出</el-button>
            <el-button type="danger" plain @click="handleDelete">删除</el-button>
         </div>
      </div>
      <div class="table_list">
         <PIMTable
            rowKey="id"
            :column="tableColumn"
            :tableData="tableData"
            :page="page"
          :height="tableHeight"
            :isSelection="true"
            @selection-change="handleSelectionChange"
            :tableLoading="tableLoading"
@@ -44,69 +133,137 @@
</template>
<script setup>
import {Search} from "@element-plus/icons-vue";
import {onMounted, ref, getCurrentInstance, nextTick} from "vue";
import {onMounted, reactive, ref, toRefs, computed, getCurrentInstance, nextTick} from "vue";
import FormDia from "@/views/customerService/feedbackRegistration/components/formDia.vue";
import {ElMessageBox} from "element-plus";
import {afterSalesServiceDelete, afterSalesServiceListPage} from "@/api/customerService/index.js";
import {afterSalesServiceDelete, afterSalesServiceListPage, getSalesLedgerDetail} from "@/api/customerService/index.js";
import useUserStore from "@/store/modules/user.js";
const { proxy } = getCurrentInstance();
const userStore = useUserStore()
import { Document, FolderOpened, UserFilled } from "@element-plus/icons-vue"
import { markRaw } from 'vue'
const statsList = ref([
  {
    icon: markRaw(Document),
    count: 0,
    label: '全部工单',
    color: '#4080ff',
    bgColor: '#eaf2ff'
  },
  {
    icon: markRaw(FolderOpened),
    count: 0,
    label: '已处理',
    color: '#ff9a2e',
    bgColor: '#fff5e6'
  },
  {
    icon: markRaw(UserFilled),
    count: 0,
    label: '已完成',
    color: '#00b42a',
    bgColor: '#e6f7ed'
  },
])
const data = reactive({
   searchForm: {
      feedbackDate: "",
   },
    customerName: "",
    status: "",
    urgency: "",
    serviceType: "",
    reviewStatus: "",
    orderNo: "",
  }
});
const { searchForm } = toRefs(data);
const tableColumn = ref([
   {
    label: "工单编号",
    prop:"afterSalesServiceNo",
    width: 150,
    align: "center"
  },
  {
    label: "销售单号",
    prop:"salesContractNo",
    width: 150,
    align: "center"
  },
  {
      label: "处理状态",
      prop: "status",
      dataType: "tag",
      formatData: (params) => {
         if (params == 1) {
      if (params === 1) {
            return "待处理";
         } else if (params == 2) {
      } else if (params === 2) {
            return "已处理";
         } else {
            return null;
         }
      },
      formatType: (params) => {
         if (params == 1) {
      if (params === 1) {
            return "danger";
         } else if (params == 2) {
      } else if (params === 2) {
            return "success";
         } else {
            return null;
         }
      },
    align: "center"
   },
   {
      label: "反馈日期",
      prop: "feedbackDate",
      width: 150,
    align: "center"
   },
   {
      label: "登记人",
      prop: "checkNickName",
    align: "center"
   },
   {
      label: "客户名称",
      prop: "customerName",
      width: 200,
    label: "紧急程度",
    prop: "urgency",
    // 根据degreeOfUrgencyOptions字典去自动匹配
    formatData: (params) => {
      if (params) {
        const item = degreeOfUrgencyOptions.value.find(item => item.value === params);
        return item?.label || params;
      }
      return null;
    },
    align: "center"
  },
  {
    label: "售后类型",
    prop: "serviceType",
    // 根据classificationOptions字典去自动匹配
    formatData: (params) => {
      if (params) {
        const item = classificationOptions.value.find(item => item.value === params);
        return item?.label || params;
      }
      return null;
    },
    align: "center"
   },
   {
      label: "问题描述",
      prop: "proDesc",
      width:300
    prop: "disRes",
    width:300,
   },
   {
      label: "关联部门",
      prop: "deptName",
      width: 200,
    align: "center"
   },
   {
      dataType: "action",
@@ -118,6 +275,7 @@
            name: "编辑",
            type: "text",
            clickFun: (row) => {
          console.log(row)
               openForm("edit", row);
            },
            disabled: (row) => {
@@ -125,6 +283,7 @@
            }
         },
      ],
    align: "center"
   },
]);
const tableData = ref([]);
@@ -135,12 +294,36 @@
   total: 0,
});
const selectedRows = ref([]);
const tableHeight = computed(() => "calc(100% -80px)");
const handleReset = () => {
  Object.keys(searchForm.value).forEach(key => {
    searchForm.value[key] = ""
  })
}
// 表格选择数据
const handleSelectionChange = (selection) => {
   selectedRows.value = selection;
};
const formDia = ref()
// 字典获取
/*
post_sale_waiting_list 新增的售后分类
degree_of_urgency 新增的紧急程度
work_order_status 主页的工单状态
review_status 首页的审核状态
*/
const { post_sale_waiting_list, degree_of_urgency, work_order_status, review_status } = proxy.useDict(
  "post_sale_waiting_list",
  "degree_of_urgency",
  "work_order_status",
  "review_status"
);
const classificationOptions = computed(() => post_sale_waiting_list?.value || []);
const degreeOfUrgencyOptions = computed(() => degree_of_urgency?.value || []);
const workOrderStatusOptions = computed(() => work_order_status?.value || []);
// 查询列表
/** 搜索按钮操作 */
@@ -155,6 +338,7 @@
};
const getList = () => {
   tableLoading.value = true;
  getSalesLedgerDetails()
   afterSalesServiceListPage({ ...searchForm.value, ...page }).then((res) => {
      tableLoading.value = false;
      tableData.value = res.data.records;
@@ -169,7 +353,7 @@
   })
};
const handleDelete = () => {
function handleDelete() {
   let ids = [];
   if (selectedRows.value.length > 0) {
      // 检查是否有他人维护的数据
@@ -191,7 +375,7 @@
      .then(() => {
         tableLoading.value = true;
         afterSalesServiceDelete(ids)
            .then((res) => {
            .then(() => {
               proxy.$modal.msgSuccess("删除成功");
               getList();
            })
@@ -219,11 +403,111 @@
      });
};
  // 获取统计数据并刷新顶部卡片
  const getSalesLedgerDetails = () => {
    getSalesLedgerDetail({}).then((res) => {
      if (res.code === 200) {
        statsList.value[0].count = res.data.filter((item) => item.status === 3)[0].count;
        statsList.value[1].count = res.data.filter((item) => item.status === 2)[0].count;
        statsList.value[2].count = res.data.filter((item) => item.status === 1)[0].count;
        // });
      }
    });
  }
onMounted(() => {
   getList();
});
</script>
<style scoped>
<style scoped lang="scss">
.search-wrapper {
  background: white;
  padding: 1rem 1rem 0 1rem;
  border: 8px;
  border-radius: 16px;
}
.expand-btn {
  width: 100%;
  padding: 20px; /* 上下左右各20px,点击这个范围都能触发事件 */
  cursor: pointer; /* 鼠标悬浮显示手型,提升体验 */
  text-align: center;
}
.workorder-stats {
  display: flex;
  gap: 16px;
  padding-bottom:1rem;
  border-radius: 8px;
}
.stat-card {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 20px;
  background-color: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
}
.stat-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 8px;
}
.stat-info {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.stat-number {
  font-size: 24px;
  font-weight: 600;
  color: #303133;
  line-height: 1;
}
.stat-label {
  font-size: 14px;
  color: #909399;
  line-height: 1;
}
.table_header{
  padding-bottom: 10px;
}
.table_list {
  height: calc(100vh - 380px);
  min-height: 360px;
  background: #fff;
  margin-top: 20px;
  display: flex;
  flex-direction: column;
}
:deep(.table_list .pagination-container) {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  margin-top: auto;
  padding: 12px 0 0;
}
:deep(.table_list .el-pagination) {
  flex-wrap: nowrap;
  justify-content: flex-end;
  width: 100%;
}
</style>