Преглед на файлове

Merge branch 'master(jg)'

luofeng преди 1 месец
родител
ревизия
9e8e32639c
променени са 45 файла, в които са добавени 4628 реда и са изтрити 825 реда
  1. 1 1
      .env.development
  2. 8 0
      src/api/sales/index.ts
  3. 32 0
      src/api/statistic/firstPassYieldData.ts
  4. 8 1
      src/api/statistic/index.js
  5. 17 0
      src/api/statistic/reportData.ts
  6. 40 0
      src/api/unqualified/index.ts
  7. 8 0
      src/api/user/index.ts
  8. 50 0
      src/components/CrudTable/configs/tableConfig.ts
  9. 228 0
      src/components/CrudTable/index.vue
  10. 14 9
      src/components/ReportView/reportTemplate.vue
  11. 7 7
      src/components/Search/index.vue
  12. 37 17
      src/hooks/userCrud.ts
  13. 1 1
      src/layout/components/AppMain/index.vue
  14. 2 1
      src/plugins/permission.ts
  15. 0 9
      src/router/modules/analysis.ts
  16. 9 0
      src/router/modules/statistic.ts
  17. 2 0
      src/store/modules/dictionary.ts
  18. 1 0
      src/styles/reset.scss
  19. 20 13
      src/views/login/index.vue
  20. 28 6
      src/views/sales/DetailCom.vue
  21. 72 48
      src/views/sales/add.vue
  22. 30 41
      src/views/sales/handle2.vue
  23. 190 0
      src/views/sales/handle3.vue
  24. 202 0
      src/views/sales/handle4.vue
  25. 77 61
      src/views/sales/handle5.vue
  26. 80 58
      src/views/sales/handle6.vue
  27. 195 0
      src/views/sales/handle7.vue
  28. 25 9
      src/views/sales/index.vue
  29. 95 144
      src/views/statistic/firstPassYield/index.vue
  30. 116 357
      src/views/statistic/report/index.vue
  31. 387 0
      src/views/statistic/report/index2.vue
  32. 404 0
      src/views/statistic/report/toPrintTables.vue
  33. 70 41
      src/views/statistic/statistic/index.vue
  34. 162 0
      src/views/unqualified/DetailCom.vue
  35. 390 0
      src/views/unqualified/add.vue
  36. 39 0
      src/views/unqualified/detail.vue
  37. 266 0
      src/views/unqualified/handle20.vue
  38. 187 0
      src/views/unqualified/handle21.vue
  39. 171 0
      src/views/unqualified/handle3.vue
  40. 172 0
      src/views/unqualified/handle4.vue
  41. 172 0
      src/views/unqualified/handle5.vue
  42. 165 0
      src/views/unqualified/handle6.vue
  43. 168 0
      src/views/unqualified/handle7.vue
  44. 279 0
      src/views/unqualified/index.vue
  45. 1 1
      tsconfig.json

+ 1 - 1
.env.development

@@ -10,7 +10,7 @@ VITE_APP_BASE_API = '/dev-api'
 # 上传文件接口地址
 VITE_APP_UPLOAD_URL = 'http://127.0.0.1:7105'
 # 开发接口地址
- VITE_APP_API_URL = 'http://127.0.0.1:7105'
+ VITE_APP_API_URL = 'http://192.168.1.69:7105'
 
 
 # 是否启用 Mock 服务

+ 8 - 0
src/api/sales/index.ts

@@ -17,6 +17,14 @@ export function getOrderList(data: object) {
   });
 }
 
+export function getCheckList(data: object) {
+  return request({
+    url: "/api/v1/sales/checkCode/list",
+    method: "post",
+    data,
+  });
+}
+
 // 用户列表
 export function getUserList(data: object) {
   return request({

+ 32 - 0
src/api/statistic/firstPassYieldData.ts

@@ -0,0 +1,32 @@
+import request from "@/utils/request";
+import { AxiosPromise } from "axios";
+
+export function getWorkShop(
+    queryParams: object
+): AxiosPromise<PageResult<any[]>> {
+  return request({
+    url: "/api/v1/quality/stat/workShop/list",
+    method: "post",
+    data: queryParams,
+  });
+}
+
+export function getWorkOrderInfo(
+    queryParams: object
+): AxiosPromise<PageResult<any[]>> {
+  return request({
+    url: "/api/v1/quality/stat/workOrderInfoRate/page",
+    method: "post",
+    data: queryParams,
+  });
+}
+
+export function getWorkInfoRate(
+    queryParams: object
+): AxiosPromise<PageResult<any[]>> {
+  return request({
+    url: "/api/v1/quality/stat/infoRate/page",
+    method: "post",
+    data: queryParams,
+  });
+}

+ 8 - 1
src/api/statistic/index.js

@@ -1,4 +1,3 @@
-
 import request from "@/utils/request";
 import axios from "axios";
 
@@ -29,3 +28,11 @@ export function getExport(data) {
     data,
   });
 }
+
+export function createNewReport(data) {
+  return service({
+    url: "/api/v1/quality/stat/export",
+    method: "post",
+    data,
+  });
+}

+ 17 - 0
src/api/statistic/reportData.ts

@@ -0,0 +1,17 @@
+import request from "@/utils/request";
+import { AxiosPromise } from "axios";
+
+/**
+ * 获取登录日志分页
+ * @param queryParams
+ */
+export function getQualityTableData(
+    queryParams: object
+): AxiosPromise<PageResult<any[]>> {
+    return request({
+        url: "/api/v1/quality/report/detail",
+        method: "post",
+        data: queryParams,
+    });
+}
+

+ 40 - 0
src/api/unqualified/index.ts

@@ -0,0 +1,40 @@
+import request from "@/utils/request";
+
+export function getUnqualifiedData(data: object) {
+  return request({
+    url: "/api/v1/unqualified/page",
+    method: "post",
+    data,
+  });
+}
+
+
+// 新增销售反馈表
+
+export function addFeedback(data: object) {
+  return request({
+    url: "/api/v1/unqualified/add",
+    method: "post",
+    data,
+  });
+}
+
+// 删除销售反馈表
+
+export function deleteFeedback(id: number) {
+  return request({
+    url: "/api/v1/unqualified/del",
+    method: "post",
+    data: { id },
+  });
+}
+
+//处理反馈表
+
+export function dealFeedback(data: object) {
+  return request({
+    url: "/api/v1/unqualified/handle",
+    method: "post",
+    data,
+  });
+}

+ 8 - 0
src/api/user/index.ts

@@ -138,3 +138,11 @@ export function importUser(deptId: number, file: File) {
     },
   });
 }
+
+
+export function getUserTree(): AxiosPromise {
+  return request({
+    url: "/api/v1/syn/user/info/tree",
+    method: "get",
+  });
+}

+ 50 - 0
src/components/CrudTable/configs/tableConfig.ts

@@ -0,0 +1,50 @@
+import { useDictionaryStore } from "@/store";
+const { dicts } = useDictionaryStore();
+import dictDataUtil from "@/common/configs/dictDataUtil";
+export const tableConfig = {
+
+  WORK_ORDER: {
+    url: "/api/v1/quality/stat/workOrderInfo",
+    column: [
+      {
+        label: "批次",
+        prop: "workOrderCode",
+        width: 120,
+        search: true,
+      },
+      {
+        label: "产品编号",
+        prop: "materialCode",
+        width: 120,
+        search: true,
+      },
+      {
+        label: "产品名称",
+        prop: "materialName",
+        search: true,
+      },
+      {
+        label: "产品型号",
+        prop: "materialModel",
+        width: 120,
+        search: true,
+      },
+      {
+        label: "产线名称",
+        prop: "workshopName",
+      },
+
+      {
+        label: "创建时间",
+        prop: "created",
+        width: 120,
+      },
+
+    ],
+  },
+
+
+
+
+
+};

+ 228 - 0
src/components/CrudTable/index.vue

@@ -0,0 +1,228 @@
+<template>
+  <el-dialog
+    v-model="isShowTable"
+    :title="tableTitle"
+    width="900"
+    :before-close="handleClose"
+    :append-to-body="true"
+  >
+    <avue-crud
+      ref="crudRef"
+      v-model:search="search"
+      v-model="form"
+      :data="data"
+      :option="option"
+      v-model:page="page"
+      @row-click="rowClick"
+      @row-save="createRow"
+      @row-update="updateRow"
+      @row-del="deleteRow"
+      @search-change="searchChange"
+      @search-reset="resetChange"
+      @size-change="dataList"
+      @current-change="dataList"
+      @selection-change="selectionChange"
+    />
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="handleClose">取消</el-button>
+        <el-button type="primary" @click="onSelected"> 确定 </el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+<script setup>
+import { ref, getCurrentInstance } from "vue";
+import { useCrud } from "@/hooks/userCrud";
+import { tableConfig } from "./configs/tableConfig";
+
+const props = defineProps({
+  tableTitle: {
+    default: "",
+    type: String,
+  },
+  tableType: {
+    default: "",
+    type: String,
+  },
+  multiple: {
+    default: false,
+    type: Boolean,
+  },
+  // 用于多选的返回值
+  multipleKey: {
+    default: "id",
+    type: String,
+  },
+  multipleRow: {
+    default: false,
+    type: Boolean,
+  },
+});
+
+const isShowTable = ref(false);
+const startSelect = async (param) => {
+  if (param) {
+    commonConfig.value.params = param;
+  }
+  dataList();
+  isShowTable.value = true;
+};
+
+/**
+ * propName 要跟字典配置的key一致
+ * dictData 字典数据, 注意props的value和label
+ * */
+const refreshDictData = (propName, dictData, keyName = "value") => {
+  nextTick(() => {
+    if (dictData && dictData.length > 0 && crudRef.value) {
+      crudRef.value.updateDic(propName, dictData);
+      search.value[propName] = dictData[0][keyName];
+    }
+  });
+};
+
+/**
+ * op 对象的字段要跟option实际字段一直 才能进行合并操作
+ */
+const mergeOption = (op) => {
+  for (const key of Object.keys(op)) {
+    option.value[key] = op[key];
+  }
+};
+
+// 传入一个url,后面不带/
+const {
+  url,
+  form,
+  data,
+  option,
+  search,
+  page,
+  toDeleteIds,
+  selectedRows,
+  Methords,
+  Utils,
+  commonConfig,
+} = useCrud({
+  src: tableConfig[props.tableType].url,
+  multipleSelectKey: props.multipleKey,
+});
+const { dataList, createRow, updateRow, deleteRow, searchChange, resetChange } =
+  Methords; //增删改查
+const { selectionChange, multipleDelete } = Methords; //选中和批量删除事件
+
+const crudRef = ref(null); //crudRef.value 获取avue-crud对象
+
+const commonTableEmits = defineEmits(["selectedSure", "selectMultipleSure"]);
+
+const calculateColumnWidth = (column) => {
+  if (!column.label) {
+    return column.minWidth;
+  }
+  // 字宽度
+  const fontSize = 17;
+  let width = fontSize * (column.label.length + 2);
+  // 如果开启过滤
+  if (column.filters) {
+    width += 12;
+  }
+  // 如果开启排序
+  if (column.sortable) {
+    width += 24;
+  }
+  return width;
+};
+
+onMounted(() => {
+  url.value = tableConfig[props.tableType].url;
+  option.value = Object.assign(option.value, {
+    searchEnter: true,
+    menu: false,
+    highlightCurrentRow: true,
+    selection: props.multiple,
+    addBtn: false,
+    height: "500",
+    overHidden: true,
+    indexWidth: "120px",
+    searchLabelWidth: "120px",
+    column: tableConfig[props.tableType].column,
+  });
+  // 列处理
+  if (option.value.column) {
+    for (let col of option.value.column) {
+      col.minWidth = calculateColumnWidth(col);
+    }
+  }
+  // dataList();
+});
+watch(
+  () => props.tableType,
+  () => {
+    url.value = tableConfig[props.tableType].url;
+    option.value = Object.assign(option.value, {
+      searchEnter: true,
+      menu: false,
+      highlightCurrentRow: true,
+      selection: props.multiple,
+      addBtn: false,
+      height: "500",
+      overHidden: true,
+      searchLabelWidth: "120px",
+      column: tableConfig[props.tableType].column,
+    });
+    // 列处理
+    if (option.value.column) {
+      for (let col of option.value.column) {
+        col.minWidth = calculateColumnWidth(col);
+      }
+    }
+    //dataList();
+  }
+);
+
+const selectRowValue = ref({});
+const rowClick = (row) => {
+  selectRowValue.value = row;
+};
+
+const handleClose = () => {
+  // 在这里可以清空打开的commonTable的搜索条件
+  search.value.bomMaterialCode = "";
+
+  crudRef.value.clearSelection();
+  toDeleteIds.value = [];
+  selectedRows.value = [];
+  selectRowValue.value = {};
+  isShowTable.value = false;
+
+  console.log(
+    "关闭弹窗",
+    toDeleteIds.value,
+    selectedRows.value,
+    selectRowValue.value
+  );
+};
+
+const onSelected = () => {
+  if (props.multiple) {
+    if (toDeleteIds.value.length < 1) {
+      ElMessage.warning("未选择任何数据");
+      return;
+    }
+    commonTableEmits("selectMultipleSure", toDeleteIds.value);
+  } else {
+    if (props.multipleRow) {
+      console.log(selectedRows);
+      commonTableEmits("selectedSure", selectedRows.value);
+    } else {
+      commonTableEmits("selectedSure", selectRowValue.value);
+    }
+  }
+
+  handleClose();
+};
+
+defineExpose({ startSelect, refreshDictData, mergeOption });
+</script>

+ 14 - 9
src/components/ReportView/reportTemplate.vue

@@ -1,4 +1,5 @@
 <template>
+  <div class="main-content">
   <div class="bgColor" v-if="modelValue" @click.stop="close">
     <div class="body">
       <div class="header">
@@ -20,13 +21,10 @@
           <div id="print">
             <div class="tableInfo">
               <div style="page-break-after: always">
-                <div class="title" style="text-align: center">质量日报</div>
+                <div class="title" style="text-align: center" v-if="props.detail.reportType==1">质量日报({{props.detail.generationDate}})</div>
+                <div class="title" style="text-align: center" v-if="props.detail.reportType==2">质量月报({{props.detail.generationDate}})</div>
+
                 <div class="tableTitle">模块筛选情况</div>
-                <div class="info">
-                  <div class="text">产品型号:</div>
-                  <div class="text">产品批次:</div>
-                  <div class="text">报告日期:2025年03月23日</div>
-                </div>
                 <table>
                   <thead>
                     <tr>
@@ -164,6 +162,7 @@
       </div>
     </div>
   </div>
+  </div>
 </template>
 
 <script setup>
@@ -172,14 +171,20 @@ import {
   consistencyTestData,
   productAcceptanceData,
 } from "@/api/statistic/reportMockData.ts";
+onMounted(async () => {
+  await getQualityTableData(props.detail.value);
 
+});
+const getQualityTableData=(data)=>{
+
+}
 const props = defineProps({
   modelValue: {
     type: [Boolean],
   },
-  // tablesData: {
-  //   type: [Object],
-  // },
+  detail: {
+    type: [Object],
+   },
 });
 const emits = defineEmits(["update:modelValue"]);
 const close = () => {

+ 7 - 7
src/components/Search/index.vue

@@ -8,7 +8,7 @@
             class="tep"
             v-model="searchForm[option.prop]"
             placeholder="Please input"
-            size="small"
+            clearable
           />
         </div>
         <div class="item" v-if="option.type == 'select'">
@@ -17,7 +17,7 @@
           <el-select
             class="tep"
             v-model="searchForm[option.prop]"
-            size="small"
+            clearable
             placeholder="Select"
           >
             <el-option
@@ -37,7 +37,6 @@
             range-separator="-"
             start-placeholder="开始日期"
             end-placeholder="结束日期"
-            size="small"
             value-format="YYYY-MM-DD"
             format="YYYY-MM-DD"
           />
@@ -45,10 +44,8 @@
       </template>
     </div>
     <div class="oprea">
-      <el-button type="primary" size="small" class="btn" @click="getData"
-        >查询</el-button
-      >
-      <el-button class="btn" size="small" @click="reset">重置</el-button>
+      <el-button type="primary" class="btn" @click="getData">查询</el-button>
+      <el-button class="btn" @click="reset">重置</el-button>
     </div>
   </div>
 </template>
@@ -106,6 +103,9 @@ defineExpose({ searchForm });
   .oprea {
     width: 240px;
     height: 100%;
+    display: flex;
+    justify-content: center; /* 水平居中 */
+    align-items: center;
   }
 }
 </style>

+ 37 - 17
src/hooks/userCrud.ts

@@ -11,6 +11,10 @@ interface UseCrudConfig {
 
   dataListUrl?: string;
 
+  afterDataList?: Function;
+
+  afterAdd?: Function;
+
   // 需要操作的数据
   row?: any;
   // done用于结束操作
@@ -23,6 +27,8 @@ interface UseCrudConfig {
   params?: object;
   // 是否是编辑,如果是编辑调用更新,否则调用新增
   isEdit?: boolean;
+  //   用于多选选中后添加进入,toDeleteIds中的key值。
+  multipleSelectKey?: string;
 }
 
 export const useCrud = (config?: UseCrudConfig) => {
@@ -54,9 +60,10 @@ export const useCrud = (config?: UseCrudConfig) => {
   });
   /** 配置项结构 v-model */
   // defaults ?: AvueCrudDefaults;
-
+  // 多选返回的数组,命名是因为后来增加了很多功能,现在这个数组里面的值是根据multipleSelectKey来决定
   const toDeleteIds = ref<Array<string>>([]);
-
+  // 多选返回的数组,返回每一行的row数据
+  const selectedRows = ref<any[]>([]);
   const save = async (config?: UseCrudConfig) => {
     try {
       const path = config?.isEdit ? "/update" : "/add";
@@ -70,6 +77,9 @@ export const useCrud = (config?: UseCrudConfig) => {
         Methords.dataList();
         config?.done && config?.done();
         ElMessage.success(res?.msg ?? "");
+        if (commonConfig.value?.afterAdd) {
+          commonConfig.value?.afterAdd(res?.data);
+        }
       } else {
         config?.loading && config?.loading();
         ElMessage.error(res?.msg ?? "");
@@ -102,13 +112,13 @@ export const useCrud = (config?: UseCrudConfig) => {
       handleSearchData();
       try {
         const res = await request({
-          url: commonConfig.value.dataListUrl ?? `${url.value}/page`,
+          url: commonConfig.value?.dataListUrl ?? `${url.value}/page`,
           method: "post",
           data: {
             pageNo: page.value.currentPage,
             pageSize: page.value.pageSize,
-            ...search.value,
             ...(commonConfig.value?.params ?? {}),
+            ...search.value,
           },
         });
         if (res?.data) {
@@ -119,6 +129,9 @@ export const useCrud = (config?: UseCrudConfig) => {
             data.value = res?.data?.records || [];
             page.value.total = res?.data?.totalCount || 0;
           }
+          if (commonConfig.value?.afterDataList) {
+            commonConfig.value?.afterDataList();
+          }
         }
         config?.done && config?.done();
       } catch (err) {
@@ -141,22 +154,25 @@ export const useCrud = (config?: UseCrudConfig) => {
           },
         });
         if (res?.data) {
-          if(res?.data instanceof Array){
-            data.value = res?.data || []
-            page.value.total = res?.data?.length || 0
-          }else{
+          if (res?.data instanceof Array) {
+            data.value = res?.data || [];
+            page.value.total = res?.data?.length || 0;
+          } else {
             data.value = res?.data?.records || [];
             for (let i = 0; i < data.value.length; i++) {
               data.value[i].$cellEdit = true;
-              if(data.value[i].children!=undefined&&data.value[i].children!=null&&data.value[i].children.length > 0 ){
-                for(let j=0;j < data.value[i].children.length; j++){
+              if (
+                data.value[i].children != undefined &&
+                data.value[i].children != null &&
+                data.value[i].children.length > 0
+              ) {
+                for (let j = 0; j < data.value[i].children.length; j++) {
                   data.value[i].children[j].$cellEdit = true;
                 }
               }
             }
             page.value.total = res?.data?.totalCount || 0;
           }
-
         }
         config?.done && config?.done();
       } catch (err) {
@@ -211,9 +227,9 @@ export const useCrud = (config?: UseCrudConfig) => {
         cancelButtonText: "取消",
         type: "warning",
       }).then(async () => {
-        if(row.children && row.children.length > 0 ){
-          ElMessage.error("请先解绑下级关系")
-          return
+        if (row.children && row.children.length > 0) {
+          ElMessage.error("请先解绑下级关系");
+          return;
         }
         try {
           const res = await request({
@@ -234,8 +250,12 @@ export const useCrud = (config?: UseCrudConfig) => {
     // 设置selection: true,后监听选中改变事件,将Id存入数组
     selectionChange: (rows?: any[]) => {
       toDeleteIds.value = [];
+      selectedRows.value = [];
       rows?.forEach((element) => {
-        toDeleteIds.value.push(element.id);
+        toDeleteIds.value.push(
+          element[commonConfig.value?.multipleSelectKey ?? "id"]
+        );
+        selectedRows.value.push(element);
       });
     },
 
@@ -364,13 +384,12 @@ export const useCrud = (config?: UseCrudConfig) => {
     /**
      * 根据搜索项导出数据
      */
-    exportData: async (urlStr: string, filePath: string) => {
+    exportData: async (urlStr: string) => {
       handleSearchData();
       const response = await request({
         url: urlStr,
         method: "post",
         data: search.value,
-        params: { filePath: filePath },
         responseType: "arraybuffer",
       });
       Utils.downloadFile(response);
@@ -387,6 +406,7 @@ export const useCrud = (config?: UseCrudConfig) => {
     toDeleteIds,
     Methords,
     Utils,
+    selectedRows,
     commonConfig,
   };
 };

+ 1 - 1
src/layout/components/AppMain/index.vue

@@ -29,7 +29,7 @@ const cachedViews = computed(() => useTagsViewStore().cachedViews); // 缓存页
   position: relative;
   width: 100%;
   min-height: calc(100vh - $navbar-height);
-  overflow: hidden;
+  overflow: auto;
   background-color: var(--el-bg-color-page);
 }
 

+ 2 - 1
src/plugins/permission.ts

@@ -9,12 +9,13 @@ import { getUserDicts } from "@/api/auth";
 export function setupPermission() {
   // 白名单路由
   const whiteList = [""];
-
+  const userStore = useUserStore();
   router.beforeEach(async (to, from, next) => {
     NProgress.start();
     isNewVersion();
     const hasToken = localStorage.getItem("token");
     if (hasToken) {
+      await userStore.getUserInfo();
       if (to.path === "/login") {
         // 如果已登录,跳转首页
         next({ path: "/" });

+ 0 - 9
src/router/modules/analysis.ts

@@ -57,14 +57,5 @@ export default {
         },
       ],
     },
-    // {
-    //   path: "charts",
-    //   component: () => import("@/views/charts/index.vue"),
-    //   name: "Charts",
-    //   meta: {
-    //     title: "图表分析",
-    //     icon: "Guide",
-    //   },
-    // },
   ],
 };

+ 9 - 0
src/router/modules/statistic.ts

@@ -46,5 +46,14 @@ export default {
         icon: "Guide",
       },
     },
+    {
+      path: "unqualified",
+      component: () => import("@/views/unqualified/index.vue"),
+      name: "Unqualified",
+      meta: {
+        title: "不合格处置",
+        icon: "Guide",
+      },
+    },
   ],
 };

+ 2 - 0
src/store/modules/dictionary.ts

@@ -32,6 +32,8 @@ export const useDictionaryStore = defineStore("dictionaryStore", () => {
     "excel_type",
     "excel_states",
     "spc_operation",
+    "sales_info_type",
+    "unqualified_audit_type",
     "spc_control_chart",
   ];
   const dicts = ref<{ [key: string]: any[] }>({});

+ 1 - 0
src/styles/reset.scss

@@ -19,6 +19,7 @@ html {
   line-height: 1.5;
   tab-size: 4;
   text-size-adjust: 100%;
+  min-width: 1300px;
 }
 
 body {

+ 20 - 13
src/views/login/index.vue

@@ -115,7 +115,7 @@ import { getCaptchaApi, getOrgListApi } from "@/api/auth";
 import { LoginData } from "@/api/auth/types";
 import { Sunny, Moon } from "@element-plus/icons-vue";
 import { LocationQuery, LocationQueryValue, useRoute } from "vue-router";
-import router from "@/router";
+
 import defaultSettings from "@/settings";
 import { ThemeEnum } from "@/enums/ThemeEnum";
 import { usePermissionStore } from "@/store/modules/permission";
@@ -194,15 +194,16 @@ function getOrgList() {
  * 登录
  */
 const route = useRoute();
+const router = useRouter();
 function handleLogin() {
   loginFormRef.value.validate((valid: boolean) => {
     if (valid) {
       loading.value = true;
       userStore
         .login(loginData.value)
-        .then(async () => {
-          const query: LocationQuery = route.query;
-          const redirect = (query.redirect as LocationQueryValue) ?? "/";
+        .then(async (res) => {
+          const query: LocationQuery = route?.query;
+          const redirect = (query?.redirect as LocationQueryValue) ?? "/";
           const otherQueryParams = Object.keys(query).reduce(
             (acc: any, cur: string) => {
               if (cur !== "redirect") {
@@ -212,12 +213,15 @@ function handleLogin() {
             },
             {}
           );
-          router.push({ path: redirect, query: otherQueryParams });
-        })
-        .catch(() => {
-          // getCaptcha();
-          console.log("catch");
+          router.push({
+            path: redirect,
+            query: { ...otherQueryParams, date: new Date() },
+          });
         })
+        // .catch(() => {
+        //   // getCaptcha();
+        //   console.log("catch");
+        // })
         .finally(() => {
           loading.value = false;
         });
@@ -230,8 +234,8 @@ const toLogin = () => {
   userStore
     .login(loginData.value)
     .then(async () => {
-      const query: LocationQuery = route.query;
-      const redirect = (query.redirect as LocationQueryValue) ?? "/";
+      const query: LocationQuery = route?.query;
+      const redirect = (query?.redirect as LocationQueryValue) ?? "/";
       const otherQueryParams = Object.keys(query).reduce(
         (acc: any, cur: string) => {
           if (cur !== "redirect") {
@@ -241,7 +245,10 @@ const toLogin = () => {
         },
         {}
       );
-      router.push({ path: redirect, query: otherQueryParams });
+      router.push({
+        path: redirect,
+        query: { ...otherQueryParams, date: new Date() },
+      });
     })
     .catch(() => {
       // getCaptcha();
@@ -275,7 +282,7 @@ watchEffect?.(() => {
  * 检查输入大小写
  */
 function checkCapslock(e: any) {
-  isCapslock.value = e.getModifierState("CapsLock");
+  //isCapslock.value = e.getModifierState("CapsLock");
 }
 
 onMounted?.(() => {

+ 28 - 6
src/views/sales/DetailCom.vue

@@ -2,21 +2,34 @@
   <div>
     <div class="sale-header">销售信息反馈表</div>
     <table border-collapse="collapse">
-      <thead>
         <tr>
           <th>顾客名称</th>
           <th>详细地址</th>
           <th>联系人</th>
           <th>联系电话</th>
         </tr>
-      </thead>
-      <tbody>
         <tr>
           <td>{{ saleModel.customer }}</td>
           <td>{{ saleModel.address }}</td>
           <td>{{ saleModel.contacts }}</td>
           <td>{{ saleModel.phoneNo }}</td>
         </tr>
+        <tr>
+          <th>产品型号</th>
+          <th>产品分类</th>
+          <th>检验批号</th>
+          <th>数量</th>
+        </tr>
+        <tr>
+          <td>{{ saleModel.materialModel }}</td>
+          <td>{{ saleModel.type }}</td>
+          <td>{{ saleModel.checkCode }}</td>
+          <td>{{ saleModel.num }}</td>
+        </tr>
+      <tr>
+        <th>产品编号</th>
+        <th colspan="3" style="font-weight: normal;">{{ saleModel.seqs }}</th>
+      </tr>
         <tr v-for="(item, index) in contentArray" :key="index">
           <td colspan="4">
             <div class="sale-box">
@@ -25,13 +38,18 @@
                 {{ item.content }}
               </div>
               <div class="sale-bottom">
-                <div class="desc">处理人:{{ item[`user${index + 1}`] }}</div>
+                <div class="desc" v-if="index === 0">市场营销部:{{ item[`user`] }}</div>
+                <div class="desc" v-if="index === 1">质量管理部:{{ item[`user`] }}</div>
+                <div class="desc" v-if="index === 2">责任部门:{{ item[`user`] }}</div>
+                <div class="desc" v-if="index === 3">责任部门:{{ item[`user`] }}</div>
+                <div class="desc" v-if="index === 4">质量管理部:{{ item[`user`] }}</div>
+                <div class="desc" v-if="index === 5">质量管理部:{{ item[`user`] }}</div>
+                <div class="desc" v-if="index === 6">市场营销部:{{ item[`user`] }}</div>
                 <div class="desc">时间: {{ item.time }}</div>
               </div>
             </div>
           </td>
         </tr>
-      </tbody>
     </table>
   </div>
 </template>
@@ -69,6 +87,10 @@ const refreshView = (row) => {
     let remark6 = JSON.parse(row.remark6);
     contentArray.value.push({ ...remark6, title: "处置情况反馈意见" });
   }
+  if (row.remark7 && JSON.parse(row.remark7).content) {
+    let remark7 = JSON.parse(row.remark7);
+    contentArray.value.push({ ...remark7, title: "处置情况反馈意见" });
+  }
 };
 
 defineExpose({ refreshView });
@@ -78,7 +100,7 @@ defineExpose({ refreshView });
 .sale-header {
   text-align: center;
   font-size: 20px;
-  font-weight: bold;
+  //font-weight: bold;
   margin-bottom: 10px;
 }
 table {

+ 72 - 48
src/views/sales/add.vue

@@ -25,29 +25,29 @@
           <el-form-item label="联系电话" prop="phoneNo">
             <el-input v-model="saleForm.phoneNo" />
           </el-form-item>
-          <el-form-item label="阶段" prop="stage">
+<!--          <el-form-item label="阶段" prop="stage">
             <el-input v-model="saleForm.stage" />
-          </el-form-item>
-          <el-form-item label="订单信息">
+          </el-form-item>-->
+          <el-form-item label="检验批号">
             <el-select
-              v-model="selectOrderCode"
-              value-key="orderNo"
-              placeholder="请选择订单信息"
+              v-model="selectCheckCode"
+              value-key="checkCode"
+              placeholder="请选择检验批号"
               style="width: 100%"
               @change="orderSelect"
             >
               <el-option
                 v-for="item in orders"
-                :key="item.orderNo"
-                :label="item.orderName + `(批号: ${item.workOrderCode})`"
+                :key="item.checkCode"
+                :label="item.checkCode"
                 :value="item"
               />
             </el-select>
           </el-form-item>
 
-          <el-form-item label="检验批号">
+<!--          <el-form-item label="检验批号">
             <div>{{ selectedOrder.workOrderCode }}</div>
-          </el-form-item>
+          </el-form-item>-->
 
           <el-form-item label="流转卡号" prop="seqs">
             <el-select
@@ -55,13 +55,29 @@
               value-key="orderCode"
               placeholder="请选择流转卡号"
               style="width: 100%"
+              filterable
               multiple
             >
               <el-option
                 v-for="item in seqList"
-                :key="item"
-                :label="item"
-                :value="item"
+                :key="item.label"
+                :label="item.label"
+                :value="item.label"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="产品分类" prop="seqs">
+            <el-select
+                v-model="saleForm.type"
+                value-key="value"
+                placeholder="请选择产品分类"
+                style="width: 100%"
+            >
+              <el-option
+                  v-for="item in typeList"
+                  :key="item.dictValue"
+                  :label="item.dictLabel"
+                  :value="item.dictValue"
               />
             </el-select>
           </el-form-item>
@@ -78,7 +94,7 @@
             <el-input v-model="remark1.content" type="textarea" />
           </el-form-item>
           <el-form-item label="填表人" prop="user">
-            <el-select
+<!--            <el-select
               v-model="remark1.user"
               placeholder="请选择"
               style="width: 100%"
@@ -89,12 +105,18 @@
                 :label="item.userName"
                 :value="item.userName"
               />
-            </el-select>
+            </el-select>-->
+            <el-tree-select
+                v-model="remark1.user"
+                :data="userList"
+                filterable
+            />
           </el-form-item>
           <el-form-item label="日期" prop="time">
             <el-date-picker
               v-model="remark1.time"
               type="date"
+              :disabled-date="disabledDate"
               placeholder="请选择日期"
               clearable
               format="YYYY年MM月DD日"
@@ -103,18 +125,11 @@
             />
           </el-form-item>
           <el-form-item label="下一步处理人" prop="nextRemarkUser">
-            <el-select
-              v-model="remark1.nextRemarkUser"
-              placeholder="请选择处理人"
-              style="width: 100%"
-            >
-              <el-option
-                v-for="item in userList"
-                :key="item.userName"
-                :label="item.userName"
-                :value="item.userName"
-              />
-            </el-select>
+            <el-tree-select
+                v-model="remark1.nextRemarkUser"
+                :data="userList"
+                filterable
+            />
           </el-form-item>
         </el-form>
       </template>
@@ -129,10 +144,17 @@
 </template>
 
 <script setup>
-import { addFeedback, getOrderList, getUserList } from "@/api/sales/index";
-
+import {addFeedback, getCheckList, getOrderList, getUserList} from "@/api/sales/index";
+import { getUserTree } from "@/api/user/index";
+import { useDictionaryStore } from "@/store";
 const drawerVisible = ref(false);
-
+const disabledDate = (time)=> {
+  //选择今天以及今天之后的日期
+ // return time.getTime() < Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择
+  //选择今天以及今天之前的日期
+  return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择今天的
+}
+const { dicts } = useDictionaryStore();
 const baseInfoRef = ref(null);
 const saleForm = reactive({
   customer: "",
@@ -189,22 +211,21 @@ const rules1 = {
 
 // 订单相关信息
 const orders = ref([]);
-const selectedOrder = ref({});
-const selectOrderCode = ref("");
+const typeList = dicts.sales_info_type
+const selectedCheckCode = ref({});
+const selectCheckCode = ref("");
 const getOrders = async () => {
-  const res = await getOrderList({
-    pageNo: 0,
-    pageSize: 200,
+  const res = await getCheckList({
   });
-  orders.value = res.data.records;
+  orders.value = res.data;
   if (orders.value.length > 0) {
-    // selectOrderCode.value = orders.value[0].orderCode;
+    // selectCheckCode.value = orders.value[0].orderCode;
     // selectedOrder.value = orders.value[0];
   }
 };
 const orderSelect = (value) => {
-  selectedOrder.value = value;
-  seqList.value = selectedOrder.value.seqs;
+  selectedCheckCode.value = value;
+  seqList.value = selectedCheckCode.value.seqs.map((item, index) => ({ value: item, label: item }));
   saleForm.seqs = [];
 };
 
@@ -214,16 +235,19 @@ const seqList = ref([]);
 const userInfo = ref({});
 const userList = ref([]);
 const getUserInfo = async () => {
-  const res = await getUserList();
-  userList.value = res.data;
+  //const res = await getUserList();
+  //userList.value = res.data;
   // if (userList.value.length > 0) {
   //   userInfo.value = userList.value[0];
   // }
+  getUserTree().then((data) => {
+    userList.value = data.data;
+  });
 };
 
 const showDrawer = () => {
-  selectedOrder.value = {};
-  selectOrderCode.value = {};
+  selectedCheckCode.value = {};
+  selectCheckCode.value = {};
   getOrders();
   getUserInfo();
   drawerVisible.value = true;
@@ -235,7 +259,7 @@ const cancelClick = () => {
   drawerVisible.value = false;
   baseInfoRef.value.resetFields();
   remark1Ref.value.resetFields();
-  selectedOrder.value = {};
+  selectedCheckCode.value = {};
 };
 
 const feedBackEmit = defineEmits(["finish"]);
@@ -243,7 +267,6 @@ const feedBackEmit = defineEmits(["finish"]);
 const confirmClick = () => {
   console.log(saleForm);
   console.log(remark1);
-  console.log(selectedOrder.value);
 
   // drawerVisible.value = false;
 
@@ -261,7 +284,7 @@ const confirmClick = () => {
     if (valid) {
       let remark1Copy = {
         content: remark1.content,
-        user1: remark1.user,
+        user: remark1.user,
         time: remark1.time,
       };
       let remark2 = {
@@ -272,12 +295,13 @@ const confirmClick = () => {
 
       let p = {
         ...saleForm,
-        ...selectedOrder.value,
+        ...selectedCheckCode.value,
+        currentUserName: remark1.nextRemarkUser,
         remark1: JSON.stringify(remark1Copy),
         remark2: JSON.stringify(remark2),
       };
 
-      p.seqs = p.seqs.join(",");
+      p.seqs = saleForm.seqs.join(",");
 
       addFeedback(p).then(() => {
         feedBackEmit("finish");

+ 30 - 41
src/views/sales/handle2.vue

@@ -18,44 +18,24 @@
           :autosize="{ minRows: 3, maxRows: 6 }"
         />
       </el-form-item>
-      <el-form-item label="填表人" prop="user">
-        <el-select
-          v-model="remark.user"
-          placeholder="请选择"
-          style="width: 100%"
-        >
-          <el-option
-            v-for="item in userList"
-            :key="item.userName"
-            :label="item.userName"
-            :value="item.userName"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="日期" prop="time">
+<!--      <el-form-item label="日期" prop="time">
         <el-date-picker
           v-model="remark.time"
           type="date"
+          :disabled-date="disabledDate"
           placeholder="请选择日期"
           clearable
           format="YYYY年MM月DD日"
           value-format="YYYY年MM月DD日"
           style="width: 100%"
         />
-      </el-form-item>
-      <el-form-item label="下一步处理人" prop="nextRemarkUser">
-        <el-select
-          v-model="remark.nextRemarkUser"
-          placeholder="请选择处理人"
-          style="width: 100%"
-        >
-          <el-option
-            v-for="item in userList"
-            :key="item.userName"
-            :label="item.userName"
-            :value="item.userName"
-          />
-        </el-select>
+      </el-form-item>-->
+      <el-form-item label="下一步处理人" prop="nextRemarkUser" v-if="remark.state == 0">
+        <el-tree-select
+            v-model="remark.nextRemarkUser"
+            :data="userList"
+            filterable
+        />
       </el-form-item>
       <el-form-item label="是否通过" prop="state">
         <el-radio-group v-model="remark.state">
@@ -77,11 +57,12 @@
 <script setup>
 import DetailCom from "@/views/sales/DetailCom.vue";
 import { dealFeedback, getUserList } from "@/api/sales/index";
-
+import { getUserTree } from "@/api/user/index";
+import {useUserStore} from "@/store";
 const drawerVisible = ref(false);
 const detailComRef = ref(null);
 const saleModel = ref({});
-
+const userStore = useUserStore();
 const showDrawer = (row) => {
   drawerVisible.value = true;
   saleModel.value = row;
@@ -92,7 +73,12 @@ const showDrawer = (row) => {
 
   getUserInfo();
 };
-
+const disabledDate = (time)=> {
+  //选择今天以及今天之后的日期
+  return time.getTime() < Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择
+  //选择今天以及今天之前的日期
+  //return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择今天的
+}
 const rules1 = {
   content: [
     { required: true, message: "请输入投诉或建议处置意见", trigger: "blur" },
@@ -118,7 +104,7 @@ const remark = reactive({
   user: "",
   time: "",
   nextRemarkUser: "",
-  state: 1,
+  state: 0,
 });
 
 const cancelClick = () => {
@@ -133,31 +119,34 @@ const feedBackEmit = defineEmits(["finish"]);
 const userInfo = ref({});
 const userList = ref([]);
 const getUserInfo = async () => {
-  const res = await getUserList();
-  userList.value = res.data;
-  // if (userList.value.length > 0) {
-  //   userInfo.value = userList.value[0];
-  // }
+  getUserTree().then((data) => {
+    userList.value = data.data;
+  });
 };
 
 const confirmClick = () => {
+  const date = new Date();
+  const now = date.getFullYear() + "年" + date.getMonth() + "月" + date.getDate() + "日"
+  remark.user = userStore.user.username;
   remarkRef.value.validate((valid) => {
     if (valid) {
       let remark2Copy = {
         content: remark.content,
-        user2: remark.user,
-        time: remark.time,
+        user: remark.user,
+        time: now,
         state: remark.state,
       };
       let remark3 = {
         content: "",
-        user3: remark.nextRemarkUser, // qinhaibo和dengyu说是user1234的
+        user: remark.nextRemarkUser, // qinhaibo和dengyu说是user1234的
         time: "",
       };
 
       let p = {
         id: saleModel.value.id,
+        currentUserName: remark.nextRemarkUser,
         remark2: JSON.stringify(remark2Copy),
+        state: remark.state,
         remark3: JSON.stringify(remark3),
         step: 1, //步骤 1 投书或建议处置意见 2 整改及纠正措施验证 3 处置情况的反馈意见
       };

+ 190 - 0
src/views/sales/handle3.vue

@@ -0,0 +1,190 @@
+<template>
+  <el-drawer v-model="drawerVisible" size="1000">
+    <div>
+      <DetailCom ref="detailComRef"></DetailCom>
+    </div>
+
+    <el-form
+      ref="remarkRef"
+      :model="remark"
+      label-width="150"
+      :rules="rules1"
+      style="max-width: 600px; margin-left: 80px; margin-top: 20px"
+    >
+      <el-form-item label="原因分析" prop="content">
+        <el-input
+          v-model="remark.content"
+          type="textarea"
+          :autosize="{ minRows: 3, maxRows: 6 }"
+        />
+      </el-form-item>
+<!--      <el-form-item label="填表人" prop="user">
+        <el-select
+          v-model="remark.user"
+          placeholder="请选择"
+          style="width: 100%"
+        >
+          <el-option
+            v-for="item in userList"
+            :key="item.userName"
+            :label="item.userName"
+            :value="item.userName"
+          />
+        </el-select>
+      </el-form-item>-->
+<!--      <el-form-item label="日期" prop="time">
+        <el-date-picker
+          v-model="remark.time"
+          type="date"
+          :disabled-date="disabledDate"
+          placeholder="请选择日期"
+          clearable
+          format="YYYY年MM月DD日"
+          value-format="YYYY年MM月DD日"
+          style="width: 100%"
+        />
+      </el-form-item>-->
+      <el-form-item label="下一步处理人" prop="nextRemarkUser" v-if="remark.state == 0">
+        <el-tree-select
+            v-model="remark.nextRemarkUser"
+            :data="userList"
+            filterable
+        />
+      </el-form-item>
+      <el-form-item label="是否通过" prop="state">
+        <el-radio-group v-model="remark.state">
+          <el-radio :value="0">同意</el-radio>
+          <el-radio :value="1">不同意</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <div class="drawer-bottom">
+        <el-button @click="cancelClick">取消</el-button>
+        <el-button type="primary" @click="confirmClick">提交</el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup>
+import DetailCom from "@/views/sales/DetailCom.vue";
+import { dealFeedback, getUserList } from "@/api/sales/index";
+import { getUserTree } from "@/api/user/index";
+import {useUserStore} from "@/store";
+const drawerVisible = ref(false);
+const detailComRef = ref(null);
+const saleModel = ref({});
+const userStore = useUserStore();
+const disabledDate = (time)=> {
+  //选择今天以及今天之后的日期
+  return time.getTime() < Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择
+  //选择今天以及今天之前的日期
+  //return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择今天的
+}
+const showDrawer = (row) => {
+  drawerVisible.value = true;
+  saleModel.value = row;
+
+  nextTick(() => {
+    detailComRef.value && detailComRef.value.refreshView(row);
+  });
+
+  getUserInfo();
+};
+
+const rules1 = {
+  content: [
+    { required: true, message: "请输入投诉或建议处置意见", trigger: "blur" },
+    { min: 2, max: 200, message: "长度在 2 到 200 个字符", trigger: "blur" },
+  ],
+  user: [
+    { required: true, message: "请输入姓名", trigger: "blur" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+  time: [{ required: true, message: "请选择日期", trigger: "change" }],
+  nextRemarkUser: [
+    { required: true, message: "请选择处理人", trigger: "change" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+};
+
+defineExpose({ showDrawer });
+
+const remarkRef = ref(null);
+
+const remark = reactive({
+  content: "",
+  user: "",
+  time: "",
+  nextRemarkUser: "",
+  state: 0,
+});
+
+const cancelClick = () => {
+  drawerVisible.value = false;
+
+  remarkRef.value.resetFields();
+};
+
+const feedBackEmit = defineEmits(["finish"]);
+
+// 用户信息
+const userInfo = ref({});
+const userList = ref([]);
+const getUserInfo = async () => {
+  getUserTree().then((data) => {
+    userList.value = data.data;
+  });
+};
+
+const confirmClick = () => {
+  remark.user = userStore.user.username;
+  const date = new Date();
+  const now = date.getFullYear() + "年" + date.getMonth() + "月" + date.getDate() + "日"
+  remarkRef.value.validate((valid) => {
+    if (valid) {
+      let remark2Copy = {
+        content: remark.content,
+        user: remark.user,
+        time: now,
+        state: remark.state,
+      };
+      let remark3 = {
+        content: "",
+        user: remark.nextRemarkUser, // qinhaibo和dengyu说是user1234的
+        time: "",
+      };
+
+      let p = {
+        id: saleModel.value.id,
+        remark3: JSON.stringify(remark2Copy),
+        remark4: JSON.stringify(remark3),
+        currentUserName: remark.nextRemarkUser,
+        state: remark.state,
+        step: 3, //步骤 1 投书或建议处置意见 2 整改及纠正措施验证 3 处置情况的反馈意见
+      };
+
+      dealFeedback(p).then(() => {
+        feedBackEmit("finish");
+        cancelClick();
+      });
+    } else {
+      console.log("remarkRef invalid");
+      return false;
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+@media print {
+  #print {
+    position: absolute; /* 或 absolute, fixed, 根据需要调整 */
+    top: 20px; /* 调整顶部位置 */
+    margin: 0; /* 重置边距 */
+    width: 1000px;
+  }
+}
+</style>

+ 202 - 0
src/views/sales/handle4.vue

@@ -0,0 +1,202 @@
+<template>
+  <el-drawer v-model="drawerVisible" size="1000">
+    <div>
+      <DetailCom ref="detailComRef"></DetailCom>
+    </div>
+
+    <el-form
+        ref="remarkRef"
+        :model="remark"
+        label-width="150"
+        :rules="rules1"
+        style="max-width: 600px; margin-left: 80px; margin-top: 20px"
+    >
+      <el-form-item label="整改及纠正措施" prop="content">
+        <el-input
+            v-model="remark.content"
+            type="textarea"
+            :autosize="{ minRows: 3, maxRows: 6 }"
+        />
+      </el-form-item>
+      <!--      <el-form-item label="填表人" prop="user">
+              <el-select
+                v-model="remark.user"
+                placeholder="请选择"
+                style="width: 100%"
+              >
+                <el-option
+                  v-for="item in userList"
+                  :key="item.userName"
+                  :label="item.userName"
+                  :value="item.userName"
+                />
+              </el-select>
+            </el-form-item>-->
+<!--      <el-form-item label="日期" prop="time">
+        <el-date-picker
+            v-model="remark.time"
+            type="date"
+            placeholder="请选择日期"
+            clearable
+            :disabled-date="disabledDate"
+            format="YYYY年MM月DD日"
+            value-format="YYYY年MM月DD日"
+            style="width: 100%"
+        />
+      </el-form-item>-->
+      <el-form-item label="下一步处理人" prop="nextRemarkUser" v-if="remark.state == 0">
+        <!--        <el-select
+                  v-model="remark.nextRemarkUser"
+                  placeholder="请选择处理人"
+                  style="width: 100%"
+                >
+                  <el-option
+                    v-for="item in userList"
+                    :key="item.userName"
+                    :label="item.userName"
+                    :value="item.userName"
+                  />
+                </el-select>-->
+        <el-tree-select
+            v-model="remark.nextRemarkUser"
+            :data="userList"
+            filterable
+        />
+      </el-form-item>
+      <el-form-item label="是否通过" prop="state">
+        <el-radio-group v-model="remark.state">
+          <el-radio :value="0">同意</el-radio>
+          <el-radio :value="1">不同意</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <div class="drawer-bottom">
+        <el-button @click="cancelClick">取消</el-button>
+        <el-button type="primary" @click="confirmClick">提交</el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup>
+import DetailCom from "@/views/sales/DetailCom.vue";
+import { dealFeedback, getUserList } from "@/api/sales/index";
+import { getUserTree } from "@/api/user/index";
+import {useUserStore} from "@/store";
+const drawerVisible = ref(false);
+const detailComRef = ref(null);
+const saleModel = ref({});
+const userStore = useUserStore();
+const disabledDate = (time)=> {
+  //选择今天以及今天之后的日期
+  return time.getTime() < Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择
+  //选择今天以及今天之前的日期
+  //return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择今天的
+}
+const showDrawer = (row) => {
+  drawerVisible.value = true;
+  saleModel.value = row;
+
+  nextTick(() => {
+    detailComRef.value && detailComRef.value.refreshView(row);
+  });
+
+  getUserInfo();
+};
+
+const rules1 = {
+  content: [
+    { required: true, message: "请输入投诉或建议处置意见", trigger: "blur" },
+    { min: 2, max: 200, message: "长度在 2 到 200 个字符", trigger: "blur" },
+  ],
+  user: [
+    { required: true, message: "请输入姓名", trigger: "blur" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+  time: [{ required: true, message: "请选择日期", trigger: "change" }],
+  nextRemarkUser: [
+    { required: true, message: "请选择处理人", trigger: "change" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+};
+
+defineExpose({ showDrawer });
+
+const remarkRef = ref(null);
+
+const remark = reactive({
+  content: "",
+  user: "",
+  time: "",
+  nextRemarkUser: "",
+  state: 0,
+});
+
+const cancelClick = () => {
+  drawerVisible.value = false;
+
+  remarkRef.value.resetFields();
+};
+
+const feedBackEmit = defineEmits(["finish"]);
+
+// 用户信息
+const userInfo = ref({});
+const userList = ref([]);
+const getUserInfo = async () => {
+  getUserTree().then((data) => {
+    userList.value = data.data;
+  });
+};
+
+const confirmClick = () => {
+  remark.user = userStore.user.username;
+  const date = new Date();
+  const now = date.getFullYear() + "年" + date.getMonth() + "月" + date.getDate() + "日"
+  remarkRef.value.validate((valid) => {
+    if (valid) {
+      let remark2Copy = {
+        content: remark.content,
+        user: remark.user,
+        time: now,
+        state: remark.state,
+      };
+      let remark3 = {
+        content: "",
+        user: remark.nextRemarkUser, // qinhaibo和dengyu说是user1234的
+        time: "",
+      };
+
+      let p = {
+        id: saleModel.value.id,
+        currentUserName: remark.nextRemarkUser,
+        remark4: JSON.stringify(remark2Copy),
+        state: remark.state,
+        remark5: JSON.stringify(remark3),
+        step: 4, //步骤 1 投书或建议处置意见 2 整改及纠正措施验证 3 处置情况的反馈意见
+      };
+
+      dealFeedback(p).then(() => {
+        feedBackEmit("finish");
+        cancelClick();
+      });
+    } else {
+      console.log("remarkRef invalid");
+      return false;
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+@media print {
+  #print {
+    position: absolute; /* 或 absolute, fixed, 根据需要调整 */
+    top: 20px; /* 调整顶部位置 */
+    margin: 0; /* 重置边距 */
+    width: 1000px;
+  }
+}
+</style>

+ 77 - 61
src/views/sales/handle5.vue

@@ -5,57 +5,63 @@
     </div>
 
     <el-form
-      ref="remarkRef"
-      :model="remark"
-      label-width="150"
-      :rules="rules1"
-      style="max-width: 600px; margin-left: 80px; margin-top: 20px"
+        ref="remarkRef"
+        :model="remark"
+        label-width="150"
+        :rules="rules1"
+        style="max-width: 600px; margin-left: 80px; margin-top: 20px"
     >
       <el-form-item label="整改及纠正措施验证" prop="content">
         <el-input
-          v-model="remark.content"
-          type="textarea"
-          :autosize="{ minRows: 3, maxRows: 6 }"
+            v-model="remark.content"
+            type="textarea"
+            :autosize="{ minRows: 3, maxRows: 6 }"
         />
       </el-form-item>
-      <el-form-item label="填表人" prop="user">
-        <el-select
-          v-model="remark.user"
-          placeholder="请选择"
-          style="width: 100%"
-        >
-          <el-option
-            v-for="item in userList"
-            :key="item.userName"
-            :label="item.userName"
-            :value="item.userName"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="日期" prop="time">
+      <!--      <el-form-item label="填表人" prop="user">
+              <el-select
+                v-model="remark.user"
+                placeholder="请选择"
+                style="width: 100%"
+              >
+                <el-option
+                  v-for="item in userList"
+                  :key="item.userName"
+                  :label="item.userName"
+                  :value="item.userName"
+                />
+              </el-select>
+            </el-form-item>-->
+<!--      <el-form-item label="日期" prop="time">
         <el-date-picker
-          v-model="remark.time"
-          type="date"
-          placeholder="请选择日期"
-          clearable
-          format="YYYY年MM月DD日"
-          value-format="YYYY年MM月DD日"
-          style="width: 100%"
+            v-model="remark.time"
+            type="date"
+            placeholder="请选择日期"
+            :disabled-date="disabledDate"
+            clearable
+            format="YYYY年MM月DD日"
+            value-format="YYYY年MM月DD日"
+            style="width: 100%"
+        />
+      </el-form-item>-->
+      <el-form-item label="下一步处理人" prop="nextRemarkUser" v-if="remark.state == 0">
+        <!--        <el-select
+                  v-model="remark.nextRemarkUser"
+                  placeholder="请选择处理人"
+                  style="width: 100%"
+                >
+                  <el-option
+                    v-for="item in userList"
+                    :key="item.userName"
+                    :label="item.userName"
+                    :value="item.userName"
+                  />
+                </el-select>-->
+        <el-tree-select
+            v-model="remark.nextRemarkUser"
+            :data="userList"
+            filterable
         />
-      </el-form-item>
-      <el-form-item label="下一步处理人" prop="nextRemarkUser">
-        <el-select
-          v-model="remark.nextRemarkUser"
-          placeholder="请选择处理人"
-          style="width: 100%"
-        >
-          <el-option
-            v-for="item in userList"
-            :key="item.userName"
-            :label="item.userName"
-            :value="item.userName"
-          />
-        </el-select>
       </el-form-item>
       <el-form-item label="是否通过" prop="state">
         <el-radio-group v-model="remark.state">
@@ -77,11 +83,18 @@
 <script setup>
 import DetailCom from "@/views/sales/DetailCom.vue";
 import { dealFeedback, getUserList } from "@/api/sales/index";
-
+import { getUserTree } from "@/api/user/index";
+import {useUserStore} from "@/store";
 const drawerVisible = ref(false);
 const detailComRef = ref(null);
 const saleModel = ref({});
-
+const userStore = useUserStore();
+const disabledDate = (time)=> {
+  //选择今天以及今天之后的日期
+  return time.getTime() < Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择
+  //选择今天以及今天之前的日期
+  //return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择今天的
+}
 const showDrawer = (row) => {
   drawerVisible.value = true;
   saleModel.value = row;
@@ -95,7 +108,7 @@ const showDrawer = (row) => {
 
 const rules1 = {
   content: [
-    { required: true, message: "请输入整改及纠正措施验证", trigger: "blur" },
+    { required: true, message: "请输入投诉或建议处置意见", trigger: "blur" },
     { min: 2, max: 200, message: "长度在 2 到 200 个字符", trigger: "blur" },
   ],
   user: [
@@ -118,7 +131,7 @@ const remark = reactive({
   user: "",
   time: "",
   nextRemarkUser: "",
-  state: 1,
+  state: 0,
 });
 
 const cancelClick = () => {
@@ -133,33 +146,36 @@ const feedBackEmit = defineEmits(["finish"]);
 const userInfo = ref({});
 const userList = ref([]);
 const getUserInfo = async () => {
-  const res = await getUserList();
-  userList.value = res.data;
-  // if (userList.value.length > 0) {
-  //   userInfo.value = userList.value[0];
-  // }
+  getUserTree().then((data) => {
+    userList.value = data.data;
+  });
 };
 
 const confirmClick = () => {
+  remark.user = userStore.user.username;
+  const date = new Date();
+  const now = date.getFullYear() + "年" + date.getMonth() + "月" + date.getDate() + "日"
   remarkRef.value.validate((valid) => {
     if (valid) {
-      let remark5Copy = {
+      let remark2Copy = {
         content: remark.content,
-        user5: remark.user,
-        time: remark.time,
+        user: remark.user,
+        time: now,
         state: remark.state,
       };
-      let remark6 = {
+      let remark3 = {
         content: "",
-        user6: remark.nextRemarkUser, // qinhaibo和dengyu说是user1234的
+        user: remark.nextRemarkUser, // qinhaibo和dengyu说是user1234的
         time: "",
       };
 
       let p = {
         id: saleModel.value.id,
-        remark5: JSON.stringify(remark5Copy),
-        remark6: JSON.stringify(remark6),
-        step: 2, //步骤 1 投书或建议处置意见 2 整改及纠正措施验证 3 处置情况的反馈意见
+        remark5: JSON.stringify(remark2Copy),
+        remark6: JSON.stringify(remark3),
+        state: remark.state,
+        currentUserName: remark.nextRemarkUser,
+        step: 5, //步骤 1 投书或建议处置意见 2 整改及纠正措施验证 3 处置情况的反馈意见
       };
 
       dealFeedback(p).then(() => {

+ 80 - 58
src/views/sales/handle6.vue

@@ -5,58 +5,64 @@
     </div>
 
     <el-form
-      ref="remarkRef"
-      :model="remark"
-      label-width="150"
-      :rules="rules1"
-      style="max-width: 600px; margin-left: 80px; margin-top: 20px"
+        ref="remarkRef"
+        :model="remark"
+        label-width="150"
+        :rules="rules1"
+        style="max-width: 600px; margin-left: 80px; margin-top: 20px"
     >
       <el-form-item label="处置情况的反馈意见" prop="content">
         <el-input
-          v-model="remark.content"
-          type="textarea"
-          :autosize="{ minRows: 3, maxRows: 6 }"
+            v-model="remark.content"
+            type="textarea"
+            :autosize="{ minRows: 3, maxRows: 6 }"
         />
       </el-form-item>
-      <el-form-item label="填表人" prop="user">
-        <el-select
-          v-model="remark.user"
-          placeholder="请选择"
-          style="width: 100%"
-        >
-          <el-option
-            v-for="item in userList"
-            :key="item.userName"
-            :label="item.userName"
-            :value="item.userName"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="日期" prop="time">
+      <!--      <el-form-item label="填表人" prop="user">
+              <el-select
+                v-model="remark.user"
+                placeholder="请选择"
+                style="width: 100%"
+              >
+                <el-option
+                  v-for="item in userList"
+                  :key="item.userName"
+                  :label="item.userName"
+                  :value="item.userName"
+                />
+              </el-select>
+            </el-form-item>-->
+<!--      <el-form-item label="日期" prop="time">
         <el-date-picker
-          v-model="remark.time"
-          type="date"
-          placeholder="请选择日期"
-          clearable
-          format="YYYY年MM月DD日"
-          value-format="YYYY年MM月DD日"
-          style="width: 100%"
+            v-model="remark.time"
+            type="date"
+            placeholder="请选择日期"
+            clearable
+            :disabled-date="disabledDate"
+            format="YYYY年MM月DD日"
+            value-format="YYYY年MM月DD日"
+            style="width: 100%"
+        />
+      </el-form-item>-->
+      <el-form-item label="下一步处理人" prop="nextRemarkUser" v-if="remark.state == 0">
+        <!--        <el-select
+                  v-model="remark.nextRemarkUser"
+                  placeholder="请选择处理人"
+                  style="width: 100%"
+                >
+                  <el-option
+                    v-for="item in userList"
+                    :key="item.userName"
+                    :label="item.userName"
+                    :value="item.userName"
+                  />
+                </el-select>-->
+        <el-tree-select
+            v-model="remark.nextRemarkUser"
+            :data="userList"
+            filterable
         />
       </el-form-item>
-      <!--      <el-form-item label="下一步处理人" prop="nextRemarkUser">-->
-      <!--        <el-select-->
-      <!--          v-model="remark.nextRemarkUser"-->
-      <!--          placeholder="请选择处理人"-->
-      <!--          style="width: 100%"-->
-      <!--        >-->
-      <!--          <el-option-->
-      <!--            v-for="item in userList"-->
-      <!--            :key="item.userName"-->
-      <!--            :label="item.userName"-->
-      <!--            :value="item.userName"-->
-      <!--          />-->
-      <!--        </el-select>-->
-      <!--      </el-form-item>-->
       <el-form-item label="是否通过" prop="state">
         <el-radio-group v-model="remark.state">
           <el-radio :value="0">同意</el-radio>
@@ -77,11 +83,18 @@
 <script setup>
 import DetailCom from "@/views/sales/DetailCom.vue";
 import { dealFeedback, getUserList } from "@/api/sales/index";
-
+import { getUserTree } from "@/api/user/index";
+import {useUserStore} from "@/store";
 const drawerVisible = ref(false);
 const detailComRef = ref(null);
 const saleModel = ref({});
-
+const userStore = useUserStore();
+const disabledDate = (time)=> {
+  //选择今天以及今天之后的日期
+  return time.getTime() < Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择
+  //选择今天以及今天之前的日期
+  //return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择今天的
+}
 const showDrawer = (row) => {
   drawerVisible.value = true;
   saleModel.value = row;
@@ -95,7 +108,7 @@ const showDrawer = (row) => {
 
 const rules1 = {
   content: [
-    { required: true, message: "请输入处置情况的反馈意见", trigger: "blur" },
+    { required: true, message: "请输入投诉或建议处置意见", trigger: "blur" },
     { min: 2, max: 200, message: "长度在 2 到 200 个字符", trigger: "blur" },
   ],
   user: [
@@ -117,7 +130,7 @@ const remark = reactive({
   content: "",
   user: "",
   time: "",
-  // nextRemarkUser: "",
+  nextRemarkUser: "",
   state: 0,
 });
 
@@ -133,27 +146,36 @@ const feedBackEmit = defineEmits(["finish"]);
 const userInfo = ref({});
 const userList = ref([]);
 const getUserInfo = async () => {
-  const res = await getUserList();
-  userList.value = res.data;
-  // if (userList.value.length > 0) {
-  //   userInfo.value = userList.value[0];
-  // }
+  getUserTree().then((data) => {
+    userList.value = data.data;
+  });
 };
 
 const confirmClick = () => {
+  remark.user = userStore.user.username;
+  const date = new Date();
+  const now = date.getFullYear() + "年" + date.getMonth() + "月" + date.getDate() + "日"
   remarkRef.value.validate((valid) => {
     if (valid) {
-      let remark6Copy = {
+      let remark2Copy = {
         content: remark.content,
-        user6: remark.user,
-        time: remark.time,
+        user: remark.user,
+        time: now,
         state: remark.state,
       };
+      let remark3 = {
+        content: "",
+        user: remark.nextRemarkUser, // qinhaibo和dengyu说是user1234的
+        time: "",
+      };
 
       let p = {
         id: saleModel.value.id,
-        remark6: JSON.stringify(remark6Copy),
-        step: 3, //步骤 1 投书或建议处置意见 2 整改及纠正措施验证 3 处置情况的反馈意见
+        remark6: JSON.stringify(remark2Copy),
+        remark7: JSON.stringify(remark3),
+        state: remark.state,
+        currentUserName: remark.nextRemarkUser,
+        step: 6, //步骤 1 投书或建议处置意见 2 整改及纠正措施验证 3 处置情况的反馈意见
       };
 
       dealFeedback(p).then(() => {

+ 195 - 0
src/views/sales/handle7.vue

@@ -0,0 +1,195 @@
+<template>
+  <el-drawer v-model="drawerVisible" size="1000">
+    <div>
+      <DetailCom ref="detailComRef"></DetailCom>
+    </div>
+
+    <el-form
+        ref="remarkRef"
+        :model="remark"
+        label-width="150"
+        :rules="rules1"
+        style="max-width: 600px; margin-left: 80px; margin-top: 20px"
+    >
+      <el-form-item label="处置情况的反馈意见" prop="content">
+        <el-input
+            v-model="remark.content"
+            type="textarea"
+            :autosize="{ minRows: 3, maxRows: 6 }"
+        />
+      </el-form-item>
+      <!--      <el-form-item label="填表人" prop="user">
+              <el-select
+                v-model="remark.user"
+                placeholder="请选择"
+                style="width: 100%"
+              >
+                <el-option
+                  v-for="item in userList"
+                  :key="item.userName"
+                  :label="item.userName"
+                  :value="item.userName"
+                />
+              </el-select>
+            </el-form-item>-->
+<!--      <el-form-item label="日期" prop="time">
+        <el-date-picker
+            v-model="remark.time"
+            type="date"
+            placeholder="请选择日期"
+            clearable
+            :disabled-date="disabledDate"
+            format="YYYY年MM月DD日"
+            value-format="YYYY年MM月DD日"
+            style="width: 100%"
+        />
+      </el-form-item>-->
+<!--      <el-form-item label="下一步处理人" prop="nextRemarkUser">
+        &lt;!&ndash;        <el-select
+                  v-model="remark.nextRemarkUser"
+                  placeholder="请选择处理人"
+                  style="width: 100%"
+                >
+                  <el-option
+                    v-for="item in userList"
+                    :key="item.userName"
+                    :label="item.userName"
+                    :value="item.userName"
+                  />
+                </el-select>&ndash;&gt;
+        <el-tree-select
+            v-model="remark.nextRemarkUser"
+            :data="userList"
+            filterable
+        />
+      </el-form-item>-->
+      <el-form-item label="是否通过" prop="state">
+        <el-radio-group v-model="remark.state">
+          <el-radio :value="0">同意</el-radio>
+          <el-radio :value="1">不同意</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <div class="drawer-bottom">
+        <el-button @click="cancelClick">取消</el-button>
+        <el-button type="primary" @click="confirmClick">提交</el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup>
+import DetailCom from "@/views/sales/DetailCom.vue";
+import { dealFeedback, getUserList } from "@/api/sales/index";
+import { getUserTree } from "@/api/user/index";
+import {useUserStore} from "@/store";
+const drawerVisible = ref(false);
+const detailComRef = ref(null);
+const saleModel = ref({});
+const userStore = useUserStore();
+const disabledDate = (time)=> {
+  //选择今天以及今天之后的日期
+  return time.getTime() < Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择
+  //选择今天以及今天之前的日期
+  //return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择今天的
+}
+const showDrawer = (row) => {
+  drawerVisible.value = true;
+  saleModel.value = row;
+
+  nextTick(() => {
+    detailComRef.value && detailComRef.value.refreshView(row);
+  });
+
+  getUserInfo();
+};
+
+const rules1 = {
+  content: [
+    { required: true, message: "请输入投诉或建议处置意见", trigger: "blur" },
+    { min: 2, max: 200, message: "长度在 2 到 200 个字符", trigger: "blur" },
+  ],
+  user: [
+    { required: true, message: "请输入姓名", trigger: "blur" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+  time: [{ required: true, message: "请选择日期", trigger: "change" }],
+  nextRemarkUser: [
+    { required: true, message: "请选择处理人", trigger: "change" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+};
+
+defineExpose({ showDrawer });
+
+const remarkRef = ref(null);
+
+const remark = reactive({
+  content: "",
+  user: "",
+  time: "",
+  nextRemarkUser: "",
+  state: 0,
+});
+
+const cancelClick = () => {
+  drawerVisible.value = false;
+
+  remarkRef.value.resetFields();
+};
+
+const feedBackEmit = defineEmits(["finish"]);
+
+// 用户信息
+const userInfo = ref({});
+const userList = ref([]);
+const getUserInfo = async () => {
+  getUserTree().then((data) => {
+    userList.value = data.data;
+  });
+};
+
+const confirmClick = () => {
+  remark.user = userStore.user.username;
+  const date = new Date();
+  const now = date.getFullYear() + "年" + date.getMonth() + "月" + date.getDate() + "日"
+  remarkRef.value.validate((valid) => {
+    if (valid) {
+      let remark2Copy = {
+        content: remark.content,
+        user: remark.user,
+        time: now,
+        state: remark.state,
+      };
+      let p = {
+        id: saleModel.value.id,
+        remark7: JSON.stringify(remark2Copy),
+        state: remark.state,
+        currentUserName: remark.nextRemarkUser,
+        step: 7, //步骤 1 投书或建议处置意见 2 整改及纠正措施验证 3 处置情况的反馈意见
+      };
+
+      dealFeedback(p).then(() => {
+        feedBackEmit("finish");
+        cancelClick();
+      });
+    } else {
+      console.log("remarkRef invalid");
+      return false;
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+@media print {
+  #print {
+    position: absolute; /* 或 absolute, fixed, 根据需要调整 */
+    top: 20px; /* 调整顶部位置 */
+    margin: 0; /* 重置边距 */
+    width: 1000px;
+  }
+}
+</style>

+ 25 - 9
src/views/sales/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="container">
     <div class="header">
-      <Search :searchOptions="searchForm" ref="searchRef" />
+      <Search :searchOptions="searchForm" ref="searchRef" @dataList="getData"/>
     </div>
     <div class="table">
       <el-button
@@ -17,6 +17,7 @@
         <el-table-column prop="materialName" label="物料名称" />
         <el-table-column prop="materialModel" label="物料型号" />
         <el-table-column prop="contacts" label="联系人" />
+        <el-table-column prop="currentUserName" label="审核人" overhidden="true" />
         <el-table-column prop="state" label="审核状态">
           <template #default="{ row }">
             <div :style="{ color: getColorByState(row.state) }">
@@ -42,7 +43,7 @@
             >
             <el-button
               link
-              v-if="row.state === 0 || row.state === 1"
+              v-if="(row.state === 0 || row.state === 1) && userStore.user.username == row.currentUserName"
               @click="handle(row)"
               type="primary"
               >处理</el-button
@@ -65,27 +66,33 @@
       <Add ref="addRef" @finish="getData"></Add>
       <Detail ref="detailRef"></Detail>
       <Handle2 ref="handle2Ref" @finish="getData"></Handle2>
+      <Handle3 ref="handle3Ref" @finish="getData"></Handle3>
+      <Handle4 ref="handle4Ref" @finish="getData"></Handle4>
       <Handle5 ref="handle5Ref" @finish="getData"></Handle5>
-      <Handle6 ref="handle5Ref" @finish="getData"></Handle6>
+      <Handle6 ref="handle6Ref" @finish="getData"></Handle6>
+      <Handle7 ref="handle7Ref" @finish="getData"></Handle7>
     </div>
   </div>
 </template>
 
 <script setup>
 import Search from "@/components/Search/index.vue";
-import { useSpcStore } from "@/store";
+import { useSpcStore,useUserStore } from "@/store";
 import { deleteFeedback, getSalesData } from "@/api/sales/index";
 import Add from "@/views/sales/add.vue";
 import Detail from "@/views/sales/detail.vue";
 import Handle2 from "@/views/sales/handle2.vue";
+import Handle3 from "@/views/sales/handle3.vue";
+import Handle4 from "@/views/sales/handle4.vue";
 import Handle5 from "@/views/sales/handle5.vue";
 import Handle6 from "@/views/sales/handle6.vue";
+import Handle7 from "@/views/sales/handle7.vue";
 
 defineOptions({
   name: "SPCSales",
 });
 const store = useSpcStore();
-
+const userStore = useUserStore();
 const router = useRouter();
 
 const addRef = ref(null);
@@ -145,16 +152,25 @@ const toDelete = async (row) => {
 
 // 处理相关
 const handle2Ref = ref(null);
+const handle3Ref = ref(null);
+const handle4Ref = ref(null);
 const handle5Ref = ref(null);
 const handle6Ref = ref(null);
+const handle7Ref = ref(null);
 const handle = (row) => {
   if (row.remark2 && !JSON.parse(row.remark2).content) {
     handle2Ref.value && handle2Ref.value.showDrawer(row); // 处理
+  } else if (row.remark3 && !JSON.parse(row.remark3).content) {
+    handle3Ref.value && handle3Ref.value.showDrawer(row); // 处理
+  } else if (row.remark4 && !JSON.parse(row.remark4).content) {
+    handle4Ref.value && handle4Ref.value.showDrawer(row); // 处理
   } else if (row.remark5 && !JSON.parse(row.remark5).content) {
-    handle6Ref.value && handle6Ref.value.showDrawer(row); // 处理
-  } else if (row.remark4) {
     handle5Ref.value && handle5Ref.value.showDrawer(row); // 处理
-  } else {
+  } else if (row.remark6 && !JSON.parse(row.remark6).content) {
+    handle6Ref.value && handle6Ref.value.showDrawer(row); // 处理
+  } else if (row.remark7 && !JSON.parse(row.remark7).content) {
+    handle7Ref.value && handle7Ref.value.showDrawer(row); // 处理
+  }else{
     ElMessage.info("该工单正在处理中。。。");
   }
 };
@@ -187,7 +203,7 @@ const getColorByState = (state) => {
     case 1:
       return "#bba559";
     case 2:
-      return "909399";
+      return "#d96868";
     case 3:
       return "#67c23a";
     default:

+ 95 - 144
src/views/statistic/firstPassYield/index.vue

@@ -6,7 +6,7 @@
           <div class="text">选择统计时间段:</div>
           <div style="display: flex">
             <el-date-picker
-              v-model="value1"
+              v-model="searchTime"
               type="daterange"
               range-separator="-"
               start-placeholder="起始时间"
@@ -17,7 +17,7 @@
             />
           </div>
         </div>
-        <div class="header">
+<!--        <div class="header">
           <div class="text">选择统计维度:</div>
           <div>
             <el-radio-group v-model="radio" style="display: flex">
@@ -27,7 +27,7 @@
               <el-radio size="small" :value="4">年</el-radio>
             </el-radio-group>
           </div>
-        </div>
+        </div>-->
         <div class="header">
           <div class="text">选择统计车间:</div>
           <el-tree
@@ -35,7 +35,6 @@
             :data="statProductionLineData"
             show-checkbox
             default-expand-all
-            :default-checked-keys="['line']"
             node-key="key"
           />
         </div>
@@ -71,12 +70,15 @@
       <div class="box">
         <div class="boxheader">
           <div>
-            <el-button type="primary" class="btn" @click="getTableDataSearch"
+            <el-button type="primary" class="btn" @click="getTableData"
               >统计查询</el-button
             >
             <el-button class="btn" @click="reset">重置</el-button>
           </div>
-          <el-button class="btn" @click="exportFnc">导出</el-button>
+
+            <el-button class="ml-3" @click="exportData('/api/v1/quality/stat/export')">
+                <template #icon> <i-ep-download /> </template>导出
+            </el-button>
         </div>
         <div class="info">
           <el-table
@@ -100,13 +102,14 @@
               prop="operationName"
               label="工序名称"
             /> -->
-            <el-table-column prop="productLineName" label="车间名称" />
-            <el-table-column prop="productName" label="产品名称" />
-            <el-table-column prop="productCode" label="产品编码" />
-            <el-table-column prop="batchNo" label="产品批次" />
-            <el-table-column prop="goodRate" label="良率" />
-            <el-table-column prop="badRate" label="不良率" />
-            <el-table-column prop="timeStr" label="日期" />
+            <el-table-column prop="workshopName" label="车间名称" />
+            <el-table-column prop="materialName" label="产品名称" />
+            <el-table-column prop="materialCode" label="产品编码" />
+              <el-table-column prop="materialModel" label="产品规格" />
+            <el-table-column prop="workOrderCode" label="产品批次" />
+            <el-table-column prop="qualified" label="良率" />
+            <el-table-column prop="noQualified" label="不良率" />
+            <el-table-column prop="updated" label="日期" />
           </el-table>
         </div>
         <div class="footer">
@@ -123,64 +126,35 @@
       </div>
     </div>
   </div>
-  <el-dialog title="选择统计产品" v-model="dialogVisible" width="60%" center>
-    <div>
-      <Search :searchOptions="searchForm" ref="searchRef" />
-    </div>
-    <div>
-      <el-table
-        :data="tableProdtData"
-        row-key="id"
-        border
-        @selection-change="handleSelectionChange"
-      >
-        <el-table-column type="selection" width="55" />
-        <el-table-column prop="productLineName" label="车间名称" />
-        <el-table-column prop="productName" label="产品名称" />
-        <el-table-column prop="productCode" label="产品编码" />
-        <el-table-column prop="batchNo" label="产品批次" />
-        <el-table-column prop="productType" label="产品类型" />
-        <el-table-column prop="timeStr" label="创建日期" />
-      </el-table>
-      <Pagination
-        :total="currentProdtOption.total"
-        :page="currentProdtOption.page"
-        :limit="currentProdtOption.limit"
-        :pageSizes="currentProdtOption.pageSizes"
-        v-model:page="currentProdtOption.page"
-        v-model:limit="currentProdtOption.limit"
-        @pagination="getProdtData"
-      />
-    </div>
-    <div>
-      <el-button type="primary" class="btn" @click="handleConfirm"
-        >确定</el-button
-      >
-      <el-button class="btn" @click="dialogVisible = false">取消</el-button>
-    </div>
-  </el-dialog>
+
+  <CrudTable
+      ref="ctableRef"
+      tableTitle="选择统计产品"
+      :multipleRow="multipleRow"
+      tableType="WORK_ORDER"
+      @selected-sure="handleConfirm"
+  />
 </template>
 
 <script setup>
-import { getData, getStatLevel, getExport } from "@/api/statistic";
+import {getData, getStatLevel, getExport} from "@/api/statistic";
 import { getMockData } from "@/api/statistic/firstPassYieldMockData";
 import Pagination from "@/components/Pagination/index.vue";
 import { downFile } from "@/utils/common";
 import Search from "@/components/Search/index.vue";
-
+import {getWorkOrderInfo, getWorkShop} from "@/api/statistic/firstPassYieldData";
+import {useCrud} from "@/hooks/userCrud";
+const checkList=ref(null);
+const { form, data, option, search, page, toDeleteIds, Methords, Utils } =
+    useCrud({
+        src: "/api/v1/quality/stat",
+    });
+const { checkBtnPerm, downloadTemplate, exportData } = Utils; //按钮权限等工具
 defineOptions({
   name: "Dashboard",
   inheritAttrs: false,
 });
-const exportFnc = async () => {
-  await getExport({
-    endTime: value1.value ? value1.value[1] : "",
-    startTime: value1.value ? value1.value[0] : "",
-    queryTypes: getValue(treeRef1.value.getCheckedNodes()),
-    queryIndex: getValue(treeRef2.value.getCheckedNodes()),
-    timeType: radio.value,
-  }).then((res) => downFile(res));
-};
+const ctableRef=ref(null);
 const treeRef1 = ref(null);
 const treeRef2 = ref(null);
 const currentOption = ref({
@@ -193,7 +167,6 @@ const currentOption = ref({
 const maxHeight = ref(null);
 const maxWidth = ref(null);
 
-const value1 = ref(null);
 const radio = ref(1);
 const tableData = ref([]);
 
@@ -225,11 +198,10 @@ const getCurrentMonthStartAndEndDates = () => {
 const getValue = (array) => {
   let resarray = [];
   for (let i = 0; i < array.length; i++) {
-    resarray.push(array[i].value);
+    resarray.push(array[i].label);
   }
   return resarray;
 };
-const queryIndexs = ref([]);
 // const getTableData = async () => {
 //   queryIndexs.value = getValue(treeRef1.value.getCheckedNodes());
 //   const { data } = await getData({
@@ -247,45 +219,49 @@ const queryIndexs = ref([]);
 
 // mock数据
 const getTableData = async () => {
-  queryIndexs.value = getValue(treeRef1.value.getCheckedNodes());
-  const { data } = await getMockData({
-    page: currentOption.value.page,
-    limit: currentOption.value.limit,
+    search.value={};
+  const { data } = await getWorkOrderInfo({
+    pageNo: currentOption.value.page,
+    pageSize: currentOption.value.limit,
+    endTime: searchTime.value ? searchTime.value[1] : "",
+    startTime: searchTime.value ? searchTime.value[0] : "",
+    queryTypes: getValue(treeRef1.value.getCheckedNodes()),
+    queryIndex: workOrderCodes.value,
   }); // 使用假数据函数
+    search.value.startTime=searchTime.value ? searchTime.value[0] : "",
+        search.value.endTime=searchTime.value ? searchTime.value[1] : "",
+        search.value.queryTypes=getValue(treeRef1.value.getCheckedNodes()),
+        search.value.queryIndex=workOrderCodes.value,
   tableData.value = data.records;
   currentOption.value.total = data.totalCount;
 };
 // -------
 
-const reset = () => {
-  value1.value = getCurrentMonthStartAndEndDates();
+const reset = () => {searchTime.value = getCurrentMonthStartAndEndDates();
   // treeRef1.value.setCheckedKeys([statProductionLineData[0].key], true, true);
   // treeRef2.value.setCheckedKeys([statProductTypeData[0].key], true, true);
-  radio.value = 1;
   currentOption.value.page = 1;
-  treeData.value = [];
-  selectedRows.value = [];
-  tableData.value = [];
+  workOrderCodes.value = [];
+    treeRef1.value.setCheckedNodes([]);
   getTableData();
 };
 
 // mock数据
 const statProductionLineData = ref([
-  {
-    key: "line",
-    label: "微电子车间",
-    children: [],
-  },
 ]);
 
 const tableProdtData = ref([]);
 const dialogVisible = ref(false);
 const searchRef = ref(null);
+const searchTime =ref(null);
 const openProdtForm = async () => {
-  dialogVisible.value = true;
-  getProdtData();
+  ctableRef.value.startSelect();
+  ctableRef.value?.mergeOption({
+    selection: true,
+    reserveSelection: true,
+  });
 };
-
+const multipleRow = ref(true);
 const getProdtData = async () => {
   const { data } = await getMockData({
     page: currentProdtOption.value.page,
@@ -294,33 +270,7 @@ const getProdtData = async () => {
   tableProdtData.value = data.records;
   currentProdtOption.value.total = data.totalCount;
 };
-const searchForm = [
-  {
-    label: "产品名称",
-    type: "input",
-    key: "prodtName",
-  },
-  {
-    label: "产品编码",
-    type: "input",
-    key: "prodtCode",
-  },
-  {
-    label: "产品类型",
-    type: "select",
-    key: "prodtType",
-    options: [
-      {
-        label: "类型1",
-        value: "1",
-      },
-      {
-        label: "类型2",
-        value: "2",
-      },
-    ],
-  },
-];
+
 
 const currentProdtOption = ref({
   total: 0,
@@ -329,63 +279,48 @@ const currentProdtOption = ref({
   pageSizes: [10, 20, 30, 40, 50, 100],
 });
 // --------------------------------------------
-const statProductTypeData = ref([
-  {
-    key: "id",
-    label: "产品类型",
-    children: [
-      {
-        key: "productType1",
-        label: "类型1",
-      },
-      {
-        key: "productType2",
-        label: "类型2",
-      },
-    ],
-  },
-]);
+
 const selectedRows = ref([]); // 存储选中的行数据
 
-const handleSelectionChange = (rows) => {
-  selectedRows.value = rows; // 更新选中的行数据
-};
 
 const treeData = ref([]); // 存储转换后的 el-tree 数据
-const handleConfirm = () => {
+
+const workOrderCodes = ref([]);
+const handleConfirm = (val) => {
   const map = {};
   const tree = [];
-
-  selectedRows.value.forEach((row) => {
-    const { productName, batchNo } = row;
+    workOrderCodes.value=[];
+  val.forEach((row) => {
+      workOrderCodes.value.push(row.workOrderCode);
+    const { materialName, workOrderCode } = row;
 
     // 如果父级节点不存在,创建父级节点
-    if (!map[productName]) {
+    if (!map[materialName]) {
       const parentNode = {
-        label: productName, // 父级名称
-        key: productName, // 父级唯一标识
+        label: materialName, // 父级名称
+        key: materialName, // 父级唯一标识
         children: [], // 子级数组
       };
-      map[productName] = parentNode;
+      map[materialName] = parentNode;
       tree.push(parentNode);
     }
 
     // 添加子级节点
-    map[productName].children.push({
-      label: batchNo, // 子级名称
-      key: batchNo, // 子级唯一标识
+    map[materialName].children.push({
+      label: workOrderCode, // 子级名称
+      key: workOrderCode, // 子级唯一标识
     });
   });
 
   treeData.value = tree; // 更新 el-tree 数据源
-  dialogVisible.value = false; // 关闭对话框
 };
-
+//列表搜索体哦阿健
+const searchPageForm = ref({});
 const getTableDataSearch = () => {
-  if (treeData.value.length === 0) {
+ /* if (treeData.value.length === 0) {
     ElMessage.warning("请选择产品");
     return;
-  }
+  }*/
   // 提取 treeData 中的 productName 和 batchNo
   const selectedProductMap = {};
   treeData.value.forEach((parent) => {
@@ -412,11 +347,27 @@ const checkedKeys = computed(() => {
   }
   return array;
 });
+const getWorkShopList=()=>{
+    getWorkShop({}).then(
+        (data)=>{
+          statProductionLineData.value=data.data;
 
+        }
+    )
+}
+/*const handleCheckChange=(data, checked, indeterminate)=>{
+    console.log("aaaaa",data); // 选中的节点数据
+    console.log(checked); // 是否选中
+    console.log(indeterminate); // 是否为半选状态
+}*/
 onMounted(async () => {
+
   window.addEventListener("resize", setHeight);
-  value1.value = getCurrentMonthStartAndEndDates();
-  setHeight();
+    searchTime.value = getCurrentMonthStartAndEndDates();
+    search.value.startTime=searchTime.value[0];
+    search.value.endTime=searchTime.value[1];
+    setHeight();
+  await  getWorkShopList();
   // await getStatLevelData();
   getTableData();
 });

+ 116 - 357
src/views/statistic/report/index.vue

@@ -1,374 +1,133 @@
 <template>
-  <div class="container1">
-    <div class="header" v-show="!addStatus && !editStatus">
-      <Search
-        ref="searchref"
-        :searchOptions="searchOptons"
-        @data-list="getTableData"
-      />
-    </div>
-    <div class="table" v-if="!addStatus && !editStatus">
-      <div class="tableheader">
-        <el-button type="primary" size="small" class="btn" @click="toAdd"
-          >新增</el-button
-        >
-        <el-button class="btn" @click="exportFnc">导出</el-button>
-      </div>
-      <!-- <el-button class="btn" style="margin-bottom: 5px" @click="showPrint"
-        >打印</el-button
-      > -->
-      <el-table
-        :data="tableData"
-        border
-        :style="{ height: maxHeight - 40 + 'px' }"
+  <div class="mainContentBox">
+    <avue-crud
+      ref="crudRef"
+      v-model:search="search"
+      v-model="form"
+      :data="data"
+      :option="option"
+      v-model:page="page"
+      @row-save="createRow"
+      @row-update="updateRow"
+      @row-del="deleteRow"
+      @search-change="searchChange"
+      @search-reset="resetChange"
+      @size-change="dataList"
+      @current-change="dataList"
+      @selection-change="selectionChange"
+    >
+      <template #menu="{ row, index, type }">
+        <el-button type="primary" size="small" @click="showDetail(row)"
+          >查看</el-button
+        ></template
       >
-        <el-table-column prop="reportCode" label="报告编码" />
-        <el-table-column prop="reportName" label="报告名称" />
-        <el-table-column label="报告类型">
-          <template #default="{ row }">
-            {{ row.reportType === "1" ? "日报" : "月报" }}
-          </template>
-        </el-table-column>
-        <el-table-column prop="genDate" label="生成日期" />
-        <el-table-column prop="creator" label="创建人" />
-        <el-table-column prop="created" label="创建时间" />
-        <el-table-column
-          align="center"
-          width="160"
-          prop=""
-          label="操作"
-          id="opear"
-        >
-          <template #default="{ row }">
-            <el-button
-              type="primary"
-              class="btn"
-              style="height: 25px"
-              @click="toEdit(row)"
-              link
-              >编辑</el-button
-            >
-            <el-button
-              type="primary"
-              class="btn"
-              style="height: 25px"
-              @click="showPrint(row)"
-              link
-              >查看</el-button
-            >
-            <el-button
-              type="info"
-              class="btn"
-              style="height: 25px"
-              link
-              @click="toDelete(row.id)"
-              >删除</el-button
-            >
-          </template>
-        </el-table-column>
-      </el-table>
-      <Pagination />
-    </div>
-    <div v-if="addStatus || editStatus" class="formView">
-      <div class="formTitle">
-        {{ addStatus ? "新增报告" : "编辑报告" }}
-      </div>
-      <el-scrollbar style="height: calc(100% - 60px)">
-        <el-form
-          ref="ruleFormRef"
-          :model="formData"
-          :rules="rules"
-          label-width="auto"
-          class="formStyle"
+      <template #menu-right="{}">
+        <el-button
+          class="ml-3"
+          @click="exportData('/api/v1/quality/report/export')"
         >
-          <el-form-item label="报告编码" prop="reportCode">
-            <el-input v-model="formData.reportCode" />
-          </el-form-item>
-          <el-form-item label="报告名称" prop="reportName">
-            <el-input v-model="formData.reportName" />
-          </el-form-item>
-          <el-form-item label="报告类型" prop="reportType">
-            <el-select v-model="formData.reportType">
-              <el-option
-                v-for="(item, index) in reportTypeOptions"
-                :key="index"
-                :label="item.label"
-                :value="item.value"
-              />
-            </el-select>
-          </el-form-item>
-          <el-form-item label="选择生成日期" prop="genDate">
-            <el-date-picker
-              v-model="formData.genDate"
-              type="date"
-              placeholder="选择日期"
-              style="width: 100%"
-              v-if="formData.reportType == 1"
-            />
-            <el-date-picker
-              v-model="formData.genDate"
-              type="month"
-              placeholder="选择日期"
-              style="width: 100%"
-              v-if="formData.reportType == 2"
-            />
-          </el-form-item>
-          <el-form-item label="产品型号" prop="prodtCode">
-            <el-input
-              v-model="formData.prodtCode"
-              @click="openChoseForm('prodt')"
-            />
-          </el-form-item>
-          <el-form-item label="产品批次" prop="batchNo">
-            <el-input
-              v-model="formData.batchNo"
-              @click="openChoseForm('batch')"
-            />
-          </el-form-item>
-          <el-form-item label="产品工序" prop="operationCode">
-            <el-input
-              v-model="formData.operationCode"
-              @click="openChoseForm('operation')"
-            />
-          </el-form-item>
-          <el-form-item label="创建人" prop="creator">
-            <el-input v-model="formData.creator" />
-          </el-form-item>
-        </el-form>
-        <div style="display: flex; justify-content: space-evenly">
-          <el-button
-            type="primary"
-            size="small"
-            style="margin-top: 10px"
-            class="btn"
-            @click="toSubmit"
-            >提交</el-button
-          >
-          <el-button
-            type="info"
-            size="small"
-            style="margin-top: 10px"
-            class="btn"
-            @click="toCancel"
-            >取消</el-button
-          >
-        </div>
-      </el-scrollbar>
-    </div>
-    <reportTemplate v-model="showStatus" :tablesData="tablesData" />
-    <operationForm ref="opRef" />
+          <template #icon> <i-ep-download /> </template>导出
+        </el-button>
+      </template>
+    </avue-crud>
+<!--    <reportTemplate v-model="showStatus" :detail="detail" />-->
+    <ToPrintDialog ref="toPrintRef"></ToPrintDialog>
   </div>
 </template>
 
 <script setup>
-import Search from "@/components/Search/index.vue";
+import { ref, getCurrentInstance } from "vue";
+import { useCrud } from "@/hooks/userCrud";
 import reportTemplate from "@/components/ReportView/reportTemplate.vue";
-import { useDictionaryStore } from "@/store";
-import { getData } from "@/api/report";
-import Pagination from "@/components/Pagination/index.vue";
-import { getMockData } from "@/api/statistic/reportMockData";
-import operationForm from "./operationForm.vue";
-const searchref = ref(null);
-const showPrint = () => {
-  showStatus.value = true;
-};
-const toLook = (row) => {
-  const fullUrl = window.location.href;
-  const parts = fullUrl.split("/");
-  const thirdSlashIndex = 2;
-  const truncatedUrl = parts.slice(0, thirdSlashIndex + 1).join("/");
-  window.open(truncatedUrl + "/" + row.fileUrl, "_blank");
-};
-const currentOption = reactive({
-  total: 0,
-  page: 1,
-  limit: 10,
-  pageSizes: [10, 20, 40],
+import ToPrintDialog from "./toPrintTables.vue";
+// 传入一个url,后面不带/
+const { form, data, option, search, page, toDeleteIds, Methords, Utils } =
+  useCrud({
+    src: "/api/v1/quality/report",
+  });
+const { dataList, createRow, updateRow, deleteRow, searchChange, resetChange } =
+  Methords; //增删改查
+const { selectionChange, multipleDelete } = Methords; //选中和批量删除事件
+const { checkBtnPerm, downloadTemplate, exportData } = Utils; //按钮权限等工具
+const tablesData = ref([]);
+const crudRef = ref(null); //crudRef.value 获取avue-crud对象
+
+onMounted(() => {
+  // console.log("crudRef", crudRef)
+  dataList();
 });
-const getCurrentMonthStartAndEndDates = () => {
-  // 获取当前日期
-  let now = new Date();
-
-  // 获取当前月份的第一天
-  let startDate = new Date(now.getFullYear(), now.getMonth(), 1);
-
-  // 获取当前月份的最后一天
-  let endDate = new Date(now.getFullYear(), now.getMonth() + 1, 0);
-
-  // 格式化日期为'YYYY-MM-DD'格式
-  function formatDate(date) {
-    let year = date.getFullYear();
-    let month = String(date.getMonth() + 1).padStart(2, "0");
-    let day = String(date.getDate()).padStart(2, "0");
-    return `${year}-${month}-${day}`;
+const showStatus = ref(false);
+const importExcelData = () => {
+  if (uploadRef.value) {
+    uploadRef.value.show("/api/v1/plan/order/import");
   }
-
-  // 返回包含开始和结束日期的数组
-  return [formatDate(startDate), formatDate(endDate)];
 };
-const tableData = ref([]);
-// const getTableData = async () => {
-//   const { data } = await getData({
-//     pageNo: currentOption.page,
-//     pageSize: currentOption.limit,
-//     startTime: searchref.value.searchForm.time
-//       ? searchref.value.searchForm.time[0]
-//       : null,
-//     endTime: searchref.value.searchForm.time
-//       ? searchref.value.searchForm.time[1]
-//       : null,
-//     reportCode: searchref.value.searchForm.reportCode,
-//     reportName: searchref.value.searchForm.reportName,
-//     reportType: searchref.value.searchForm.reportType,
-//   });
-//   tableData.value = data.records;
-//   currentOption.total = data.totalCount;
-// };
 
-// mock数据
-const getTableData = async () => {
-  const { data } = await getMockData(); // 使用假数据函数
-  tableData.value = data.records;
-  currentOption.total = data.totalCount;
-  console.log(tableData.value);
-};
+const toPrintRef = ref(null);
 
-const toCancel = () => {
-  addStatus.value = false;
-  editStatus.value = false;
+const detail = ref({});
+const showDetail = (row) => {
+  // showStatus.value = true;
+  // detail.value = row;
+  toPrintRef.value && toPrintRef.value.openPrintDialog(row);
 };
 
-const formData = reactive({
-  reportCode: "",
-  rePortName: "",
-  rePortType: "",
-  creator: "",
-  prodtCode: "",
-  batchNo: "",
-  operationCode: "",
-});
-
-const addStatus = ref(false);
-const toAdd = () => {
-  reset();
-  addStatus.value = true;
-};
-const editStatus = ref(false);
-const toEdit = (row) => {
-  console.log(row);
-  editStatus.value = true;
-  formData.reportCode = row.reportCode;
-  formData.reportName = row.reportName;
-  formData.reportType = row.reportType;
-  formData.genDate = row.genDate;
-  formData.creator = row.creator;
-  formData.prodtCode = row.prodtCode;
-  formData.batchNo = row.batchNo;
-  formData.operationCode = row.operationCode;
-};
-
-const reset = () => {
-  formData.reportCode = "";
-  formData.reportName = "";
-  formData.reportType = "";
-  formData.creator = "";
-  formData.prodtCode = "";
-  formData.batchNo = "";
-  formData.operationCode = "";
-};
-
-const toSubmit = () => {
-  addStatus.value = false;
-  editStatus.value = false;
-};
-
-const reportTypeOptions = ref([
-  { label: "日报", value: "1" },
-  { label: "月报", value: "2" },
-]);
-const showStatus = ref(false);
-const searchOptons = [
-  {
-    label: "创建时间",
-    prop: "time",
-    type: "daterange",
-  },
-  {
-    label: "报告编号",
-    prop: "reportCode",
-    type: "input",
-  },
-  {
-    label: "报告名称",
-    prop: "reportName",
-    type: "input",
-  },
-  {
-    label: "报告类型",
-    prop: "reportType",
-    type: "select",
-    options: reportTypeOptions.value,
-  },
-];
-
-const opRef = ref(null);
-const openChoseForm = (type) => {
-  opRef.value.open(type);
-};
-
-//------------------
-const maxHeight = ref(null);
-const setHeight = () => {
-  maxHeight.value = document.querySelector(".table").clientHeight - 30;
-};
-onMounted(async () => {
-  searchref.value.searchForm.time = getCurrentMonthStartAndEndDates();
-  setHeight();
-  getTableData();
+// 设置表格列或者其他自定义的option
+option.value = Object.assign(option.value, {
+  searchEnter: true,
+  viewBtn: false,
+  column: [
+    {
+      label: "报告编号",
+      prop: "reportCode",
+      search: true,
+    },
+    {
+      label: "报告名称",
+      prop: "reportName",
+      search: true,
+    },
+    {
+      label: "报告类型",
+      prop: "reportType",
+      search: true,
+      type: "select", //类型为单选框
+      dicData: [
+        {
+          label: "日报",
+          value: "1",
+        },
+        {
+          label: "月报",
+          value: "2",
+        },
+      ],
+      value: "1",
+      control: (val, form) => {
+        if (val === "1") {
+          return {
+            generationDate: {
+              type: "date",
+              format: "YYYY年MM月DD日",
+              valueFormat: "YYYY-MM-DD",
+            },
+          };
+        } else {
+          return {
+            generationDate: {
+              type: "month",
+              format: "YYYY年MM月",
+              valueFormat: "YYYY-MM",
+            },
+          };
+        }
+      },
+    },
+    {
+      label: "日期",
+      prop: "generationDate",
+      type: "datetime",
+    },
+  ],
 });
 </script>
-
-<style scoped lang="scss">
-.btn {
-  height: 25px;
-}
-.container1 {
-  background-color: white;
-  width: 100%;
-  height: 100%;
-  padding: 20px;
-  display: flex;
-  flex-direction: column;
-  .header {
-    width: 100%;
-    height: auto;
-  }
-  .table {
-    flex: 1;
-    padding-bottom: 20px;
-    .tableheader {
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      margin: 10px 0px 10px 0px;
-    }
-  }
-}
-.formView {
-  width: 100%;
-  height: 100%;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-
-  .formTitle {
-    text-align: center;
-    font-size: 20px;
-    margin-bottom: 20px;
-  }
-
-  .formStyle {
-    width: 400px;
-  }
-}
-</style>

+ 387 - 0
src/views/statistic/report/index2.vue

@@ -0,0 +1,387 @@
+<template>
+  <div class="container1">
+    <div class="header" v-show="!addStatus && !editStatus">
+      <Search
+        ref="searchref"
+        :searchOptions="searchOptons"
+        @data-list="getTableData"
+      />
+    </div>
+    <div class="table" v-if="!addStatus && !editStatus">
+      <div class="tableheader">
+        <el-button type="primary" class="btn" @click="toAdd">新增</el-button>
+        <el-button class="btn" @click="exportFnc">导出</el-button>
+      </div>
+      <!-- <el-button class="btn" style="margin-bottom: 5px" @click="showPrint"
+        >打印</el-button
+      > -->
+      <el-table
+        :data="tableData"
+        border
+        :style="{ height: maxHeight - 40 + 'px' }"
+      >
+        <el-table-column prop="reportCode" label="报告编码" />
+        <el-table-column prop="reportName" label="报告名称" />
+        <el-table-column label="报告类型">
+          <template #default="{ row }">
+            {{ row.reportType === "1" ? "日报" : "月报" }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="genDate" label="生成日期" />
+        <el-table-column prop="creator" label="创建人" />
+        <el-table-column prop="created" label="创建时间" />
+        <el-table-column
+          align="center"
+          width="160"
+          prop=""
+          label="操作"
+          id="opear"
+        >
+          <template #default="{ row }">
+            <el-button
+              type="primary"
+              class="btn"
+              style="height: 25px"
+              @click="toEdit(row)"
+              link
+              >编辑</el-button
+            >
+            <el-button
+              type="primary"
+              class="btn"
+              style="height: 25px"
+              @click="showPrint(row)"
+              link
+              >查看</el-button
+            >
+            <el-button
+              type="info"
+              class="btn"
+              style="height: 25px"
+              link
+              @click="toDelete(row.id)"
+              >删除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+      <Pagination
+        :total="currentOption.total"
+        :page="currentOption.page"
+        :limit="currentOption.limit"
+        :pageSizes="currentOption.pageSizes"
+        v-model:page="currentOption.page"
+        v-model:limit="currentOption.limit"
+        @pagination="getData"
+      />
+    </div>
+    <div v-if="addStatus || editStatus" class="formView">
+      <div class="formTitle">
+        {{ addStatus ? "新增报告" : "编辑报告" }}
+      </div>
+      <el-scrollbar style="height: calc(100% - 60px)">
+        <el-form
+          ref="ruleFormRef"
+          :model="formData"
+          label-width="auto"
+          class="formStyle"
+        >
+          <el-form-item label="报告编码" prop="reportCode">
+            <el-input v-model="formData.reportCode" />
+          </el-form-item>
+          <el-form-item label="报告名称" prop="reportName">
+            <el-input v-model="formData.reportName" />
+          </el-form-item>
+          <el-form-item label="报告类型" prop="reportType">
+            <el-select v-model="formData.reportType">
+              <el-option
+                v-for="(item, index) in reportTypeOptions"
+                :key="index"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item
+            label="选择生成日期"
+            prop="genDate"
+            v-if="formData.reportType"
+          >
+            <el-date-picker
+              v-model="formData.genDate"
+              type="date"
+              placeholder="选择日期"
+              style="width: 100%"
+              value-format="YYYY-MM-DD"
+              v-if="formData.reportType == 1"
+            />
+            <el-date-picker
+              v-model="formData.genDate"
+              type="month"
+              value-format="YYYY-MM-DD"
+              placeholder="选择日期"
+              style="width: 100%"
+              v-if="formData.reportType == 2"
+            />
+          </el-form-item>
+          <!--          <el-form-item label="产品型号" prop="prodtCode">-->
+          <!--            <el-input-->
+          <!--              v-model="formData.prodtCode"-->
+          <!--              @click="openChoseForm('prodt')"-->
+          <!--            />-->
+          <!--          </el-form-item>-->
+          <!--          <el-form-item label="产品批次" prop="batchNo">-->
+          <!--            <el-input-->
+          <!--              v-model="formData.batchNo"-->
+          <!--              @click="openChoseForm('batch')"-->
+          <!--            />-->
+          <!--          </el-form-item>-->
+          <!--          <el-form-item label="产品工序" prop="operationCode">-->
+          <!--            <el-input-->
+          <!--              v-model="formData.operationCode"-->
+          <!--              @click="openChoseForm('operation')"-->
+          <!--            />-->
+          <!--          </el-form-item>-->
+          <!--          <el-form-item label="创建人" prop="creator">-->
+          <!--            <el-input v-model="formData.creator" />-->
+          <!--          </el-form-item>-->
+        </el-form>
+        <div style="display: flex; justify-content: space-evenly">
+          <el-button
+            type="primary"
+            style="margin-top: 10px"
+            class="btn"
+            @click="toSubmit"
+            >提交</el-button
+          >
+          <el-button
+            type="info"
+            style="margin-top: 10px"
+            class="btn"
+            @click="toCancel"
+            >取消</el-button
+          >
+        </div>
+      </el-scrollbar>
+    </div>
+    <reportTemplate v-model="showStatus" :tablesData="tablesData" />
+    <operationForm ref="opRef" />
+  </div>
+</template>
+
+<script setup>
+import Search from "@/components/Search/index.vue";
+import reportTemplate from "@/components/ReportView/reportTemplate.vue";
+import { useDictionaryStore } from "@/store";
+import { getData } from "@/api/report";
+import Pagination from "@/components/Pagination/index.vue";
+import { getMockData } from "@/api/statistic/reportMockData";
+import operationForm from "./operationForm.vue";
+const searchref = ref(null);
+const showPrint = () => {
+  showStatus.value = true;
+};
+const tablesData = ref([]);
+const toLook = (row) => {
+  const fullUrl = window.location.href;
+  const parts = fullUrl.split("/");
+  const thirdSlashIndex = 2;
+  const truncatedUrl = parts.slice(0, thirdSlashIndex + 1).join("/");
+  window.open(truncatedUrl + "/" + row.fileUrl, "_blank");
+};
+const currentOption = reactive({
+  total: 0,
+  page: 1,
+  limit: 10,
+  pageSizes: [10, 20, 40],
+});
+const getCurrentMonthStartAndEndDates = () => {
+  // 获取当前日期
+  let now = new Date();
+
+  // 获取当前月份的第一天
+  let startDate = new Date(now.getFullYear(), now.getMonth(), 1);
+
+  // 获取当前月份的最后一天
+  let endDate = new Date(now.getFullYear(), now.getMonth() + 1, 0);
+
+  // 格式化日期为'YYYY-MM-DD'格式
+  function formatDate(date) {
+    let year = date.getFullYear();
+    let month = String(date.getMonth() + 1).padStart(2, "0");
+    let day = String(date.getDate()).padStart(2, "0");
+    return `${year}-${month}-${day}`;
+  }
+
+  // 返回包含开始和结束日期的数组
+  return [formatDate(startDate), formatDate(endDate)];
+};
+const tableData = ref([]);
+// const getTableData = async () => {
+//   const { data } = await getData({
+//     pageNo: currentOption.page,
+//     pageSize: currentOption.limit,
+//     startTime: searchref.value.searchForm.time
+//       ? searchref.value.searchForm.time[0]
+//       : null,
+//     endTime: searchref.value.searchForm.time
+//       ? searchref.value.searchForm.time[1]
+//       : null,
+//     reportCode: searchref.value.searchForm.reportCode,
+//     reportName: searchref.value.searchForm.reportName,
+//     reportType: searchref.value.searchForm.reportType,
+//   });
+//   tableData.value = data.records;
+//   currentOption.total = data.totalCount;
+// };
+
+// mock数据
+const getTableData = async () => {
+  const { data } = await getMockData(); // 使用假数据函数
+  tableData.value = data.records;
+  currentOption.total = data.totalCount;
+  console.log(tableData.value);
+};
+
+const toCancel = () => {
+  addStatus.value = false;
+  editStatus.value = false;
+};
+
+const formData = reactive({
+  reportCode: "",
+  rePortName: "",
+  rePortType: "",
+  creator: "",
+  prodtCode: "",
+  batchNo: "",
+  operationCode: "",
+});
+
+const addStatus = ref(false);
+const toAdd = () => {
+  reset();
+  addStatus.value = true;
+};
+const editStatus = ref(false);
+const toEdit = (row) => {
+  console.log(row);
+  editStatus.value = true;
+  formData.reportCode = row.reportCode;
+  formData.reportName = row.reportName;
+  formData.reportType = row.reportType;
+  formData.genDate = row.genDate;
+  formData.creator = row.creator;
+  formData.prodtCode = row.prodtCode;
+  formData.batchNo = row.batchNo;
+  formData.operationCode = row.operationCode;
+};
+
+const reset = () => {
+  formData.reportCode = "";
+  formData.reportName = "";
+  formData.reportType = "";
+  formData.creator = "";
+  formData.prodtCode = "";
+  formData.batchNo = "";
+  formData.operationCode = "";
+};
+
+const toSubmit = () => {
+  addStatus.value = false;
+  editStatus.value = false;
+  console.log(formData);
+};
+
+const reportTypeOptions = ref([
+  { label: "日报", value: "1" },
+  { label: "月报", value: "2" },
+]);
+const showStatus = ref(false);
+const searchOptons = [
+  {
+    label: "创建时间",
+    prop: "time",
+    type: "daterange",
+  },
+  {
+    label: "报告编号",
+    prop: "reportCode",
+    type: "input",
+  },
+  {
+    label: "报告名称",
+    prop: "reportName",
+    type: "input",
+  },
+  {
+    label: "报告类型",
+    prop: "reportType",
+    type: "select",
+    options: reportTypeOptions.value,
+  },
+];
+
+const exportFnc = () => {};
+
+const opRef = ref(null);
+const openChoseForm = (type) => {
+  opRef.value.open(type);
+};
+
+//------------------
+const maxHeight = ref(null);
+const setHeight = () => {
+  maxHeight.value = document.querySelector(".table").clientHeight - 30;
+};
+onMounted(async () => {
+  searchref.value.searchForm.time = getCurrentMonthStartAndEndDates();
+  setHeight();
+  getTableData();
+});
+</script>
+
+<style scoped lang="scss">
+.btn {
+  height: 25px;
+}
+.container1 {
+  background-color: white;
+  width: 100%;
+  height: 100%;
+  padding: 20px;
+  display: flex;
+  flex-direction: column;
+  .header {
+    width: 100%;
+    height: auto;
+  }
+  .table {
+    flex: 1;
+    padding-bottom: 20px;
+    .tableheader {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin: 10px 0px 10px 0px;
+    }
+  }
+}
+.formView {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+
+  .formTitle {
+    text-align: center;
+    font-size: 20px;
+    margin-bottom: 20px;
+  }
+
+  .formStyle {
+    width: 400px;
+  }
+}
+</style>

+ 404 - 0
src/views/statistic/report/toPrintTables.vue

@@ -0,0 +1,404 @@
+<script setup lang="ts">
+import { ElMessageBox } from "element-plus";
+import {
+  consistencyTestData,
+  moduleScreeningData,
+  productAcceptanceData,
+} from "@/api/statistic/reportMockData";
+import { getQualityTableData } from "@/api/statistic/reportData";
+
+const detail = ref<any>({});
+
+const dialogVisible = ref(false);
+const tableData = ref([]);
+const openPrintDialog = (row) => {
+  dialogVisible.value = true;
+  console.info("openPrintDialog", row);
+  getQualityTableData(row).then((data) => {
+    tableData.value = data.data;
+  });
+  //   在这里调接口
+  detail.value = row;
+};
+
+const handleClose = (done: () => void) => {};
+defineExpose({
+  openPrintDialog: openPrintDialog,
+});
+</script>
+
+<template>
+  <el-dialog
+    v-model="dialogVisible"
+    width="1000"
+    append-to-body
+    align-center
+    :close-on-click-modal="false"
+  >
+    <div>
+      <el-scrollbar class="scroll-container">
+        <div id="print">
+          <div class="tableInfo">
+            <div style="page-break-after: always">
+              <div
+                class="title"
+                style="text-align: center"
+                v-if="detail.reportType == 1"
+              >
+                质量日报({{ detail.generationDate }})
+              </div>
+              <div
+                class="title"
+                style="text-align: center"
+                v-if="detail.reportType == 2"
+              >
+                质量月报({{ detail.generationDate }})
+              </div>
+
+              <div class="tableTitle">模块筛选情况</div>
+              <table v-for="(item, index) in tableData.filterList" :key="index" style="margin-top:10px">
+                <thead>
+                  <tr>
+                    <th rowspan="2">序号</th>
+                    <th id="lineId" rowspan="2">
+                      <span class="left-text">筛选项目</span>
+                      <span class="right-text">产品型号/检验批号</span>
+                      <svg xmlns="http://www.w3.org/2000/svg" class="xiexian">
+                        <path
+                          d="M 0 80 L 250 80 L 0 0 Z"
+                          stroke="rgba(0, 0, 0, 0.3)"
+                          stroke-width="1"
+                          fill="none"
+                        />
+                        <path
+                          d="M 0 80 L 250 80"
+                          stroke="rgba(0, 0, 0, 0.3)"
+                          stroke-width="1"
+                          fill="none"
+                        />
+                        <!-- 左边 -->
+                        <path
+                          d="M 250 80 L 0 0"
+                          stroke="rgba(0, 0, 0, 0.3)"
+                          stroke-width="1"
+                          fill="none"
+                        />
+                      </svg>
+                    </th>
+                    <th colspan="2" v-for="(itemCheck, index) in item.checkList">{{itemCheck.materialModel}} {{itemCheck.checkCode}}</th>
+                  </tr>
+                  <tr v-for="(itemCheck, index) in item.checkList">
+                    <th class="vertical-text">数量</th>
+                    <th class="vertical-text">剔除数</th>
+                  </tr>
+                </thead>
+                <tbody>
+                  <tr v-for="(itemOperation, index) in item.filterDetailList" :key="index" >
+                    <td style="text-align: center" v-for="(item, index) in itemOperation">{{ item }}</td>
+
+
+                  </tr>
+                </tbody>
+              </table>
+            </div>
+            <div style="page-break-after: always">
+              <div class="tableTitle" style="margin-top: 100px">
+                销售信息反馈
+              </div>
+              <table>
+                <thead>
+                  <tr>
+                    <th rowspan="2">日期</th>
+                    <th colspan="3">返回产品</th>
+                    <th rowspan="2">用户</th>
+                    <th rowspan="2">反馈内容</th>
+                    <th rowspan="2">原因</th>
+                    <th rowspan="2">纠正措施</th>
+                    <th rowspan="2">备注</th>
+                  </tr>
+                  <tr>
+                    <th>型号</th>
+                    <th>批次</th>
+                    <th>数量</th>
+                  </tr>
+                </thead>
+                <tbody>
+
+                  <tr v-for="(item, index) in tableData.salesReportList" :key="index">
+                    <td style="text-align: center">{{ item.created }}</td>
+                    <td style="text-align: center">{{ item.materialModel }}</td>
+                    <td style="text-align: center">{{ item.workOrderCode }}</td>
+                    <td style="text-align: center">{{ item.num }}</td>
+                    <td style="text-align: center">{{ item.customer }}</td>
+                    <td style="text-align: center">{{ item.remark1 }}</td>
+                    <td style="text-align: center">{{ item.remark3 }}</td>
+                    <td style="text-align: center">{{ item.remark4 }}</td>
+                    <td style="text-align: center">{{ item.remark }}</td>
+                  </tr>
+                </tbody>
+              </table>
+            </div>
+            <div style="page-break-after: always; margin-top: 50px">
+              <div class="tableTitle">成品率统计</div>
+              <table v-for="(item, index) in tableData.finishListList">
+                <thead >
+
+                  <tr >
+                    <th id="lineId" rowspan="2">
+                      <span class="right-text">产品分类</span>
+                      <span class="left-text">工序</span>
+                      <svg xmlns="http://www.w3.org/2000/svg" class="xiexian">
+                        <path
+                          d="M 0 80 L 250 80 L 0 0 Z"
+                          stroke="rgba(0, 0, 0, 0.3)"
+                          stroke-width="1"
+                          fill="none"
+                        />
+                        <path
+                          d="M 0 80 L 250 80"
+                          stroke="rgba(0, 0, 0, 0.3)"
+                          stroke-width="1"
+                          fill="none"
+                        />
+                        <!-- 左边 -->
+                        <path
+                          d="M 250 80 L 0 0"
+                          stroke="rgba(0, 0, 0, 0.3)"
+                          stroke-width="1"
+                          fill="none"
+                        />
+                      </svg>
+                    </th>
+                    <th  :colspan="index==0?3:4" v-for="(itemModel, index) in item.materialModelList">{{itemModel}}</th>
+                  </tr>
+                  <tr>
+                    <th class="vertical-text" v-for="(itemLine, index) in item.headLine">{{itemLine}}</th>
+
+                  </tr>
+
+                </thead>
+                <tbody>
+                  <tr v-for="(itemLine, index) in item.lineList" :key="index">
+                    <td v-for="(itemOp, index) in itemLine">{{itemOp}}</td>
+
+                  </tr>
+                  <tr>
+                    <td>备注</td>
+                    <td :colspan="item.num * 4-1" v-html="item.remark" style="text-align: center"></td>
+                  </tr>
+                </tbody>
+              </table>
+            </div>
+            <div class="tableTitle" style="margin-top: 50px">入库</div>
+<!--            <div class="info">
+              <div class="text">产品型号:</div>
+              <div class="text">产品批次:</div>
+              <div class="text">报告日期:2025年03月23日</div>
+            </div>-->
+            <table>
+              <thead>
+                <tr>
+                  <th>序号</th>
+                  <th>产品型号</th>
+                  <th>批号</th>
+                  <th>数量</th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr v-for="(item, index) in tableData.instockReportList" :key="index">
+                  <td style="text-align: center">{{ index+1 }}</td>
+                  <td style="text-align: center">{{ item.materialModel }}</td>
+                  <td style="text-align: center">{{ item.workOrderCode }}</td>
+                  <td style="text-align: center">{{ item.num }}</td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </div>
+      </el-scrollbar>
+    </div>
+    <template #header>
+      <div class="dialog-header">
+        <div>报告预览</div>
+        <el-button
+          type="primary"
+          size="small"
+          @click="dialogVisible = false"
+          v-print="'#print'"
+        >
+          打印
+        </el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<style scoped lang="scss">
+.dialog-header {
+  display: flex;
+  justify-content: start;
+  align-items: center;
+  gap: 20px;
+}
+
+.scroll-container {
+  height: calc(100vh - 200px);
+}
+
+#lineId {
+  width: 250px;
+  height: 81px;
+  position: relative;
+  padding: 0;
+  //background: #f2f2f2
+  //  url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiPjxsaW5lIHgxPSIwIiB5MT0iMCIgeDI9IjEwMCUiIHkyPSIxMDAlIiBzdHJva2U9ImJsYWNrIiBzdHJva2Utd2lkdGg9IjEiLz48L3N2Zz4=)
+  //  no-repeat 100% center;
+
+  .xiexian {
+    position: absolute;
+    left: 0;
+    top: 0;
+  }
+
+  .left-text {
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    line-height: 40px;
+    width: 70%;
+    text-align: start;
+    padding-left: 10px;
+  }
+
+  .right-text {
+    position: absolute;
+    right: 0;
+    top: 0;
+    line-height: 40px;
+    width: 70%;
+    text-align: end;
+    padding-right: 10px;
+  }
+}
+@media print {
+  #print {
+    position: absolute; /* 或 absolute, fixed, 根据需要调整 */
+    top: 20px; /* 调整顶部位置 */
+    margin: 0; /* 重置边距 */
+    width: 700px;
+  }
+}
+table {
+  width: 100%;
+  border-collapse: collapse; /* 合并表格边框 */
+}
+th,
+td {
+  border: 1px solid rgba(0, 0, 0, 0.3); /* 设置所有单元格的边框 */
+  //padding: 8px;
+  text-align: left;
+}
+th {
+  text-align: center;
+  background-color: #f2f2f2; /* 设置表头的背景颜色 */
+}
+
+.bgColor {
+  position: fixed;
+  width: 100vw;
+  height: 100vh;
+  z-index: 99999;
+  background-color: rgba(0, 0, 0, 0.3);
+  top: 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  left: 0;
+  .body {
+    width: 80%;
+    height: 85vh;
+    background-color: white;
+    display: flex;
+    flex-direction: column;
+    padding: 20px;
+    .header {
+      width: 100%;
+      height: 40px;
+      display: flex;
+      padding-bottom: 10px;
+      justify-content: space-between;
+      border-bottom: 1px solid rgba(0, 0, 0, 0.3);
+    }
+    .box {
+      height: calc(100% - 40px);
+    }
+  }
+}
+.tableInfo {
+  width: 100%;
+  height: 60px;
+
+  .tableTitle {
+    margin: 10px 0;
+    font-size: 20px;
+    font-weight: 600;
+    letter-spacing: 20px;
+    text-align: center;
+  }
+
+  .title {
+    margin: 10px 0;
+    font-size: 20px;
+    font-weight: 600;
+  }
+  .info {
+    display: flex;
+    padding: 0 20px;
+    justify-content: space-between;
+  }
+}
+
+.slash {
+  position: relative;
+}
+.slash::before {
+  content: "";
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  border-left: 1px solid #444;
+  transform: rotate(45deg);
+  transform-origin: 0 0;
+}
+.split-line {
+  border-bottom: 1px solid #444;
+  padding: 4px 0;
+}
+
+//上下分割成两行的
+.top-and-bottom {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: space-around;
+  border: 0;
+  .content {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+
+  .middle-line {
+    width: 100%;
+    height: 1px;
+    background-color: rgba(0, 0, 0, 0.3);
+  }
+}
+
+.vertical-text {
+  writing-mode: vertical-rl; /* 竖排从右到左 */
+  text-orientation: upright; /* 保持字符直立 */
+}
+</style>

+ 70 - 41
src/views/statistic/statistic/index.vue

@@ -6,7 +6,7 @@
           <div class="text">选择统计时间段:</div>
           <div style="display: flex">
             <el-date-picker
-              v-model="value1"
+              v-model="searTime"
               type="daterange"
               range-separator="-"
               start-placeholder="起始时间"
@@ -17,7 +17,7 @@
             />
           </div>
         </div>
-        <div class="header">
+<!--        <div class="header">
           <div class="text">选择统计维度:</div>
           <div>
             <el-radio-group v-model="radio" style="display: flex">
@@ -27,7 +27,7 @@
               <el-radio size="small" :value="4">年</el-radio>
             </el-radio-group>
           </div>
-        </div>
+        </div>-->
         <div class="header">
           <div class="text">选择统计维度:</div>
           <el-tree
@@ -62,7 +62,9 @@
             >
             <el-button class="btn" @click="reset">重置</el-button>
           </div>
-          <el-button class="btn" @click="exportFnc">导出</el-button>
+          <el-button class="ml-3" @click="exportData('/api/v1/quality/stat/quality/export')">
+            <template #icon> <i-ep-download /> </template>导出
+          </el-button>
         </div>
         <div class="info">
           <el-table
@@ -72,23 +74,28 @@
             style="width: calc(100% - 50)"
           >
             <el-table-column
-              v-if="queryIndexs.includes('productLine')"
+              v-if="queryTypes.includes('productLine')"
               prop="productLineName"
               label="产线名称"
             />
             <el-table-column
-              v-if="queryIndexs.includes('prodict')"
-              prop="materialName"
-              label="产品名称"
+                v-if="queryTypes.includes('workSection')"
+                prop="workSection"
+                label="工段名称"
             />
             <el-table-column
-              v-if="queryIndexs.includes('operation')"
+              v-if="queryTypes.includes('operation')"
               prop="operationName"
               label="工序名称"
             />
-            <el-table-column prop="goodRate" label="良率" />
-            <el-table-column prop="badRate" label="不良率" />
-            <el-table-column prop="timeStr" label="日期" />
+            <el-table-column prop="materialName" label="产品名称" />
+            <el-table-column prop="materialCode" label="产品编号" />
+              <el-table-column prop="materialModel" label="产品规格" />
+            <el-table-column  prop="produceNum" label="生产数量"  />
+            <el-table-column v-if="queryIndexs.includes('pass')" prop="qualified" label="合格率"  />
+            <el-table-column v-if="queryIndexs.includes('oneTimePassRate')" prop="oneTimePassRate" label="一次性合格率" />
+            <el-table-column v-if="queryIndexs.includes('PPM')" prop="ppm" label="PPM" />
+
           </el-table>
         </div>
         <div class="footer">
@@ -111,14 +118,21 @@
 import { getData, getStatLevel, getExport } from "@/api/statistic";
 import Pagination from "@/components/Pagination/index.vue";
 import { downFile } from "@/utils/common";
+import {getWorkInfoRate, getWorkOrderInfo} from "@/api/statistic/firstPassYieldData";
+import {useCrud} from "@/hooks/userCrud";
 defineOptions({
   name: "Dashboard",
   inheritAttrs: false,
 });
+const { form, data, option, search, page, toDeleteIds, Methords, Utils } =
+    useCrud({
+        src: "/api/v1/quality/stat",
+    });
+const { checkBtnPerm, downloadTemplate, exportData } = Utils;
 const exportFnc = async () => {
   await getExport({
-    endTime: value1.value ? value1.value[1] : "",
-    startTime: value1.value ? value1.value[0] : "",
+    endTime: searTime.value ? searTime.value[1] : "",
+    startTime: searTime.value ? searTime.value[0] : "",
     queryTypes: getValue(treeRef1.value.getCheckedNodes()),
     queryIndex: getValue(treeRef2.value.getCheckedNodes()),
     timeType: radio.value,
@@ -132,28 +146,12 @@ const currentOption = ref({
   limit: 10,
   pageSizes: [10, 20],
 });
-const data1 = [
-  {
-    value: "pass",
-    key: "合格率",
-    label: "合格率",
-  },
-  {
-    value: "oneTimePassRate",
-    key: "一次性送检合格率",
-    label: "一次性送检合格率",
-  },
-  {
-    value: "PPM",
-    key: "PPM",
-    label: "PPM",
-  },
-];
+
 const maxHeight = ref(null);
 const maxWidth = ref(null);
 
-const value1 = ref(null);
-const radio = ref(1);
+const searTime = ref(null);
+const radio = ref('1');
 const tableData = ref([]);
 
 const setHeight = () => {
@@ -189,28 +187,52 @@ const getValue = (array) => {
   return resarray;
 };
 const queryIndexs = ref([]);
+const queryTypes=ref([]);
 const getTableData = async () => {
-  queryIndexs.value = getValue(treeRef1.value.getCheckedNodes());
-  const { data } = await getData({
-    endTime: value1.value ? value1.value[1] : "",
-    startTime: value1.value ? value1.value[0] : "",
+  queryTypes.value = getValue(treeRef1.value.getCheckedNodes());
+  queryIndexs.value=getValue(treeRef2.value.getCheckedNodes());
+  const { data } = await getWorkInfoRate({
+    endTime: searTime.value ? searTime.value[1] : "",
+    startTime: searTime.value ? searTime.value[0] : "",
     pageNo: currentOption.value.page,
     pageSize: currentOption.value.limit,
     queryTypes: getValue(treeRef1.value.getCheckedNodes()),
     queryIndex: getValue(treeRef2.value.getCheckedNodes()),
-    timeType: radio.value,
   });
+    search.value.startTime=searTime.value[0];
+    search.value.endTime=searTime.value[1];
+    search.value.queryTypes=getValue(treeRef1.value.getCheckedNodes());
+    search.value.queryIndex=getValue(treeRef2.value.getCheckedNodes());
   tableData.value = data.records;
   currentOption.value.total = data.totalCount;
 };
+
 const reset = () => {
-  value1.value = getCurrentMonthStartAndEndDates();
+  console.log();
+  searTime.value = getCurrentMonthStartAndEndDates();
   treeRef1.value.setCheckedKeys(checkedKeys.value, true, true);
   treeRef2.value.setCheckedKeys([data1[0].key], true, true);
-  radio.value = 1;
+  radio.value = '1';
   currentOption.value.page = 1;
   getTableData();
 };
+const data1 = [
+  {
+    value: "pass",
+    key: "合格率",
+    label: "合格率",
+  },
+  {
+    value: "oneTimePassRate",
+    key: "一次性送检合格率",
+    label: "一次性送检合格率",
+  },
+  {
+    value: "PPM",
+    key: "PPM",
+    label: "PPM",
+  },
+];
 const statLevelData = ref([]);
 const getStatLevelData = async () => {
   const { data } = await getStatLevel();
@@ -229,9 +251,13 @@ const checkedKeys = computed(() => {
 
 onMounted(async () => {
   window.addEventListener("resize", setHeight);
-  value1.value = getCurrentMonthStartAndEndDates();
+  searTime.value = getCurrentMonthStartAndEndDates();
   setHeight();
   await getStatLevelData();
+    search.value.startTime=searTime.value[0];
+    search.value.endTime=searTime.value[1];
+    search.value.queryTypes=getValue(treeRef1.value.getCheckedNodes());
+    search.value.queryIndex=getValue(treeRef2.value.getCheckedNodes());
   getTableData();
 });
 </script>
@@ -256,6 +282,9 @@ onMounted(async () => {
       padding: 20px;
     }
   }
+  .el-radio {
+    display: block;
+  }
   .databox {
     width: calc(100% - 260px);
     border-left: 2px solid #00000010;

+ 162 - 0
src/views/unqualified/DetailCom.vue

@@ -0,0 +1,162 @@
+<template>
+  <div>
+    <div class="sale-header">不合格品(质量问题)分析评审处置表</div>
+    <div class="sale-right">编号: {{saleModel.formNo}}</div>
+    <table border-collapse="collapse">
+        <tr>
+          <td>产品型号</td>
+          <td>{{ saleModel.materialModel }}</td>
+          <td>产品分类</td>
+          <td>{{ saleModel.type }}</td>
+          <td>生产批号</td>
+          <td>{{ saleModel.workOrderCode }}</td>
+        </tr>
+      <tr>
+        <td>产品编号</td>
+        <td colspan="2" style="font-weight: normal;text-align: left;">{{ saleModel.seqs }}</td>
+        <td>数量</td>
+        <td colspan="2" style="font-weight: normal;">{{ saleModel.seqNum }}</td>
+      </tr>
+        <tr>
+          <td>器件名称及型号</td>
+          <td>{{ saleModel.componentName }}</td>
+          <td>器件检验批号或器件生产批号</td>
+          <td>{{ saleModel.checkProduceNo }}</td>
+          <td>数量</td>
+          <td>{{ saleModel.num }}</td>
+        </tr>
+      <tr>
+        <td>供方单位</td>
+        <td colspan="5" style="font-weight: normal;text-align: left;">{{ saleModel.company }}</td>
+      </tr>
+      <tr>
+        <td>审理级别</td>
+        <td v-if="saleModel.level === '0'">▣ 一级 ▢ 二级</td>
+        <td v-else>▢ 一级 ▣ 二级</td>
+        <td>发生阶段</td>
+        <td>{{ saleModel.stage }}</td>
+        <td>发生时间</td>
+        <td>{{ saleModel.happenTime }}</td>
+      </tr>
+        <tr v-for="(item, index) in contentArray" :key="index">
+          <td colspan="6">
+            <div class="sale-box">
+              <div class="sale-title">{{ item.title }}</div>
+              <div class="sale-content">
+                {{ item.content }}
+              </div>
+              <div class="sale-bottom">
+                <div class="desc" v-if="index === 0">填表人:{{ item[`user`] }}</div>
+                <div class="desc" v-if="index === 0">检验人员:{{ item[`user1`] }}</div>
+
+                <div class="desc" v-if="index === 1">技术人员:{{ item[`user1`] }}</div>
+                <div class="desc" v-if="index === 1">联系电话:{{ item[`phone`] }}</div>
+                <div class="desc" v-if="index === 1">责任部门:{{ item[`user2`] }}</div>
+
+                <div class="desc" v-if="index === 2">分析单位:{{ item[`company`] }}</div>
+
+                <div class="desc" v-if="index === 3">责任部门:{{saleModel.auditType === '1' ? item[`users`] : item[`user`]}}</div>
+
+
+                <div class="desc" v-if="index === 4">责任部门:{{ item[`user`] }}</div>
+                <div class="desc" v-if="index === 5">签字:{{ item[`user`] }}</div>
+                <div class="desc" v-if="index === 6">签字:{{ item[`user`] }}</div>
+                <div class="desc">时间: {{ item.time }}</div>
+              </div>
+            </div>
+          </td>
+        </tr>
+    </table>
+  </div>
+</template>
+
+<script setup>
+const saleModel = ref({});
+
+const contentArray = ref([]);
+const refreshView = (row) => {
+  saleModel.value = row;
+
+  contentArray.value = [];
+
+  if (row.remark1 && JSON.parse(row.remark1).content) {
+    let remark1 = JSON.parse(row.remark1);
+    contentArray.value.push({ ...remark1, title: "不合格现象(质量问题)描述:" });
+  }
+  if (row.remark2 && JSON.parse(row.remark2).content) {
+    let remark2 = JSON.parse(row.remark2);
+    contentArray.value.push({ ...remark2, title: "分析处置要求:" });
+  }
+  if (row.remark3 && JSON.parse(row.remark3).content) {
+    let remark3 = JSON.parse(row.remark3);
+    contentArray.value.push({ ...remark3, title: "原因分析:" });
+  }
+  if (row.remark4 && JSON.parse(row.remark4).content) {
+    let remark4 = JSON.parse(row.remark4);
+    contentArray.value.push({ ...remark4, title: "采取的措施:" });
+  }
+  if (row.remark5 && JSON.parse(row.remark5).content) {
+    let remark5 = JSON.parse(row.remark5);
+    contentArray.value.push({ ...remark5, title: "措施落实:" });
+  }
+  if (row.remark6 && JSON.parse(row.remark6).content) {
+    let remark6 = JSON.parse(row.remark6);
+    contentArray.value.push({ ...remark6, title: "不合格品评审(审理)处置意见:" });
+  }
+  if (row.remark7 && JSON.parse(row.remark7).content) {
+    let remark7 = JSON.parse(row.remark7);
+    contentArray.value.push({ ...remark7, title: "组长(或分管领导)审批意见:" });
+  }
+};
+
+defineExpose({ refreshView });
+</script>
+
+<style scoped lang="scss">
+.sale-header {
+  text-align: center;
+  font-size: 20px;
+  //font-weight: bold;
+  margin-bottom: 10px;
+}
+.sale-right {
+  text-align: right;
+  width: 800px;
+}
+table {
+  width: 800px;
+  margin: 0 auto;
+  border: 1px solid #000000;
+  border-collapse: collapse;
+}
+
+th,
+td {
+  border: 1px solid #000000;
+  text-align: center;
+  padding: 3px;
+}
+
+.sale-box {
+  .sale-title {
+    font-size: 16px;
+    margin-bottom: 5px;
+    text-align: start;
+  }
+  .sale-content {
+    font-size: 16px;
+    min-height: 60px;
+    margin-bottom: 10px;
+    text-align: start;
+    padding: 0 8px;
+  }
+  .sale-bottom {
+    display: flex;
+    justify-content: flex-end;
+    margin-top: 10px;
+  }
+  .desc {
+    margin-right: 20px;
+  }
+}
+</style>

+ 390 - 0
src/views/unqualified/add.vue

@@ -0,0 +1,390 @@
+<template>
+  <div>
+    <el-drawer v-model="drawerVisible" size="800" :close-on-click-modal="false">
+      <template #header>
+        <h4>新增不合格审理</h4>
+      </template>
+      <template #default>
+        <el-form
+          ref="baseInfoRef"
+          :model="saleForm"
+          label-width="120"
+          :rules="rules"
+          style="max-width: 600px"
+        >
+          <el-form-item label="订单信息">
+            <el-select
+              v-model="selectOrderCode"
+              value-key="orderNo"
+              placeholder="请选择订单信息"
+              style="width: 100%"
+              @change="orderSelect"
+            >
+              <el-option
+                v-for="item in orders"
+                :key="item.orderNo"
+                :label="item.orderName + `(批号: ${item.workOrderCode})`"
+                :value="item"
+              />
+            </el-select>
+          </el-form-item>
+<!--
+          <el-form-item label="检验批号" hidden>
+            <div>{{ selectedOrder.workOrderCode }}</div>
+          </el-form-item>-->
+          <el-form-item label="流转卡号" prop="seqs">
+            <el-select
+              v-model="saleForm.seqs"
+              value-key="orderCode"
+              placeholder="请选择流转卡号"
+              style="width: 100%"
+              multiple
+            >
+              <el-option
+                v-for="item in seqList"
+                :key="item.label"
+                :label="item.label"
+                :value="item.label"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="产品分类" prop="type">
+            <el-select
+                v-model="saleForm.type"
+                value-key="value"
+                placeholder="请选择产品分类"
+                style="width: 100%"
+            >
+              <el-option
+                  v-for="item in typeList"
+                  :key="item.dictValue"
+                  :label="item.dictLabel"
+                  :value="item.dictValue"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="器件名称及型号" prop="componentName">
+            <el-input v-model="saleForm.componentName" />
+          </el-form-item>
+          <el-form-item label="检验批号或生产批号" prop="checkProduceNo">
+            <el-input v-model="saleForm.checkProduceNo"></el-input>
+            <input v-model="saleForm.workOrderCode" hidden="true"/>
+          </el-form-item>
+          <el-form-item label="数量" prop="num">
+            <el-input v-model="saleForm.num" type="number"/>
+          </el-form-item>
+          <el-form-item label="供方单位" prop="company">
+            <el-input v-model="saleForm.company"/>
+          </el-form-item>
+          <el-form-item label="审核类型" prop="auditType">
+            <el-select
+                v-model="saleForm.auditType"
+                value-key="value"
+                placeholder="请选择审核类型"
+                style="width: 100%"
+            >
+              <el-option
+                  v-for="item in auditTypes"
+                  :key="item.dictValue"
+                  :label="item.dictLabel"
+                  :value="item.dictValue"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="审理级别" prop="level">
+            <el-select
+                v-model="saleForm.level"
+                value-key="value"
+                placeholder="请选择审理级别"
+                style="width: 100%"
+            >
+              <el-option
+                  v-for="item in levelTypes"
+                  :key="item.dictValue"
+                  :label="item.dictLabel"
+                  :value="item.dictValue"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="发生阶段" prop="stage">
+            <el-input v-model="saleForm.stage"/>
+          </el-form-item>
+          <el-form-item label="发生日期" prop="happenTime">
+            <el-date-picker
+                v-model="remark1.happenTime"
+                type="date"
+                :disabled-date="disabledDate1"
+                placeholder="请选择日期"
+                clearable
+                format="YYYY年MM月DD日"
+                value-format="YYYY年MM月DD日"
+                style="width: 100%"
+            />
+          </el-form-item>
+        </el-form>
+
+
+        <el-form
+          ref="remark1Ref"
+          :model="remark1"
+          label-width="120"
+          :rules="rules1"
+          style="max-width: 600px"
+        >
+          <el-form-item label="不合格现象(质量问题)描述" prop="content">
+            <el-input v-model="remark1.content" type="textarea" />
+          </el-form-item>
+          <el-form-item label="填表人" prop="user">
+<!--            <el-select
+              v-model="remark1.user"
+              placeholder="请选择"
+              style="width: 100%"
+            >
+              <el-option
+                v-for="item in userList"
+                :key="item.userName"
+                :label="item.userName"
+                :value="item.userName"
+              />
+            </el-select>-->
+            <el-tree-select
+                v-model="remark1.user"
+                :data="userList"
+                filterable
+            />
+          </el-form-item>
+          <el-form-item label="检验人" prop="user1">
+            <el-tree-select
+                v-model="remark1.user1"
+                :data="userList"
+                filterable
+            />
+          </el-form-item>
+          <el-form-item label="日期" prop="time">
+            <el-date-picker
+              v-model="remark1.time"
+              type="date"
+              :disabled-date="disabledDate"
+              placeholder="请选择日期"
+              clearable
+              format="YYYY年MM月DD日"
+              value-format="YYYY年MM月DD日"
+              style="width: 100%"
+            />
+          </el-form-item>
+          <el-form-item label="下一步处理人" prop="nextRemarkUser">
+            <el-tree-select
+                v-model="remark1.nextRemarkUser"
+                :data="userList"
+                filterable
+            />
+          </el-form-item>
+        </el-form>
+      </template>
+      <template #footer>
+        <div class="drawer-bottom">
+          <el-button @click="cancelClick">取消</el-button>
+          <el-button type="primary" @click="confirmClick">提交</el-button>
+        </div>
+      </template>
+    </el-drawer>
+  </div>
+</template>
+
+<script setup>
+import { addFeedback } from "@/api/unqualified/index";
+import { getOrderList } from "@/api/sales/index";
+import { getUserTree } from "@/api/user/index";
+import { useDictionaryStore } from "@/store";
+const drawerVisible = ref(false);
+const disabledDate = (time)=> {
+  //选择今天以及今天之后的日期
+  return time.getTime() < Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择
+  //选择今天以及今天之前的日期
+  //return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择今天的
+}
+const disabledDate1 = (time)=> {
+  //选择今天以及今天之后的日期
+  return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择
+  //选择今天以及今天之前的日期
+  //return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择今天的
+}
+const { dicts } = useDictionaryStore();
+const auditTypes = dicts.unqualified_audit_type
+const levelTypes = ref([
+  {dictValue: "0",dictLabel: "一级"},{dictValue: "1",dictLabel: "二级"}
+])
+const baseInfoRef = ref(null);
+const saleForm = reactive({
+  customer: "",
+  address: "",
+  contacts: "",
+  phoneNo: "",
+  stage: "",
+  seqs: [],
+});
+// 顾客投诉或建议
+const remark1Ref = ref(null);
+
+const remark1 = reactive({
+  content: "",
+  user: "",
+  time: "",
+  nextRemarkUser: "",
+});
+
+const rules = {
+  type: [
+    { required: true, message: "请选择产品分类", trigger: "blur" },
+  ],
+  componentName: [
+    { required: true, message: "请输入器件名称及型号", trigger: "blur" },
+  ],
+  num: [
+    { required: true, message: "请输入数量", trigger: "blur" },
+  ],
+  auditType: [
+    { required: true, message: "请选择审核类型", trigger: "blur" },
+  ],
+  seqs: [{ required: true, message: "请选择订单信息", trigger: "change" }],
+  checkProduceNo: [{ required: true, message: "请输入检验批号或生产批号", trigger: "change" }],
+  level: [{ required: true, message: "请选择审理级别", trigger: "change" }],
+  company: [{ required: true, message: "请输入供方单位", trigger: "change" }],
+  happenTime: [{ required: true, message: "请选择发生时间", trigger: "change" }],
+  stage: [{ required: true, message: "请输入发生阶段", trigger: "change" }],
+};
+const rules1 = {
+  content: [
+    { required: true, message: "请输入不合格现象(质量问题)描述", trigger: "blur" },
+    { min: 2, max: 200, message: "长度在 2 到 200 个字符", trigger: "blur" },
+  ],
+  user: [
+    { required: true, message: "请输入姓名", trigger: "blur" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+  user1:[{ required: true, message: "检验人员不能为空", trigger: "blur" }],
+  time: [{ required: true, message: "请选择日期", trigger: "change" }],
+  nextRemarkUser: [
+    { required: true, message: "请选择处理人", trigger: "change" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+};
+
+// 订单相关信息
+const orders = ref([]);
+const opOptions = ref([...dicts.spc_operation]);
+const typeList = dicts.sales_info_type
+const selectedOrder = ref({});
+const selectOrderCode = ref("");
+const getOrders = async () => {
+  const res = await getOrderList({
+    pageNo: 0,
+    pageSize: 200,
+  });
+  orders.value = res.data.records;
+  if (orders.value.length > 0) {
+    // selectOrderCode.value = orders.value[0].orderCode;
+    // selectedOrder.value = orders.value[0];
+  }
+};
+const orderSelect = (value) => {
+  selectedOrder.value = value;
+  seqList.value = selectedOrder.value.seqs.map((item, index) => ({ value: item, label: item }));
+  saleForm.seqs = [];
+};
+
+const seqList = ref([]);
+
+// 用户信息
+const userInfo = ref({});
+const userList = ref([]);
+const getUserInfo = async () => {
+  //const res = await getUserList();
+  //userList.value = res.data;
+  // if (userList.value.length > 0) {
+  //   userInfo.value = userList.value[0];
+  // }
+  getUserTree().then((data) => {
+    userList.value = data.data;
+  });
+};
+
+const showDrawer = () => {
+  selectedOrder.value = {};
+  selectOrderCode.value = {};
+  getOrders();
+  getUserInfo();
+  drawerVisible.value = true;
+};
+
+defineExpose({ showDrawer });
+
+const cancelClick = () => {
+  drawerVisible.value = false;
+  baseInfoRef.value.resetFields();
+  remark1Ref.value.resetFields();
+  selectedOrder.value = {};
+};
+
+const feedBackEmit = defineEmits(["finish"]);
+
+const confirmClick = () => {
+  console.log(saleForm);
+  console.log(remark1);
+  console.log(selectedOrder.value);
+
+  // drawerVisible.value = false;
+
+  //
+  // // 验证表单
+  baseInfoRef.value.validate((valid) => {
+    if (valid) {
+      console.log("baseInfoRef valid");
+    } else {
+      console.log("baseInfoRef invalid");
+      return false;
+    }
+  });
+  remark1Ref.value.validate((valid) => {
+    if (valid) {
+      let remark1Copy = {
+        content: remark1.content,
+        user: remark1.user,
+        user1: remark1.user1,
+        time: remark1.time,
+      };
+      let remark2 = {
+        content: "",
+        user2: remark1.nextRemarkUser,
+        time: "",
+      };
+
+      let p = {
+        ...saleForm,
+        ...selectedOrder.value,
+        currentUserName: remark1.nextRemarkUser,
+        remark1: JSON.stringify(remark1Copy),
+        remark2: JSON.stringify(remark2),
+      };
+
+      p.seqs = saleForm.seqs.join(",");
+
+      addFeedback(p).then(() => {
+        feedBackEmit("finish");
+        cancelClick();
+      });
+    } else {
+      console.log("remark1Ref invalid");
+      return false;
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+.drawer-bottom {
+  display: flex;
+  justify-content: flex-start;
+  align-items: center;
+}
+</style>

+ 39 - 0
src/views/unqualified/detail.vue

@@ -0,0 +1,39 @@
+<template>
+  <el-drawer v-model="drawerVisible" size="1000">
+    <template #header>
+      <div><el-button type="primary" v-print="'#print'">打印</el-button></div>
+    </template>
+
+    <div id="print">
+      <DetailCom ref="detailComRef"></DetailCom>
+    </div>
+  </el-drawer>
+</template>
+
+<script setup>
+import DetailCom from "@/views/unqualified/DetailCom.vue";
+
+const drawerVisible = ref(false);
+const detailComRef = ref(null);
+
+const showDrawer = (row) => {
+  drawerVisible.value = true;
+
+  nextTick(() => {
+    detailComRef.value && detailComRef.value.refreshView(row);
+  });
+};
+
+defineExpose({ showDrawer });
+</script>
+
+<style scoped lang="scss">
+@media print {
+  #print {
+    position: absolute; /* 或 absolute, fixed, 根据需要调整 */
+    top: 20px; /* 调整顶部位置 */
+    margin: 0; /* 重置边距 */
+    width: 1000px;
+  }
+}
+</style>

+ 266 - 0
src/views/unqualified/handle20.vue

@@ -0,0 +1,266 @@
+<template>
+  <el-drawer v-model="drawerVisible" size="1000">
+    <div>
+      <DetailCom ref="detailComRef"></DetailCom>
+    </div>
+
+    <el-form
+        ref="remarkRef"
+        :model="remark"
+        label-width="150"
+        :rules="rules1"
+        style="max-width: 600px; margin-left: 80px; margin-top: 20px"
+    >
+      <el-form-item label="分析处置要求:" prop="content2">
+        <el-input
+            v-model="remark.content2"
+            type="textarea"
+            :autosize="{ minRows: 3, maxRows: 6 }"
+        />
+      </el-form-item>
+      <el-form-item label="技术人员" prop="user1">
+        <el-tree-select
+            v-model="remark.user1"
+            :data="userList"
+            filterable
+        />
+      </el-form-item>
+      <el-form-item label="联系电话" prop="phone">
+        <el-input v-model="remark.phone" />
+      </el-form-item>
+      <el-form-item label="责任部门" prop="user2">
+        <el-tree-select
+            v-model="remark.user2"
+            :data="userList"
+            filterable
+        />
+      </el-form-item>
+      <el-form-item label="原因分析:" prop="content3">
+        <el-input
+            v-model="remark.content3"
+            type="textarea"
+            :autosize="{ minRows: 3, maxRows: 6 }"
+        />
+      </el-form-item>
+      <el-form-item label="分析单位:" prop="company">
+        <el-input v-model="remark.company" />
+      </el-form-item>
+      <el-form-item label="采取的措施:" prop="content4">
+        <el-input
+            v-model="remark.content4"
+            type="textarea"
+            :autosize="{ minRows: 3, maxRows: 6 }"
+        />
+      </el-form-item>
+      <el-form-item label="责任部门" prop="users">
+        <el-tree-select
+            v-model="remark.users"
+            :data="userList"
+            multiple
+            filterable
+        />
+      </el-form-item>
+
+      <el-form-item label="措施落实:" prop="content5">
+        <el-input
+            v-model="remark.content5"
+            type="textarea"
+            :autosize="{ minRows: 3, maxRows: 6 }"
+        />
+      </el-form-item>
+      <el-form-item label="责任部门" prop="user5">
+        <el-tree-select
+            v-model="remark.user5"
+            :data="userList"
+            filterable
+        />
+      </el-form-item>
+
+
+      <el-form-item label="下一步处理人" prop="nextRemarkUser" v-if="remark.state == 0">
+        <el-tree-select
+            v-model="remark.nextRemarkUser"
+            :data="userList"
+            filterable
+        />
+      </el-form-item>
+      <el-form-item label="是否通过" prop="state">
+        <el-radio-group v-model="remark.state">
+          <el-radio :value="0">同意</el-radio>
+          <el-radio :value="1">不同意</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <div class="drawer-bottom">
+        <el-button @click="cancelClick">取消</el-button>
+        <el-button type="primary" @click="confirmClick">提交</el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup>
+import DetailCom from "@/views/unqualified/DetailCom.vue";
+import { dealFeedback } from "@/api/unqualified/index";
+import { getUserTree } from "@/api/user/index";
+import {useUserStore} from "@/store";
+const drawerVisible = ref(false);
+const detailComRef = ref(null);
+const saleModel = ref({});
+const userStore = useUserStore();
+const showDrawer = (row) => {
+  drawerVisible.value = true;
+  saleModel.value = row;
+
+  nextTick(() => {
+    detailComRef.value && detailComRef.value.refreshView(row);
+  });
+
+  getUserInfo();
+};
+const disabledDate = (time)=> {
+  //选择今天以及今天之后的日期
+  return time.getTime() < Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择
+  //选择今天以及今天之前的日期
+  //return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择今天的
+}
+const rules1 = {
+  content2: [
+    { required: true, message: "请输入分析处置要求", trigger: "blur" },
+    { min: 2, max: 200, message: "长度在 2 到 200 个字符", trigger: "blur" },
+  ],
+  content3: [
+    { required: true, message: "请输入原因分析", trigger: "blur" },
+    { min: 2, max: 200, message: "长度在 2 到 200 个字符", trigger: "blur" },
+  ],
+  content4: [
+    { required: true, message: "请输入采取的措施", trigger: "blur" },
+    { min: 2, max: 200, message: "长度在 2 到 200 个字符", trigger: "blur" },
+  ],
+  content5: [
+    { required: true, message: "请输入措施落实", trigger: "blur" },
+    { min: 2, max: 200, message: "长度在 2 到 200 个字符", trigger: "blur" },
+  ],
+  users: [
+    { required: true, message: "请选择人员", trigger: "blur" },
+  ],
+  user1: [
+    { required: true, message: "请选择人员", trigger: "blur" },
+  ],
+  user2: [
+    { required: true, message: "请选择人员", trigger: "blur" },
+  ],
+  user5: [
+    { required: true, message: "请选择人员", trigger: "blur" },
+  ],
+  phone: [
+    { required: true, message: "请输入电话", trigger: "blur" },
+    { min: 11, max: 11, message: "长度在11个字符", trigger: "blur" },
+  ],
+  company: [{ required: true, message: "请输入分析单位", trigger: "change" }],
+  nextRemarkUser: [
+    { required: true, message: "请选择处理人", trigger: "change" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+};
+
+defineExpose({ showDrawer });
+
+const remarkRef = ref(null);
+
+const remark = reactive({
+  content: "",
+  user: "",
+  time: "",
+  nextRemarkUser: "",
+  state: 0,
+});
+
+const cancelClick = () => {
+  drawerVisible.value = false;
+
+  remarkRef.value.resetFields();
+};
+
+const feedBackEmit = defineEmits(["finish"]);
+
+// 用户信息
+const userInfo = ref({});
+const userList = ref([]);
+const getUserInfo = async () => {
+  getUserTree().then((data) => {
+    userList.value = data.data;
+  });
+};
+
+const confirmClick = () => {
+  const date = new Date();
+  const now = date.getFullYear() + "年" + date.getMonth() + "月" + date.getDate() + "日"
+  remark.user = userStore.user.username;
+  remarkRef.value.validate((valid) => {
+    if (valid) {
+      let remark2Copy = {
+        content: remark.content2,
+        user: remark.user,
+        time: now,
+        user1: remark.user1,
+        user2: remark.user2,
+        phone: remark.phone,
+        state: remark.state,
+      };
+      let remark3 = {
+        content: remark.content3,
+        company: remark.company,
+        time: now,
+      };
+      let remark4 = {
+        content: remark.content4,
+        users: remark.users.join(","),
+        time: now,
+      };
+      let remark5 = {
+        content: remark.content5,
+        user: remark.user5,
+        time: now,
+      };
+      let remark6 = {
+        content: '',
+        user: remark.nextRemarkUser,
+      };
+
+      let p = {
+        id: saleModel.value.id,
+        remark2: JSON.stringify(remark2Copy),
+        remark3: JSON.stringify(remark3),
+        remark4: JSON.stringify(remark4),
+        remark5: JSON.stringify(remark5),
+        currentUserName: remark.nextRemarkUser,
+        remark6: JSON.stringify(remark6),
+        state: remark.state,
+        step: 1, //步骤 1 投书或建议处置意见 2 整改及纠正措施验证 3 处置情况的反馈意见
+      };
+
+      dealFeedback(p).then(() => {
+        feedBackEmit("finish");
+        cancelClick();
+      });
+    } else {
+      console.log("remarkRef invalid");
+      return false;
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+@media print {
+  #print {
+    position: absolute; /* 或 absolute, fixed, 根据需要调整 */
+    top: 20px; /* 调整顶部位置 */
+    margin: 0; /* 重置边距 */
+    width: 1000px;
+  }
+}
+</style>

+ 187 - 0
src/views/unqualified/handle21.vue

@@ -0,0 +1,187 @@
+<template>
+  <el-drawer v-model="drawerVisible" size="1000">
+    <div>
+      <DetailCom ref="detailComRef"></DetailCom>
+    </div>
+
+    <el-form
+        ref="remarkRef"
+        :model="remark"
+        label-width="150"
+        :rules="rules1"
+        style="max-width: 600px; margin-left: 80px; margin-top: 20px"
+    >
+      <el-form-item label="分析处置要求" prop="content">
+        <el-input
+            v-model="remark.content"
+            type="textarea"
+            :autosize="{ minRows: 3, maxRows: 6 }"
+        />
+      </el-form-item>
+      <el-form-item label="技术人员" prop="user1">
+        <el-tree-select
+            v-model="remark.user1"
+            :data="userList"
+            filterable
+        />
+      </el-form-item>
+      <el-form-item label="联系电话" prop="phone">
+        <el-input v-model="remark.phone" />
+      </el-form-item>
+      <el-form-item label="责任部门" prop="user2">
+        <el-tree-select
+            v-model="remark.user2"
+            :data="userList"
+            filterable
+        />
+      </el-form-item>
+
+      <el-form-item label="下一步处理人" prop="nextRemarkUser" v-if="remark.state == 0">
+        <el-tree-select
+            v-model="remark.nextRemarkUser"
+            :data="userList"
+            filterable
+        />
+      </el-form-item>
+      <el-form-item label="是否通过" prop="state">
+        <el-radio-group v-model="remark.state">
+          <el-radio :value="0">同意</el-radio>
+          <el-radio :value="1">不同意</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <div class="drawer-bottom">
+        <el-button @click="cancelClick">取消</el-button>
+        <el-button type="primary" @click="confirmClick">提交</el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup>
+import DetailCom from "@/views/unqualified/DetailCom.vue";
+import { dealFeedback} from "@/api/unqualified/index";
+import { getUserTree } from "@/api/user/index";
+import {useUserStore} from "@/store";
+const drawerVisible = ref(false);
+const detailComRef = ref(null);
+const saleModel = ref({});
+const userStore = useUserStore();
+const disabledDate = (time)=> {
+  //选择今天以及今天之后的日期
+  return time.getTime() < Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择
+  //选择今天以及今天之前的日期
+  //return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择今天的
+}
+const showDrawer = (row) => {
+  drawerVisible.value = true;
+  saleModel.value = row;
+
+  nextTick(() => {
+    detailComRef.value && detailComRef.value.refreshView(row);
+  });
+
+  getUserInfo();
+};
+
+const rules1 = {
+  content: [
+    { required: true, message: "请输入投诉或建议处置意见", trigger: "blur" },
+    { min: 2, max: 200, message: "长度在 2 到 200 个字符", trigger: "blur" },
+  ],
+  user1: [
+    { required: true, message: "请输入姓名", trigger: "blur" },
+  ],
+  user2: [
+    { required: true, message: "请输入姓名", trigger: "blur" },
+  ],
+
+  phone: [{ required: true, message: "请输入联系电话", trigger: "change" }],
+  nextRemarkUser: [
+    { required: true, message: "请选择处理人", trigger: "change" },
+  ],
+};
+
+defineExpose({ showDrawer });
+
+const remarkRef = ref(null);
+
+const remark = reactive({
+  content: "",
+  user: "",
+  time: "",
+  nextRemarkUser: "",
+  state: 0,
+});
+
+const cancelClick = () => {
+  drawerVisible.value = false;
+
+  remarkRef.value.resetFields();
+};
+
+const feedBackEmit = defineEmits(["finish"]);
+
+// 用户信息
+const userInfo = ref({});
+const userList = ref([]);
+const getUserInfo = async () => {
+  getUserTree().then((data) => {
+    userList.value = data.data;
+  });
+};
+
+const confirmClick = () => {
+  const date = new Date();
+  const now = date.getFullYear() + "年" + date.getMonth() + "月" + date.getDate() + "日"
+  remark.user = userStore.user.username;
+  remarkRef.value.validate((valid) => {
+    if (valid) {
+      let remark2Copy = {
+        content: remark.content,
+        user: remark.user,
+        user1: remark.user1,
+        user2: remark.user2,
+        phone: remark.phone,
+        time: now,
+        state: remark.state,
+      };
+      let remark3 = {
+        content: "",
+        user: remark.nextRemarkUser, // qinhaibo和dengyu说是user1234的
+        time: "",
+      };
+
+      let p = {
+        id: saleModel.value.id,
+        remark2: JSON.stringify(remark2Copy),
+        remark3: JSON.stringify(remark3),
+        currentUserName: remark.nextRemarkUser,
+        state: remark.state,
+        step: 3, //步骤 1 投书或建议处置意见 2 整改及纠正措施验证 3 处置情况的反馈意见
+      };
+
+      dealFeedback(p).then(() => {
+        feedBackEmit("finish");
+        cancelClick();
+      });
+    } else {
+      console.log("remarkRef invalid");
+      return false;
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+@media print {
+  #print {
+    position: absolute; /* 或 absolute, fixed, 根据需要调整 */
+    top: 20px; /* 调整顶部位置 */
+    margin: 0; /* 重置边距 */
+    width: 1000px;
+  }
+}
+</style>

+ 171 - 0
src/views/unqualified/handle3.vue

@@ -0,0 +1,171 @@
+<template>
+  <el-drawer v-model="drawerVisible" size="1000">
+    <div>
+      <DetailCom ref="detailComRef"></DetailCom>
+    </div>
+
+    <el-form
+      ref="remarkRef"
+      :model="remark"
+      label-width="150"
+      :rules="rules1"
+      style="max-width: 600px; margin-left: 80px; margin-top: 20px"
+    >
+      <el-form-item label="原因分析" prop="content">
+        <el-input
+          v-model="remark.content"
+          type="textarea"
+          :autosize="{ minRows: 3, maxRows: 6 }"
+        />
+      </el-form-item>
+
+      <el-form-item label="分析单位" prop="company">
+        <el-input
+            v-model="remark.company"
+        />
+      </el-form-item>
+      <el-form-item label="下一步处理人" prop="nextRemarkUser" v-if="remark.state == 0">
+        <el-tree-select
+            v-model="remark.nextRemarkUser"
+            :data="userList"
+            filterable
+        />
+      </el-form-item>
+      <el-form-item label="是否通过" prop="state">
+        <el-radio-group v-model="remark.state">
+          <el-radio :value="0">同意</el-radio>
+          <el-radio :value="1">不同意</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <div class="drawer-bottom">
+        <el-button @click="cancelClick">取消</el-button>
+        <el-button type="primary" @click="confirmClick">提交</el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup>
+import DetailCom from "@/views/unqualified/DetailCom.vue";
+import { dealFeedback} from "@/api/unqualified/index";
+import { getUserTree } from "@/api/user/index";
+import {useUserStore} from "@/store";
+const drawerVisible = ref(false);
+const detailComRef = ref(null);
+const saleModel = ref({});
+const userStore = useUserStore();
+const disabledDate = (time)=> {
+  //选择今天以及今天之后的日期
+  return time.getTime() < Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择
+  //选择今天以及今天之前的日期
+  //return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择今天的
+}
+const showDrawer = (row) => {
+  drawerVisible.value = true;
+  saleModel.value = row;
+
+  nextTick(() => {
+    detailComRef.value && detailComRef.value.refreshView(row);
+  });
+
+  getUserInfo();
+};
+
+const rules1 = {
+  content: [
+    { required: true, message: "请输入投诉或建议处置意见", trigger: "blur" },
+    { min: 2, max: 200, message: "长度在 2 到 200 个字符", trigger: "blur" },
+  ],
+  user: [
+    { required: true, message: "请输入姓名", trigger: "blur" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+  company: [{ required: true, message: "请输入分析单位", trigger: "change" }],
+  nextRemarkUser: [
+    { required: true, message: "请选择处理人", trigger: "change" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+};
+
+defineExpose({ showDrawer });
+
+const remarkRef = ref(null);
+
+const remark = reactive({
+  content: "",
+  user: "",
+  time: "",
+  nextRemarkUser: "",
+  state: 0,
+});
+
+const cancelClick = () => {
+  drawerVisible.value = false;
+
+  remarkRef.value.resetFields();
+};
+
+const feedBackEmit = defineEmits(["finish"]);
+
+// 用户信息
+const userInfo = ref({});
+const userList = ref([]);
+const getUserInfo = async () => {
+  getUserTree().then((data) => {
+    userList.value = data.data;
+  });
+};
+
+const confirmClick = () => {
+  const date = new Date();
+  const now = date.getFullYear() + "年" + date.getMonth() + "月" + date.getDate() + "日"
+  remark.user = userStore.user.username;
+  remarkRef.value.validate((valid) => {
+    if (valid) {
+      let remark2Copy = {
+        content: remark.content,
+        user: remark.user,
+        time: now,
+        company: remark.company,
+        state: remark.state,
+      };
+      let remark3 = {
+        content: "",
+        user: remark.nextRemarkUser, // qinhaibo和dengyu说是user1234的
+        time: "",
+      };
+
+      let p = {
+        id: saleModel.value.id,
+        remark3: JSON.stringify(remark2Copy),
+        remark4: JSON.stringify(remark3),
+        currentUserName: remark.nextRemarkUser,
+        state: remark.state,
+        step: 3, //步骤 1 投书或建议处置意见 2 整改及纠正措施验证 3 处置情况的反馈意见
+      };
+
+      dealFeedback(p).then(() => {
+        feedBackEmit("finish");
+        cancelClick();
+      });
+    } else {
+      console.log("remarkRef invalid");
+      return false;
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+@media print {
+  #print {
+    position: absolute; /* 或 absolute, fixed, 根据需要调整 */
+    top: 20px; /* 调整顶部位置 */
+    margin: 0; /* 重置边距 */
+    width: 1000px;
+  }
+}
+</style>

+ 172 - 0
src/views/unqualified/handle4.vue

@@ -0,0 +1,172 @@
+<template>
+  <el-drawer v-model="drawerVisible" size="1000">
+    <div>
+      <DetailCom ref="detailComRef"></DetailCom>
+    </div>
+
+    <el-form
+        ref="remarkRef"
+        :model="remark"
+        label-width="150"
+        :rules="rules1"
+        style="max-width: 600px; margin-left: 80px; margin-top: 20px"
+    >
+      <el-form-item label="采取的措施" prop="content">
+        <el-input
+            v-model="remark.content"
+            type="textarea"
+            :autosize="{ minRows: 3, maxRows: 6 }"
+        />
+      </el-form-item>
+
+<!--      <el-form-item label="责任部门" prop="user">
+        <el-tree-select
+            v-model="remark.user"
+            :data="userList"
+            filterable
+        />
+      </el-form-item>-->
+      <el-form-item label="下一步处理人" prop="nextRemarkUser" v-if="remark.state == 0">
+        <el-tree-select
+            v-model="remark.nextRemarkUser"
+            :data="userList"
+            filterable
+        />
+      </el-form-item>
+      <el-form-item label="是否通过" prop="state">
+        <el-radio-group v-model="remark.state">
+          <el-radio :value="0">同意</el-radio>
+          <el-radio :value="1">不同意</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <div class="drawer-bottom">
+        <el-button @click="cancelClick">取消</el-button>
+        <el-button type="primary" @click="confirmClick">提交</el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup>
+import DetailCom from "@/views/unqualified/DetailCom.vue";
+import { dealFeedback} from "@/api/unqualified/index";
+import { getUserTree } from "@/api/user/index";
+import {useUserStore} from "@/store";
+const drawerVisible = ref(false);
+const detailComRef = ref(null);
+const saleModel = ref({});
+const userStore = useUserStore();
+const disabledDate = (time)=> {
+  //选择今天以及今天之后的日期
+  return time.getTime() < Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择
+  //选择今天以及今天之前的日期
+  //return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择今天的
+}
+const showDrawer = (row) => {
+  drawerVisible.value = true;
+  saleModel.value = row;
+
+  nextTick(() => {
+    detailComRef.value && detailComRef.value.refreshView(row);
+  });
+
+  getUserInfo();
+};
+
+const rules1 = {
+  content: [
+    { required: true, message: "请输入投诉或建议处置意见", trigger: "blur" },
+    { min: 2, max: 200, message: "长度在 2 到 200 个字符", trigger: "blur" },
+  ],
+  user: [
+    { required: true, message: "请输入姓名", trigger: "blur" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+  time: [{ required: true, message: "请选择日期", trigger: "change" }],
+  nextRemarkUser: [
+    { required: true, message: "请选择处理人", trigger: "change" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+};
+
+defineExpose({ showDrawer });
+
+const remarkRef = ref(null);
+
+const remark = reactive({
+  content: "",
+  user: "",
+  time: "",
+  nextRemarkUser: "",
+  state: 0,
+});
+
+const cancelClick = () => {
+  drawerVisible.value = false;
+
+  remarkRef.value.resetFields();
+};
+
+const feedBackEmit = defineEmits(["finish"]);
+
+// 用户信息
+const userInfo = ref({});
+const userList = ref([]);
+const getUserInfo = async () => {
+  getUserTree().then((data) => {
+    userList.value = data.data;
+  });
+};
+
+const confirmClick = () => {
+  const date = new Date();
+  const now = date.getFullYear() + "年" + date.getMonth() + "月" + date.getDate() + "日"
+  remark.user = userStore.user.username;
+  remarkRef.value.validate((valid) => {
+    if (valid) {
+      let remark2Copy = {
+        content: remark.content,
+        user: remark.user,
+        time: now,
+        state: remark.state,
+      };
+      let remark3 = {
+        content: "",
+        user: remark.nextRemarkUser, // qinhaibo和dengyu说是user1234的
+        time: "",
+      };
+
+      let p = {
+        id: saleModel.value.id,
+        remark4: JSON.stringify(remark2Copy),
+        remark5: JSON.stringify(remark3),
+        currentUserName: remark.nextRemarkUser,
+        state: remark.state,
+        step: 4, //步骤 1 投书或建议处置意见 2 整改及纠正措施验证 3 处置情况的反馈意见
+      };
+
+      dealFeedback(p).then(() => {
+        feedBackEmit("finish");
+        cancelClick();
+      });
+    } else {
+      console.log("remarkRef invalid");
+      return false;
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+@media print {
+  #print {
+    position: absolute; /* 或 absolute, fixed, 根据需要调整 */
+    top: 20px; /* 调整顶部位置 */
+    margin: 0; /* 重置边距 */
+    width: 1000px;
+  }
+}
+</style>

+ 172 - 0
src/views/unqualified/handle5.vue

@@ -0,0 +1,172 @@
+<template>
+  <el-drawer v-model="drawerVisible" size="1000">
+    <div>
+      <DetailCom ref="detailComRef"></DetailCom>
+    </div>
+
+    <el-form
+        ref="remarkRef"
+        :model="remark"
+        label-width="150"
+        :rules="rules1"
+        style="max-width: 600px; margin-left: 80px; margin-top: 20px"
+    >
+      <el-form-item label="措施落实" prop="content">
+        <el-input
+            v-model="remark.content"
+            type="textarea"
+            :autosize="{ minRows: 3, maxRows: 6 }"
+        />
+      </el-form-item>
+
+      <!--      <el-form-item label="责任部门" prop="user">
+              <el-tree-select
+                  v-model="remark.user"
+                  :data="userList"
+                  filterable
+              />
+            </el-form-item>-->
+      <el-form-item label="下一步处理人" prop="nextRemarkUser" v-if="remark.state == 0">
+        <el-tree-select
+            v-model="remark.nextRemarkUser"
+            :data="userList"
+            filterable
+        />
+      </el-form-item>
+      <el-form-item label="是否通过" prop="state">
+        <el-radio-group v-model="remark.state">
+          <el-radio :value="0">同意</el-radio>
+          <el-radio :value="1">不同意</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <div class="drawer-bottom">
+        <el-button @click="cancelClick">取消</el-button>
+        <el-button type="primary" @click="confirmClick">提交</el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup>
+import DetailCom from "@/views/unqualified/DetailCom.vue";
+import { dealFeedback} from "@/api/unqualified/index";
+import { getUserTree } from "@/api/user/index";
+import {useUserStore} from "@/store";
+const drawerVisible = ref(false);
+const detailComRef = ref(null);
+const saleModel = ref({});
+const userStore = useUserStore();
+const disabledDate = (time)=> {
+  //选择今天以及今天之后的日期
+  return time.getTime() < Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择
+  //选择今天以及今天之前的日期
+  //return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择今天的
+}
+const showDrawer = (row) => {
+  drawerVisible.value = true;
+  saleModel.value = row;
+
+  nextTick(() => {
+    detailComRef.value && detailComRef.value.refreshView(row);
+  });
+
+  getUserInfo();
+};
+
+const rules1 = {
+  content: [
+    { required: true, message: "请输入投诉或建议处置意见", trigger: "blur" },
+    { min: 2, max: 200, message: "长度在 2 到 200 个字符", trigger: "blur" },
+  ],
+  user: [
+    { required: true, message: "请输入姓名", trigger: "blur" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+  time: [{ required: true, message: "请选择日期", trigger: "change" }],
+  nextRemarkUser: [
+    { required: true, message: "请选择处理人", trigger: "change" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+};
+
+defineExpose({ showDrawer });
+
+const remarkRef = ref(null);
+
+const remark = reactive({
+  content: "",
+  user: "",
+  time: "",
+  nextRemarkUser: "",
+  state: 0,
+});
+
+const cancelClick = () => {
+  drawerVisible.value = false;
+
+  remarkRef.value.resetFields();
+};
+
+const feedBackEmit = defineEmits(["finish"]);
+
+// 用户信息
+const userInfo = ref({});
+const userList = ref([]);
+const getUserInfo = async () => {
+  getUserTree().then((data) => {
+    userList.value = data.data;
+  });
+};
+
+const confirmClick = () => {
+  const date = new Date();
+  const now = date.getFullYear() + "年" + date.getMonth() + "月" + date.getDate() + "日"
+  remark.user = userStore.user.username;
+  remarkRef.value.validate((valid) => {
+    if (valid) {
+      let remark2Copy = {
+        content: remark.content,
+        user: remark.user,
+        time: now,
+        state: remark.state,
+      };
+      let remark3 = {
+        content: "",
+        user: remark.nextRemarkUser, // qinhaibo和dengyu说是user1234的
+        time: "",
+      };
+
+      let p = {
+        id: saleModel.value.id,
+        remark5: JSON.stringify(remark2Copy),
+        remark6: JSON.stringify(remark3),
+        state: remark.state,
+        currentUserName: remark.nextRemarkUser,
+        step: 5, //步骤 1 投书或建议处置意见 2 整改及纠正措施验证 3 处置情况的反馈意见
+      };
+
+      dealFeedback(p).then(() => {
+        feedBackEmit("finish");
+        cancelClick();
+      });
+    } else {
+      console.log("remarkRef invalid");
+      return false;
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+@media print {
+  #print {
+    position: absolute; /* 或 absolute, fixed, 根据需要调整 */
+    top: 20px; /* 调整顶部位置 */
+    margin: 0; /* 重置边距 */
+    width: 1000px;
+  }
+}
+</style>

+ 165 - 0
src/views/unqualified/handle6.vue

@@ -0,0 +1,165 @@
+<template>
+  <el-drawer v-model="drawerVisible" size="1000">
+    <div>
+      <DetailCom ref="detailComRef"></DetailCom>
+    </div>
+
+    <el-form
+        ref="remarkRef"
+        :model="remark"
+        label-width="150"
+        :rules="rules1"
+        style="max-width: 600px; margin-left: 80px; margin-top: 20px"
+    >
+      <el-form-item label="不合格品评审(审理)处置意见" prop="content">
+        <el-input
+            v-model="remark.content"
+            type="textarea"
+            :autosize="{ minRows: 3, maxRows: 6 }"
+        />
+      </el-form-item>
+
+      <el-form-item label="下一步处理人" prop="nextRemarkUser" v-if="remark.state == 0">
+        <el-tree-select
+            v-model="remark.nextRemarkUser"
+            :data="userList"
+            filterable
+        />
+      </el-form-item>
+      <el-form-item label="是否通过" prop="state">
+        <el-radio-group v-model="remark.state">
+          <el-radio :value="0">同意</el-radio>
+          <el-radio :value="1">不同意</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <div class="drawer-bottom">
+        <el-button @click="cancelClick">取消</el-button>
+        <el-button type="primary" @click="confirmClick">提交</el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup>
+import DetailCom from "@/views/unqualified/DetailCom.vue";
+import { dealFeedback } from "@/api/unqualified/index";
+import { getUserTree } from "@/api/user/index";
+import {useUserStore} from "@/store";
+const drawerVisible = ref(false);
+const detailComRef = ref(null);
+const saleModel = ref({});
+const userStore = useUserStore();
+const disabledDate = (time)=> {
+  //选择今天以及今天之后的日期
+  return time.getTime() < Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择
+  //选择今天以及今天之前的日期
+  //return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择今天的
+}
+const showDrawer = (row) => {
+  drawerVisible.value = true;
+  saleModel.value = row;
+
+  nextTick(() => {
+    detailComRef.value && detailComRef.value.refreshView(row);
+  });
+
+  getUserInfo();
+};
+
+const rules1 = {
+  content: [
+    { required: true, message: "请输入投诉或建议处置意见", trigger: "blur" },
+    { min: 2, max: 200, message: "长度在 2 到 200 个字符", trigger: "blur" },
+  ],
+  user: [
+    { required: true, message: "请输入姓名", trigger: "blur" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+  time: [{ required: true, message: "请选择日期", trigger: "change" }],
+  nextRemarkUser: [
+    { required: true, message: "请选择处理人", trigger: "change" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+};
+
+defineExpose({ showDrawer });
+
+const remarkRef = ref(null);
+
+const remark = reactive({
+  content: "",
+  user: "",
+  time: "",
+  nextRemarkUser: "",
+  state: 0,
+});
+
+const cancelClick = () => {
+  drawerVisible.value = false;
+
+  remarkRef.value.resetFields();
+};
+
+const feedBackEmit = defineEmits(["finish"]);
+
+// 用户信息
+const userInfo = ref({});
+const userList = ref([]);
+const getUserInfo = async () => {
+  getUserTree().then((data) => {
+    userList.value = data.data;
+  });
+};
+
+const confirmClick = () => {
+  const date = new Date();
+  const now = date.getFullYear() + "年" + date.getMonth() + "月" + date.getDate() + "日"
+  remark.user = userStore.user.username;
+  remarkRef.value.validate((valid) => {
+    if (valid) {
+      let remark2Copy = {
+        content: remark.content,
+        user: remark.user,
+        time: now,
+        state: remark.state,
+      };
+      let remark3 = {
+        content: "",
+        user: remark.nextRemarkUser, // qinhaibo和dengyu说是user1234的
+        time: "",
+      };
+
+      let p = {
+        id: saleModel.value.id,
+        remark6: JSON.stringify(remark2Copy),
+        remark7: JSON.stringify(remark3),
+        state: remark.state,
+        currentUserName: remark.nextRemarkUser,
+        step: 6, //步骤 1 投书或建议处置意见 2 整改及纠正措施验证 3 处置情况的反馈意见
+      };
+
+      dealFeedback(p).then(() => {
+        feedBackEmit("finish");
+        cancelClick();
+      });
+    } else {
+      console.log("remarkRef invalid");
+      return false;
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+@media print {
+  #print {
+    position: absolute; /* 或 absolute, fixed, 根据需要调整 */
+    top: 20px; /* 调整顶部位置 */
+    margin: 0; /* 重置边距 */
+    width: 1000px;
+  }
+}
+</style>

+ 168 - 0
src/views/unqualified/handle7.vue

@@ -0,0 +1,168 @@
+<template>
+  <el-drawer v-model="drawerVisible" size="1000">
+    <div>
+      <DetailCom ref="detailComRef"></DetailCom>
+    </div>
+
+    <el-form
+        ref="remarkRef"
+        :model="remark"
+        label-width="150"
+        :rules="rules1"
+        style="max-width: 600px; margin-left: 80px; margin-top: 20px"
+    >
+      <el-form-item label="组长(或分管领导)审批意见" prop="content">
+        <el-input
+            v-model="remark.content"
+            type="textarea"
+            :autosize="{ minRows: 3, maxRows: 6 }"
+        />
+      </el-form-item>
+<!--      <el-form-item label="日期" prop="time">
+        <el-date-picker
+            v-model="remark.time"
+            type="date"
+            placeholder="请选择日期"
+            clearable
+            :disabled-date="disabledDate"
+            format="YYYY年MM月DD日"
+            value-format="YYYY年MM月DD日"
+            style="width: 100%"
+        />
+      </el-form-item>-->
+      <el-form-item label="是否通过" prop="state">
+        <el-radio-group v-model="remark.state">
+          <el-radio :value="0">同意</el-radio>
+          <el-radio :value="1">不同意</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <div class="drawer-bottom">
+        <el-button @click="cancelClick">取消</el-button>
+        <el-button type="primary" @click="confirmClick">提交</el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup>
+import DetailCom from "@/views/unqualified/DetailCom.vue";
+import { dealFeedback } from "@/api/unqualified/index";
+import { getUserTree } from "@/api/user/index";
+import {useUserStore} from "@/store";
+const drawerVisible = ref(false);
+const detailComRef = ref(null);
+const saleModel = ref({});
+const userStore = useUserStore();
+const disabledDate = (time)=> {
+  //选择今天以及今天之后的日期
+  return time.getTime() < Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择
+  //选择今天以及今天之前的日期
+  //return time.getTime() > Date.now() - 8.64e7;//如果没有后面的-8.64e7就是不可以选择今天的
+}
+const showDrawer = (row) => {
+  drawerVisible.value = true;
+  saleModel.value = row;
+
+  nextTick(() => {
+    detailComRef.value && detailComRef.value.refreshView(row);
+  });
+
+  getUserInfo();
+};
+
+const rules1 = {
+  content: [
+    { required: true, message: "请输入投诉或建议处置意见", trigger: "blur" },
+    { min: 2, max: 200, message: "长度在 2 到 200 个字符", trigger: "blur" },
+  ],
+  user: [
+    { required: true, message: "请输入姓名", trigger: "blur" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+  time: [{ required: true, message: "请选择日期", trigger: "change" }],
+  nextRemarkUser: [
+    { required: true, message: "请选择处理人", trigger: "change" },
+    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" },
+  ],
+};
+
+defineExpose({ showDrawer });
+
+const remarkRef = ref(null);
+
+const remark = reactive({
+  content: "",
+  user: "",
+  time: "",
+  nextRemarkUser: "",
+  state: 0,
+});
+
+const cancelClick = () => {
+  drawerVisible.value = false;
+
+  remarkRef.value.resetFields();
+};
+
+const feedBackEmit = defineEmits(["finish"]);
+
+// 用户信息
+const userInfo = ref({});
+const userList = ref([]);
+const getUserInfo = async () => {
+  getUserTree().then((data) => {
+    userList.value = data.data;
+  });
+};
+
+const confirmClick = () => {
+  const date = new Date();
+  const now = date.getFullYear() + "年" + date.getMonth() + "月" + date.getDate() + "日"
+  remark.user = userStore.user.username;
+  remarkRef.value.validate((valid) => {
+    if (valid) {
+      let remark2Copy = {
+        content: remark.content,
+        user: remark.user,
+        time: now,
+        state: remark.state,
+      };
+      let remark3 = {
+        content: "",
+        user: remark.nextRemarkUser, // qinhaibo和dengyu说是user1234的
+        time: "",
+      };
+
+      let p = {
+        id: saleModel.value.id,
+        remark7: JSON.stringify(remark2Copy),
+        state: remark.state,
+        currentUserName: remark.nextRemarkUser,
+        step: 7, //步骤 1 投书或建议处置意见 2 整改及纠正措施验证 3 处置情况的反馈意见
+      };
+
+      dealFeedback(p).then(() => {
+        feedBackEmit("finish");
+        cancelClick();
+      });
+    } else {
+      console.log("remarkRef invalid");
+      return false;
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+@media print {
+  #print {
+    position: absolute; /* 或 absolute, fixed, 根据需要调整 */
+    top: 20px; /* 调整顶部位置 */
+    margin: 0; /* 重置边距 */
+    width: 1000px;
+  }
+}
+</style>

+ 279 - 0
src/views/unqualified/index.vue

@@ -0,0 +1,279 @@
+<template>
+  <div class="container">
+    <div class="header">
+      <Search :searchOptions="searchForm" ref="searchRef" @dataList="getData"/>
+    </div>
+    <div class="table">
+      <el-button
+        type="primary"
+        size="small"
+        class="btn"
+        style="margin-bottom: 10px"
+        @click="toAdd"
+        >新增</el-button
+      >
+      <el-table :data="tableData" border>
+        <el-table-column prop="materialModel" label="产品型号" />
+        <el-table-column prop="type" label="产品分类" />
+        <el-table-column prop="workOrderCode" label="生产批号" />
+        <el-table-column prop="seqs" label="管号" width="200" overhidden="true"/>
+        <el-table-column prop="seqNum" label="数量" />
+        <el-table-column prop="componentName" label="器件名称及型号" />
+        <el-table-column prop="num" label="数量" />
+        <el-table-column prop="company" label="供方单位" overhidden="true" />
+        <el-table-column prop="currentUserName" label="审核人" overhidden="true" />
+        <el-table-column prop="auditType" label="审核类型">
+          <template #default="{ row }">
+              {{ getTextByAuditType(row.auditType) }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="state" label="审核状态">
+          <template #default="{ row }">
+            <div :style="{ color: getColorByState(row.state) }">
+              {{ getTextByState(row.state) }}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="created" label="创建时间" />
+        <el-table-column
+          align="center"
+          width="160"
+          prop=""
+          label="操作"
+          id="opear"
+        >
+          <template #default="{ row }">
+            <el-button
+              v-if="row.state === 0"
+              link
+              type="danger"
+              @click="toDelete(row)"
+              >删除</el-button
+            >
+            <el-button
+              link
+              v-if="(row.state === 0 || row.state === 1) && userStore.user.username == row.currentUserName"
+              @click="handle(row)"
+              type="primary"
+              >处理</el-button
+            >
+            <el-button link @click="toDetail(row)" type="primary"
+              >详情</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+      <Pagination
+        :total="currentOption.total"
+        :page="currentOption.page"
+        :limit="currentOption.limit"
+        :pageSizes="currentOption.pageSizes"
+        v-model:page="currentOption.page"
+        v-model:limit="currentOption.limit"
+        @pagination="getData"
+      />
+      <Add ref="addRef" @finish="getData"></Add>
+      <Detail ref="detailRef"></Detail>
+      <Handle20 ref="handle20Ref" @finish="getData"></Handle20>
+      <Handle21 ref="handle21Ref" @finish="getData"></Handle21>
+      <Handle3 ref="handle3Ref" @finish="getData"></Handle3>
+      <Handle4 ref="handle4Ref" @finish="getData"></Handle4>
+      <Handle5 ref="handle5Ref" @finish="getData"></Handle5>
+      <Handle6 ref="handle6Ref" @finish="getData"></Handle6>
+      <Handle7 ref="handle7Ref" @finish="getData"></Handle7>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import Search from "@/components/Search/index.vue";
+import { useSpcStore,useUserStore,useDictionaryStore } from "@/store";
+const { dicts } = useDictionaryStore();
+import { deleteFeedback, getUnqualifiedData } from "@/api/unqualified/index";
+import Add from "@/views/unqualified/add.vue";
+import Detail from "@/views/unqualified/detail.vue";
+import Handle20 from "@/views/unqualified/handle20.vue";
+import Handle21 from "@/views/unqualified/handle21.vue";
+import Handle3 from "@/views/unqualified/handle3.vue";
+import Handle4 from "@/views/unqualified/handle4.vue";
+import Handle5 from "@/views/unqualified/handle5.vue";
+import Handle6 from "@/views/unqualified/handle6.vue";
+import Handle7 from "@/views/unqualified/handle7.vue";
+
+defineOptions({
+  name: "SPCUnqualified",
+});
+const userStore = useUserStore();
+const auditTypes = dicts.unqualified_audit_type
+const store = useSpcStore();
+
+const router = useRouter();
+
+const addRef = ref(null);
+
+const currentOption = reactive({
+  total: 0,
+  page: 1,
+  limit: 10,
+});
+const tableData = ref([]);
+const searchRef = ref(null);
+const searchForm = [
+  {
+    label: "工单号",
+    prop: "workOrderCode",
+    type: "input",
+  },
+  {
+    label: "供方单位",
+    prop: "company",
+    type: "input",
+  },
+  {
+    label: "元器件名称及型号",
+    prop: "componentName",
+    type: "input",
+  },
+];
+
+const getData = async (obj) => {
+  const { data, code } = await getUnqualifiedData({
+    ...searchRef.value.searchForm,
+    pageNo: currentOption.page,
+    pageSize: currentOption.limit,
+  });
+  if (code == "200") {
+    tableData.value = data.records;
+    currentOption.total = data.totalCount;
+  }
+};
+
+const toAdd = () => {
+  addRef.value && addRef.value.showDrawer();
+};
+
+const toDelete = async (row) => {
+  const res = await deleteFeedback(row.id);
+  currentOption.page = 1;
+  getData();
+  // const { code } = await deleteData({ id });
+  // if (code == "200") {
+  //   ElMessage.success("操作成功");
+  //   getData();
+  // }
+};
+
+// 处理相关
+const handle20Ref = ref(null);
+const handle21Ref = ref(null);
+const handle3Ref = ref(null);
+const handle4Ref = ref(null);
+const handle5Ref = ref(null);
+const handle6Ref = ref(null);
+const handle7Ref = ref(null);
+const handle = (row) => {
+  if (row.remark2 && !JSON.parse(row.remark2).content) {
+    if(row.auditType == '1'){
+      handle20Ref.value && handle20Ref.value.showDrawer(row); // 处理
+    }else{
+      handle21Ref.value && handle21Ref.value.showDrawer(row); // 处理
+    }
+  } else if (row.remark3 && !JSON.parse(row.remark3).content) {
+    handle3Ref.value && handle3Ref.value.showDrawer(row); // 处理
+  } else if (row.remark4 && !JSON.parse(row.remark4).content) {
+    handle4Ref.value && handle4Ref.value.showDrawer(row); // 处理
+  } else if (row.remark5 && !JSON.parse(row.remark5).content) {
+    handle5Ref.value && handle5Ref.value.showDrawer(row); // 处理
+  } else if (row.remark6 && !JSON.parse(row.remark6).content) {
+    handle6Ref.value && handle6Ref.value.showDrawer(row); // 处理
+  } else if (row.remark7 && !JSON.parse(row.remark7).content) {
+    handle7Ref.value && handle7Ref.value.showDrawer(row); // 处理
+  }else{
+    ElMessage.info("该工单正在处理中。。。");
+  }
+};
+
+// 详情
+const detailRef = ref(null);
+const toDetail = (row) => {
+  detailRef.value && detailRef.value.showDrawer(row); // 详情
+};
+const getTextByAuditType = (state) => {
+  if(state){
+    const item = auditTypes.filter((v)=>{
+      console.log("dictValue:"  + v.dictValue + ",state:" + state  + "..." + (v.dictValue === state))
+      return v.dictValue === state
+    })
+    if(item.length > 0){
+      return item[0].dictLabel
+    }
+  }
+};
+// 审核状态0待处理 1 审核中 2 审核驳回 3 审核完成
+const getTextByState = (state) => {
+  switch (state) {
+    case 0:
+      return "待处理";
+    case 1:
+      return "审核中";
+    case 2:
+      return "审核驳回";
+    case 3:
+      return "审核完成";
+    default:
+      return "";
+  }
+};
+const getColorByState = (state) => {
+  switch (state) {
+    case 0:
+      return "#59acbb";
+    case 1:
+      return "#bba559";
+    case 2:
+      return "#d96868";
+    case 3:
+      return "#67c23a";
+    default:
+      return "";
+  }
+};
+
+onMounted(() => {
+  getData();
+});
+</script>
+
+<style scoped lang="scss">
+.container {
+  background-color: white;
+  width: 100%;
+  height: 100%;
+  padding: 20px;
+  display: flex;
+  flex-direction: column;
+  .header {
+    width: 100%;
+    height: auto;
+  }
+  .table {
+    flex: 1;
+    padding-bottom: 20px;
+  }
+  .formView {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    .formTitle {
+      text-align: center;
+      font-size: 20px;
+      margin-bottom: 20px;
+    }
+    .formStyle {
+      width: 400px;
+    }
+  }
+}
+</style>

+ 1 - 1
tsconfig.json

@@ -12,7 +12,7 @@
     "lib": ["esnext", "dom"],
     "baseUrl": ".",
     "allowJs": true,
-    "noImplicitAny": true,
+    "noImplicitAny": false,
     "paths": {
       "@/*": ["src/*"]
     },