From f397a6cfd118ae36022576374ed4a1fd9e15448d Mon Sep 17 00:00:00 2001
From: zhangwei <1504152376@qq.com>
Date: 星期四, 26 六月 2025 17:13:05 +0800
Subject: [PATCH] '登录注册完善'

---
 src/router/modules/remaining.ts         |   22 
 src/views/item/index.vue                |  506 ++++++++++++++++++
 types/index.d.ts                        |    3 
 src/views/login/index.vue               |    2 
 src/router/modules/item.ts              |   12 
 src/store/modules/user.ts               |    4 
 src/api/item/index.ts                   |  148 +++++
 src/views/home/index.vue                |  263 +++++----
 src/utils/http/index.ts                 |    9 
 src/views/item/component/editDialog.vue |  193 +++++++
 src/utils/commonFunction.ts             |  138 +++++
 src/router/modules/home.ts              |   10 
 src/utils/auth.ts                       |   20 
 src/router/index.ts                     |   16 
 src/router/utils.ts                     |   13 
 src/api/util.ts                         |    2 
 src/utils/formatTime.ts                 |  207 +++++++
 17 files changed, 1,409 insertions(+), 159 deletions(-)

diff --git a/src/api/item/index.ts b/src/api/item/index.ts
new file mode 100644
index 0000000..c2e812a
--- /dev/null
+++ b/src/api/item/index.ts
@@ -0,0 +1,148 @@
+/**
+ * 锛堜笉寤鸿鍐欐垚 request.post(xxx)锛屽洜涓鸿繖鏍� post 鏃讹紝鏃犳硶 params 涓� data 鍚屾椂浼犲弬锛�
+ *
+ * 娉ㄥ唽api鎺ュ彛闆嗗悎
+ * @method login 鐧诲綍
+ */
+
+import { http } from "@/utils/http";
+import { baseUrlApi } from "../util";
+type Result = {
+  success: boolean;
+  data: Array<any>;
+};
+
+// 鑾峰彇琛屾斂鍖哄煙鍒楄〃
+export const getRegionList = () => {
+  return http.request<Result>(
+    "get",
+    baseUrlApi("/api/tenderOrder/getRegionList")
+  );
+};
+
+// 鑾峰彇寮�鏍囨柟寮忛泦鍚�
+export const getKaibiaofangshiList = () => {
+  return http.request<Result>(
+    "get",
+    baseUrlApi("/api/tenderOrder/getKaibiaofangshiList")
+  );
+};
+
+// 鑾峰彇鏄惁鏋氫妇闆嗗悎
+export const getYesNoEnumList = () => {
+  return http.request<Result>(
+    "get",
+    baseUrlApi("/api/tenderOrder/getYesNoEnumList")
+  );
+};
+
+// 鑾峰彇澶嶅悎浣撴姇鏍囬泦鍚�
+export const getFuhetitoubiaoList = () => {
+  return http.request<Result>(
+    "get",
+    baseUrlApi("/api/tenderOrder/getFuhetitoubiaoList")
+  );
+};
+
+// 鑾峰彇瀹氭爣瑙勫垯闆嗗悎
+export const getDingbiaoguizeList = () => {
+  return http.request<Result>(
+    "get",
+    baseUrlApi("/api/tenderOrder/getDingbiaoguizeList")
+  );
+};
+
+// 鑾峰彇浠g爜绫诲瀷闆嗗悎
+export const getDaimaleixingList = () => {
+  return http.request<Result>(
+    "get",
+    baseUrlApi("/api/tenderOrder/getDaimaleixingList")
+  );
+};
+
+// 鑾峰彇閲囪喘鏂瑰紡闆嗗悎
+export const getCaigoufangshiList = () => {
+  return http.request<Result>(
+    "get",
+    baseUrlApi("/api/tenderOrder/getCaigoufangshiList")
+  );
+};
+
+// 鑾峰彇琛屼笟鍝佺洰闆嗗悎
+export const getHangyepingmuList = () => {
+  return http.request<Result>(
+    "get",
+    baseUrlApi("/api/tenderOrder/getHangyepingmuList")
+  );
+};
+
+// 鑾峰彇椤圭洰杩涘害闆嗗悎
+export const getOrderStatusList = () => {
+  return http.request<Result>(
+    "get",
+    baseUrlApi("/api/tenderOrder/getOrderStatusList")
+  );
+};
+
+// 鑾峰彇闈炴斂搴滆鍗曞鐞嗚鎯�
+export const getTenderOrderDetail = () => {
+  return http.request<Result>("get", baseUrlApi("/api/tenderOrder/detail"));
+};
+
+// 涓嬭浇闈炴斂搴滆鍗曞鐞嗘暟鎹鍏ユā鏉�
+export const importFZF = () => {
+  return http.request<Result>("get", baseUrlApi("/api/tenderOrder/import"));
+};
+
+// 棣栭〉鏌ヨ闈炴斂搴滆鍗曞鐞�
+export const shouyeOrder = (data?: object) => {
+  return http.request("post", baseUrlApi("/api/tenderOrder/shouyeOrder"), {
+    data
+  });
+};
+
+// 鎷涙爣浠g悊鍒嗛〉鏌ヨ闈炴斂搴滆鍗曞鐞�
+export const zhaobiaoPageOrder = (data?: object) => {
+  return http.request("post", baseUrlApi("/api/tenderOrder/page"), { data });
+};
+
+// 閲囪喘浠g悊浜哄鍔犻潪鏀垮簻璁㈠崟澶勭悊
+export const caigourenAdd = (data?: object) => {
+  return http.request("post", baseUrlApi("/api/tenderOrder/add"), { data });
+};
+
+// 閲囪喘浠g悊浜烘洿鏂伴潪鏀垮簻璁㈠崟澶勭悊
+export const caigourenUpdate = (data?: object) => {
+  return http.request("post", baseUrlApi("/api/tenderOrder/update"), { data });
+};
+
+// 閲囪喘浠g悊浜烘洿鏂伴潪鏀垮簻璁㈠崟璐ㄧ枒
+export const caigourenUpdateZhiyi = (data?: object) => {
+  return http.request("post", baseUrlApi("/api/tenderOrder/updateZhiyi"), {
+    data
+  });
+};
+
+// 閲囪喘浠g悊浜烘洿鏂伴潪鏀垮簻璁㈠崟鎶曡瘔
+export const caigourenUpdateTousu = (data?: object) => {
+  return http.request("post", baseUrlApi("/api/tenderOrder/updateTousu"), {
+    data
+  });
+};
+
+// 閲囪喘浠g悊浜哄垹闄ら潪鏀垮簻璁㈠崟澶勭悊
+export const caigourenDelete = (data?: object) => {
+  return http.request("post", baseUrlApi("/api/tenderOrder/delete"), { data });
+};
+
+// 閲囪喘浠g悊浜烘壒閲忓垹闄ら潪鏀垮簻璁㈠崟澶勭悊
+export const caigourenBatchDelete = (data?: object) => {
+  return http.request("post", baseUrlApi("/api/tenderOrder/batchDelete"), {
+    data
+  });
+};
+
+// 瀵煎嚭闈炴斂搴滆鍗曞鐞嗚褰�
+export const exportFZF = (data?: object) => {
+  return http.request("post", baseUrlApi("/api/tenderOrder/export"), { data });
+};
diff --git a/src/api/util.ts b/src/api/util.ts
index 5763e01..c6316ec 100644
--- a/src/api/util.ts
+++ b/src/api/util.ts
@@ -1,4 +1,4 @@
 export const baseUrlApi = (url: string) =>
   process.env.NODE_ENV === "development"
     ? `/api${url}`
-    : `http://192.168.0.36:5005${url}`;
+    : `http://192.168.0.31:5005${url}`;
diff --git a/src/router/index.ts b/src/router/index.ts
index 91e06ca..a4d8e99 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -106,8 +106,9 @@
 }
 
 /** 璺敱鐧藉悕鍗� */
-// const whiteList = ["/login"];
-const whiteList = [];
+const whiteList = ["/login"];
+const noLoginList = ["/index", "/register", "/registersucess"];
+// const whiteList = [];
 
 const { VITE_HIDE_HOME } = import.meta.env;
 
@@ -141,7 +142,7 @@
     }
     // 寮�鍚殣钘忛椤靛悗鍦ㄦ祻瑙堝櫒鍦板潃鏍忔墜鍔ㄨ緭鍏ラ椤祑elcome璺敱鍒欒烦杞埌404椤甸潰
     if (VITE_HIDE_HOME === "true" && to.fullPath === "/welcome") {
-      next({ path: "/error/404" });
+      next({ path: "/index" });
     }
     if (_from?.name) {
       // name涓鸿秴閾炬帴
@@ -194,10 +195,15 @@
   } else {
     if (to.path !== "/login") {
       if (whiteList.indexOf(to.path) !== -1) {
+        console.log(to.path, "====1", noLoginList.indexOf(to.path));
         next();
       } else {
-        removeToken();
-        next({ path: "/login" });
+        // if (noLoginList.indexOf(to.path) == -1) {
+        next();
+        // } else {
+        //   removeToken();
+        //   next({ path: "/login" });
+        // }
       }
     } else {
       next();
diff --git a/src/router/modules/home.ts b/src/router/modules/home.ts
index ee5224f..1cc1a4f 100644
--- a/src/router/modules/home.ts
+++ b/src/router/modules/home.ts
@@ -2,13 +2,13 @@
 const Layout = () => import("@/layout/index.vue");
 
 export default {
-  path: "/welcome",
-  name: "Welcome",
+  path: "/",
+  name: "Home",
   component: Layout,
-  // redirect: "/welcome",
+  redirect: "/welcome",
   meta: {
     icon: "ep/home-filled",
-    title: "涓婚〉",
+    title: "棣栭〉",
     rank: 0
   },
   children: [
@@ -17,7 +17,7 @@
       name: "Welcome",
       component: () => import("@/views/welcome/index.vue"),
       meta: {
-        title: "涓婚〉",
+        title: "棣栭〉",
         showLink: VITE_HIDE_HOME === "true" ? false : true
       }
     }
diff --git a/src/router/modules/item.ts b/src/router/modules/item.ts
new file mode 100644
index 0000000..768d651
--- /dev/null
+++ b/src/router/modules/item.ts
@@ -0,0 +1,12 @@
+export default {
+  path: "/item",
+  component: () => import("@/views/item/index.vue"),
+  name: "item",
+  // redirect: "/error/403",
+  meta: {
+    icon: "ri/information-line",
+    // showLink: false,
+    title: "椤圭洰绠$悊",
+    rank: 9
+  }
+} satisfies RouteConfigsTable;
diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts
index 621931b..6421398 100644
--- a/src/router/modules/remaining.ts
+++ b/src/router/modules/remaining.ts
@@ -1,19 +1,19 @@
 const Layout = () => import("@/layout/index.vue");
 
 export default [
+  // {
+  //   path: "/",
+  //   name: "Main",
+  //   redirect: "/home",
+  //   meta: {
+  //     title: "棣栭〉",
+  //     showLink: false,
+  //     rank: 101
+  //   }
+  // },
   {
-    path: "/",
+    path: "/index",
     name: "Main",
-    redirect: "/home",
-    meta: {
-      title: "棣栭〉",
-      showLink: false,
-      rank: 101
-    }
-  },
-  {
-    path: "/home",
-    name: "Home",
     component: () => import("@/views/home/index.vue"),
     meta: {
       title: "棣栭〉",
diff --git a/src/router/utils.ts b/src/router/utils.ts
index bb895a1..28e32b8 100644
--- a/src/router/utils.ts
+++ b/src/router/utils.ts
@@ -33,7 +33,7 @@
   const { name, path, parentId, meta } = routeInfo;
   return isAllEmpty(parentId)
     ? isAllEmpty(meta?.rank) ||
-      (meta?.rank === 0 && name !== "Welcome" && path !== "/welcome")
+      (meta?.rank === 0 && name !== "Home" && path !== "/")
       ? true
       : false
     : false;
@@ -171,7 +171,7 @@
           if (!router.hasRoute(v?.name)) router.addRoute(v);
           const flattenRouters: any = router
             .getRoutes()
-            .find(n => n.path === "/welcome");
+            .find(n => n.path === "/");
           // 淇濇寔router.options.routes[0].children涓巔ath涓�"/"鐨刢hildren涓�鑷达紝闃叉鏁版嵁涓嶄竴鑷村鑷村紓甯�
           flattenRouters.children = router.options.routes[0].children;
           router.addRoute(flattenRouters);
@@ -205,8 +205,8 @@
     } else {
       return new Promise(resolve => {
         getAsyncRoutes().then(({ data }) => {
-          // handleAsyncRoutes(cloneDeep(data));
-          // storageLocal().setItem(key, data);
+          handleAsyncRoutes(cloneDeep(data));
+          storageLocal().setItem(key, data);
           resolve(router);
         });
       });
@@ -214,7 +214,7 @@
   } else {
     return new Promise(resolve => {
       getAsyncRoutes().then(({ data }) => {
-        // handleAsyncRoutes(cloneDeep(data));
+        handleAsyncRoutes(cloneDeep(data));
         resolve(router);
       });
     });
@@ -249,7 +249,7 @@
   if (routesList?.length === 0) return routesList;
   const newRoutesList: RouteRecordRaw[] = [];
   routesList.forEach((v: RouteRecordRaw) => {
-    if (v.path === "/welcome") {
+    if (v.path === "/") {
       newRoutesList.push({
         component: v.component,
         name: v.name,
@@ -388,6 +388,7 @@
   );
   tag && useMultiTagsStoreHook().handleTags("push", topMenu);
   console.log(topMenu, "topMenu");
+
   return topMenu;
 }
 
diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts
index 09b6642..cbd4d99 100644
--- a/src/store/modules/user.ts
+++ b/src/store/modules/user.ts
@@ -68,7 +68,9 @@
       return new Promise<UserResult>((resolve, reject) => {
         getLogin(data)
           .then(data => {
-            if (data?.success) setToken(data.data);
+            console.log(data, "杩欐槸浠�涔堬紵");
+
+            if (data?.code == 200) setToken(data.result);
             resolve(data);
           })
           .catch(error => {
diff --git a/src/utils/auth.ts b/src/utils/auth.ts
index f2b28cb..7e5a326 100644
--- a/src/utils/auth.ts
+++ b/src/utils/auth.ts
@@ -16,7 +16,7 @@
   /** 鏄电О */
   nickname?: string;
   /** 褰撳墠鐧诲綍鐢ㄦ埛鐨勮鑹� */
-  roles?: Array<string>;
+  exRoles?: Array<string>;
   /** 褰撳墠鐧诲綍鐢ㄦ埛鐨勬寜閽骇鍒潈闄� */
   permissions?: Array<string>;
 }
@@ -68,11 +68,11 @@
       : {}
   );
 
-  function setUserKey({ avatar, username, nickname, roles, permissions }) {
+  function setUserKey({ avatar, username, nickname, exRoles, permissions }) {
     useUserStoreHook().SET_AVATAR(avatar);
     useUserStoreHook().SET_USERNAME(username);
     useUserStoreHook().SET_NICKNAME(nickname);
-    useUserStoreHook().SET_ROLES(roles);
+    useUserStoreHook().SET_ROLES(exRoles);
     useUserStoreHook().SET_PERMS(permissions);
     storageLocal().setItem(userKey, {
       refreshToken,
@@ -80,18 +80,18 @@
       avatar,
       username,
       nickname,
-      roles,
+      exRoles,
       permissions
     });
   }
 
-  if (data.username && data.roles) {
-    const { username, roles } = data;
+  if (data.exRoles) {
+    const { username, exRoles } = data;
     setUserKey({
       avatar: data?.avatar ?? "",
       username,
       nickname: data?.nickname ?? "",
-      roles,
+      exRoles,
       permissions: data?.permissions ?? []
     });
   } else {
@@ -101,15 +101,15 @@
       storageLocal().getItem<DataInfo<number>>(userKey)?.username ?? "";
     const nickname =
       storageLocal().getItem<DataInfo<number>>(userKey)?.nickname ?? "";
-    const roles =
-      storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? [];
+    const exRoles =
+      storageLocal().getItem<DataInfo<number>>(userKey)?.exRoles ?? [];
     const permissions =
       storageLocal().getItem<DataInfo<number>>(userKey)?.permissions ?? [];
     setUserKey({
       avatar,
       username,
       nickname,
-      roles,
+      exRoles,
       permissions
     });
   }
diff --git a/src/utils/commonFunction.ts b/src/utils/commonFunction.ts
new file mode 100644
index 0000000..f911cc8
--- /dev/null
+++ b/src/utils/commonFunction.ts
@@ -0,0 +1,138 @@
+// 閫氱敤鍑芥暟
+// import useClipboard from "vue-clipboard3";
+// import { ElMessage } from "element-plus";
+import { formatDate } from "@/utils/formatTime";
+
+export default function () {
+  // const { toClipboard } = useClipboard();
+
+  // 鐧惧垎姣旀牸寮忓寲
+  const percentFormat = (
+    row: EmptyArrayType,
+    column: number,
+    cellValue: string
+  ) => {
+    return cellValue ? `${cellValue}%` : "-";
+  };
+  // 鍒楄〃鏃ユ湡鏃堕棿鏍煎紡鍖�
+  const dateFormatYMD = (
+    row: EmptyArrayType,
+    column: number,
+    cellValue: string
+  ) => {
+    if (!cellValue) return "-";
+    return formatDate(new Date(cellValue), "YYYY-mm-dd");
+  };
+  // 鍒楄〃鏃ユ湡鏃堕棿鏍煎紡鍖�
+  const dateFormatYMDHMS = (
+    row: EmptyArrayType,
+    column: number,
+    cellValue: string
+  ) => {
+    if (!cellValue) return "-";
+    return formatDate(new Date(cellValue), "YYYY-mm-dd HH:MM:SS");
+  };
+  // 鍒楄〃鏃ユ湡鏃堕棿鏍煎紡鍖�
+  const dateFormatHMS = (
+    row: EmptyArrayType,
+    column: number,
+    cellValue: string
+  ) => {
+    if (!cellValue) return "-";
+    let time = 0;
+    if (typeof row === "number") time = row;
+    if (typeof cellValue === "number") time = cellValue;
+    return formatDate(new Date(time * 1000), "HH:MM:SS");
+  };
+  // 灏忔暟鏍煎紡鍖�
+  const scaleFormat = (value: string = "0", scale: number = 4) => {
+    return Number.parseFloat(value).toFixed(scale);
+  };
+  // 灏忔暟鏍煎紡鍖�
+  const scale2Format = (value: string = "0") => {
+    return Number.parseFloat(value).toFixed(2);
+  };
+  // 鍗冨垎绗︼紝榛樿淇濈暀涓や綅灏忔暟
+  const groupSeparator = (value: number, minimumFractionDigits: number = 2) => {
+    return value.toLocaleString("en-US", {
+      minimumFractionDigits: minimumFractionDigits,
+      maximumFractionDigits: 2
+    });
+  };
+
+  /**
+   * 鍒犻櫎瀛楃涓查灏炬寚瀹氬瓧绗�
+   * @param Str 婧愬瓧绗�
+   * @param char 鍘婚櫎鐨勬寚瀹氬瓧绗�
+   * @param type 绫诲瀷锛屽彸杈规垨宸﹁竟锛屼负绌烘槸鏇挎崲棣栧熬
+   */
+  const trimChar = (Str: string, char: string, type: string) => {
+    if (char) {
+      if (type == "left") {
+        return Str.replace(new RegExp("^\\" + char + "+", "g"), "");
+      } else if (type == "right") {
+        return Str.replace(new RegExp("\\" + char + "+$", "g"), "");
+      }
+      return Str.replace(
+        new RegExp("^\\" + char + "+|\\" + char + "+$", "g"),
+        ""
+      );
+    }
+    return Str.replace(/^\s+|\s+$/g, "");
+  };
+  // 鐐瑰嚮澶嶅埗鏂囨湰
+  // const copyText = (text: string) => {
+  //   return new Promise((resolve, reject) => {
+  //     try {
+  //       //澶嶅埗
+  //       toClipboard(text);
+  //       //涓嬮潰鍙互璁剧疆澶嶅埗鎴愬姛鐨勬彁绀烘绛夋搷浣�
+  //       ElMessage.success("澶嶅埗鎴愬姛");
+  //       resolve(text);
+  //     } catch (e) {
+  //       //澶嶅埗澶辫触
+  //       ElMessage.error("澶嶅埗澶辫触");
+  //       reject(e);
+  //     }
+  //   });
+  // };
+  // 鍘绘帀Html鏍囩(鍙栧墠闈�5涓瓧绗�)
+  const removeHtmlSub = (value: string) => {
+    const str = value.replace(/<[^>]+>/g, "");
+    if (str.length > 50) return str.substring(0, 50) + "......";
+    else return str;
+  };
+  // 鍘绘帀Html鏍囩
+  const removeHtml = (value: string) => {
+    return value.replace(/<[^>]+>/g, "");
+  };
+  // 鑾峰彇鏋氫妇鎻忚堪
+  const getEnumDesc = (key: any, lstEnum: any) => {
+    return lstEnum.find((x: any) => x.value == key)?.describe;
+  };
+  // 杩藉姞query鍙傛暟鍒皍rl
+  const appendQueryParams = (url: string, params: { [key: string]: any }) => {
+    if (!params || Object.keys(params).length == 0) return url;
+    const queryString = Object.keys(params)
+      .map(
+        key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`
+      )
+      .join("&");
+    return `${url}${url.includes("?") ? "&" : "?"}${queryString}`;
+  };
+  return {
+    percentFormat,
+    dateFormatYMD,
+    dateFormatYMDHMS,
+    dateFormatHMS,
+    scaleFormat,
+    scale2Format,
+    groupSeparator,
+    copyText,
+    removeHtmlSub,
+    removeHtml,
+    getEnumDesc,
+    appendQueryParams,
+    trimChar
+  };
+}
diff --git a/src/utils/formatTime.ts b/src/utils/formatTime.ts
new file mode 100644
index 0000000..5a95660
--- /dev/null
+++ b/src/utils/formatTime.ts
@@ -0,0 +1,207 @@
+/**
+ * 鏃堕棿鏃ユ湡杞崲
+ * @param date 褰撳墠鏃堕棿锛宯ew Date() 鏍煎紡
+ * @param format 闇�瑕佽浆鎹㈢殑鏃堕棿鏍煎紡瀛楃涓�
+ * @description format 瀛楃涓查殢鎰忥紝濡� `YYYY-mm銆乊YYY-mm-dd`
+ * @description format 瀛e害锛�"YYYY-mm-dd HH:MM:SS QQQQ"
+ * @description format 鏄熸湡锛�"YYYY-mm-dd HH:MM:SS WWW"
+ * @description format 鍑犲懆锛�"YYYY-mm-dd HH:MM:SS ZZZ"
+ * @description format 瀛e害 + 鏄熸湡 + 鍑犲懆锛�"YYYY-mm-dd HH:MM:SS WWW QQQQ ZZZ"
+ * @returns 杩斿洖鎷兼帴鍚庣殑鏃堕棿瀛楃涓�
+ */
+export function formatDate(date: Date, format: string): string {
+  const we = date.getDay(); // 鏄熸湡
+  const z = getWeek(date); // 鍛�
+  const qut = Math.floor((date.getMonth() + 3) / 3).toString(); // 瀛e害
+  const opt: { [key: string]: string } = {
+    "Y+": date.getFullYear().toString(), // 骞�
+    "m+": (date.getMonth() + 1).toString(), // 鏈�(鏈堜唤浠�0寮�濮嬶紝瑕�+1)
+    "d+": date.getDate().toString(), // 鏃�
+    "H+": date.getHours().toString(), // 鏃�
+    "M+": date.getMinutes().toString(), // 鍒�
+    "S+": date.getSeconds().toString(), // 绉�
+    "q+": qut // 瀛e害
+  };
+  // 涓枃鏁板瓧 (鏄熸湡)
+  const week: { [key: string]: string } = {
+    "0": "鏃�",
+    "1": "涓�",
+    "2": "浜�",
+    "3": "涓�",
+    "4": "鍥�",
+    "5": "浜�",
+    "6": "鍏�"
+  };
+  // 涓枃鏁板瓧锛堝搴︼級
+  const quarter: { [key: string]: string } = {
+    "1": "涓�",
+    "2": "浜�",
+    "3": "涓�",
+    "4": "鍥�"
+  };
+  if (/(W+)/.test(format))
+    format = format.replace(
+      RegExp.$1,
+      RegExp.$1.length > 1
+        ? RegExp.$1.length > 2
+          ? "鏄熸湡" + week[we]
+          : "鍛�" + week[we]
+        : week[we]
+    );
+  if (/(Q+)/.test(format))
+    format = format.replace(
+      RegExp.$1,
+      RegExp.$1.length == 4 ? "绗�" + quarter[qut] + "瀛e害" : quarter[qut]
+    );
+  if (/(Z+)/.test(format))
+    format = format.replace(
+      RegExp.$1,
+      RegExp.$1.length == 3 ? "绗�" + z + "鍛�" : z + ""
+    );
+  for (const k in opt) {
+    const r = new RegExp("(" + k + ")").exec(format);
+    // 鑻ヨ緭鍏ョ殑闀垮害涓嶄负1锛屽垯鍓嶉潰琛ラ浂
+    if (r)
+      format = format.replace(
+        r[1],
+        RegExp.$1.length == 1 ? opt[k] : opt[k].padStart(RegExp.$1.length, "0")
+      );
+  }
+  return format;
+}
+
+/**
+ * 鑾峰彇褰撳墠鏃ユ湡鏄鍑犲懆
+ * @param dateTime 褰撳墠浼犲叆鐨勬棩鏈熷��
+ * @returns 杩斿洖绗嚑鍛ㄦ暟瀛楀��
+ */
+export function getWeek(dateTime: Date): number {
+  const temptTime = new Date(dateTime.getTime());
+  // 鍛ㄥ嚑
+  const weekday = temptTime.getDay() || 7;
+  // 鍛�1+5澶�=鍛ㄥ叚
+  temptTime.setDate(temptTime.getDate() - weekday + 1 + 5);
+  let firstDay = new Date(temptTime.getFullYear(), 0, 1);
+  const dayOfWeek = firstDay.getDay();
+  let spendDay = 1;
+  if (dayOfWeek != 0) spendDay = 7 - dayOfWeek + 1;
+  firstDay = new Date(temptTime.getFullYear(), 0, 1 + spendDay);
+  const d = Math.ceil((temptTime.valueOf() - firstDay.valueOf()) / 86400000);
+  const result = Math.ceil(d / 7);
+  return result;
+}
+
+/**
+ * 灏嗘椂闂磋浆鎹负 `鍑犵鍓峘銆乣鍑犲垎閽熷墠`銆乣鍑犲皬鏃跺墠`銆乣鍑犲ぉ鍓峘
+ * @param param 褰撳墠鏃堕棿锛宯ew Date() 鏍煎紡鎴栬�呭瓧绗︿覆鏃堕棿鏍煎紡
+ * @param format 闇�瑕佽浆鎹㈢殑鏃堕棿鏍煎紡瀛楃涓�
+ * @description param 10绉掞細  10 * 1000
+ * @description param 1鍒嗭細   60 * 1000
+ * @description param 1灏忔椂锛� 60 * 60 * 1000
+ * @description param 24灏忔椂锛�60 * 60 * 24 * 1000
+ * @description param 3澶╋細   60 * 60* 24 * 1000 * 3
+ * @returns 杩斿洖鎷兼帴鍚庣殑鏃堕棿瀛楃涓�
+ */
+export function formatPast(
+  param: string | Date,
+  format: string = "YYYY-mm-dd"
+): string {
+  // 浼犲叆鏍煎紡澶勭悊銆佸瓨鍌ㄨ浆鎹㈠��
+  let t: any, s: number;
+  // 鑾峰彇js 鏃堕棿鎴�
+  let time: number = new Date().getTime();
+  // 鏄惁鏄璞�
+  typeof param === "string" || "object"
+    ? (t = new Date(param).getTime())
+    : (t = param);
+  // 褰撳墠鏃堕棿鎴� - 浼犲叆鏃堕棿鎴�
+  time = Number.parseInt(`${time - t}`);
+  if (time < 10000) {
+    // 10绉掑唴
+    return "鍒氬垰";
+  } else if (time < 60000 && time >= 10000) {
+    // 瓒呰繃10绉掑皯浜�1鍒嗛挓鍐�
+    s = Math.floor(time / 1000);
+    return `${s}绉掑墠`;
+  } else if (time < 3600000 && time >= 60000) {
+    // 瓒呰繃1鍒嗛挓灏戜簬1灏忔椂
+    s = Math.floor(time / 60000);
+    return `${s}鍒嗛挓鍓峘;
+  } else if (time < 86400000 && time >= 3600000) {
+    // 瓒呰繃1灏忔椂灏戜簬24灏忔椂
+    s = Math.floor(time / 3600000);
+    return `${s}灏忔椂鍓峘;
+  } else if (time < 259200000 && time >= 86400000) {
+    // 瓒呰繃1澶╁皯浜�3澶╁唴
+    s = Math.floor(time / 86400000);
+    return `${s}澶╁墠`;
+  } else {
+    // 瓒呰繃3澶�
+    const date =
+      typeof param === "string" || "object" ? new Date(param) : param;
+    return formatDate(date, format);
+  }
+}
+
+/**
+ * 鏃堕棿闂�欒
+ * @param param 褰撳墠鏃堕棿锛宯ew Date() 鏍煎紡
+ * @description param 璋冪敤 `formatAxis(new Date())` 杈撳嚭 `涓婂崍濂絗
+ * @returns 杩斿洖鎷兼帴鍚庣殑鏃堕棿瀛楃涓�
+ */
+export function formatAxis(param: Date): string {
+  const hour: number = new Date(param).getHours();
+  if (hour < 6) return "鍑屾櫒濂�";
+  else if (hour < 9) return "鏃╀笂濂�";
+  else if (hour < 12) return "涓婂崍濂�";
+  else if (hour < 14) return "涓崍濂�";
+  else if (hour < 17) return "涓嬪崍濂�";
+  else if (hour < 19) return "鍌嶆櫄濂�";
+  else if (hour < 22) return "鏅氫笂濂�";
+  else return "澶滈噷濂�";
+}
+
+/**
+ * 鑾峰彇涓や釜鏃堕棿鐩稿樊鐨勭鏁�
+ * @dateBegin 寮�濮嬫椂闂达紝new Date() 鏍煎紡
+ * @dateEnd 缁撴潫鏃堕棿锛宯ew Date() 鏍煎紡
+ * @returns 杩斿洖绉掓暟
+ */
+export function getTimeDiff(dateBegin: Date, dateEnd: Date) {
+  const dateDiff = dateEnd.getTime() - dateBegin.getTime();
+  return dateDiff / 1000;
+}
+
+/**
+ * 鏍煎紡鍖栦袱涓椂闂村樊
+ * @dateBegin 寮�濮嬫椂闂达紝new Date() 鏍煎紡
+ * @dateEnd 缁撴潫鏃堕棿锛宯ew Date() 鏍煎紡
+ * @description dateBegin 2025-1-1锛宒ateEnd 2025-1-2 10:10:10 锛�   1澶�10鏃�10鍒�10绉�
+ * @returns 杩斿洖鎷兼帴鍚庣殑鏃堕棿瀛楃涓�
+ */
+export function formatTimeDiff(dateBegin: Date, dateEnd: Date) {
+  const dateDiff = dateEnd.getTime() - dateBegin.getTime(); //鏃堕棿宸殑姣鏁�
+  const dayDiff = Math.floor(dateDiff / (24 * 3600 * 1000)); //璁$畻鍑虹浉宸ぉ鏁�
+  const leave1 = dateDiff % (24 * 3600 * 1000); //璁$畻澶╂暟鍚庡墿浣欑殑姣鏁�
+  const hours = Math.floor(leave1 / (3600 * 1000)); //璁$畻鍑哄皬鏃舵暟
+  //璁$畻鐩稿樊鍒嗛挓鏁�
+  const leave2 = leave1 % (3600 * 1000); //璁$畻灏忔椂鏁板悗鍓╀綑鐨勬绉掓暟
+  const minutes = Math.floor(leave2 / (60 * 1000)); //璁$畻鐩稿樊鍒嗛挓鏁�
+  //璁$畻鐩稿樊绉掓暟
+  const leave3 = leave2 % (60 * 1000); //璁$畻鍒嗛挓鏁板悗鍓╀綑鐨勬绉掓暟
+  const seconds = Math.round(leave3 / 1000);
+  let result = "";
+  if (dayDiff > 0) {
+    result += dayDiff + "澶�";
+  }
+  if (hours > 0) {
+    result += hours + "鏃�";
+  }
+  if (minutes > 0) {
+    result += minutes + "鍒�";
+  }
+  if (seconds >= 0) {
+    result += seconds + "绉�";
+  }
+  return result;
+}
diff --git a/src/utils/http/index.ts b/src/utils/http/index.ts
index 19b5be2..298dd29 100644
--- a/src/utils/http/index.ts
+++ b/src/utils/http/index.ts
@@ -73,7 +73,14 @@
           return config;
         }
         /** 璇锋眰鐧藉悕鍗曪紝鏀剧疆涓�浜涗笉闇�瑕乣token`鐨勬帴鍙o紙閫氳繃璁剧疆璇锋眰鐧藉悕鍗曪紝闃叉`token`杩囨湡鍚庡啀璇锋眰閫犳垚鐨勬寰幆闂锛� */
-        const whiteList = ["/refresh-token", "/login"];
+        const whiteList = [
+          "/refresh-token",
+          "/loginPhone",
+          "/register",
+          "customerRegistration",
+          "captcha",
+          "exRole"
+        ];
         return whiteList.some(url => config.url.endsWith(url))
           ? config
           : new Promise(resolve => {
diff --git a/src/views/home/index.vue b/src/views/home/index.vue
index 041ec08..9645a61 100644
--- a/src/views/home/index.vue
+++ b/src/views/home/index.vue
@@ -1,3 +1,4 @@
+el
 <template>
   <div class="header">
     <img width="227px" height="74px" src="@/assets/home/logo.png" alt="" />
@@ -41,64 +42,71 @@
       </div>
     </div>
     <div class="right">
-      <el-tabs v-model="activeName" class="demo-tabs">
+      <!-- <el-tabs v-model="activeName" class="demo-tabs">
         <el-tab-pane label="鎰忓悜鍏紑" name="first">
-          鎰忓悜鍏紑
-          <!-- <div class="item">
-            <span
-              ><span style="color: #145ccd; font-weight: 600">路</span
-              >銆愬洓宸濈渷鎴愰兘甯傘��2024骞寸煶鐩樿閬撲粯瀹剁鏉戠伯娌逛骇涓氬洯鍖哄強閰嶅鍩虹璁炬柦寤鸿椤圭洰纾嬪晢鍏憡</span
-            >
-            <span>2024-04-15 18:10</span>
-          </div>
-          <div class="item">
-            <span
-              ><span style="color: #145ccd; font-weight: 600">路</span
-              >銆愬洓宸濈渷鎴愰兘甯傘�戠唺鐚胺娓稿涓績灞�閮ㄦ敼閫犻」鐩鍟嗗叕鍛�</span
-            >
-            <span>2024-04-15 18:10</span>
-          </div>
-          <div class="item">
-            <span
-              ><span style="color: #145ccd; font-weight: 600">路</span
-              >銆愬洓宸濈渷鎴愰兘甯傘�戜腹鏅閬撴皯婀栫ぞ鍖虹孩鐧藉枩浜嬫湇鍔″満鎵�纾嬪晢鍏憡</span
-            >
-            <span>2024-04-15 18:10</span>
-          </div>
-          <div class="item">
-            <span
-              ><span style="color: #145ccd; font-weight: 600">路</span
-              >銆愬洓宸濈渷鎴愰兘甯傘�戞垚閮戒笢閮ㄦ柊鍖轰笁宀旀箹楂樼骇涓浣撹壓涓績鍓嶄复鏃跺仠杞﹀尯鍜屾鏍¢棬涓や晶闂ㄥ崼瀹ら棿鍖哄煙榛戝寲鍙婃帓姘存彁鍗囪В闄ゅ唴娑濋」鐩鍟嗗叕鍛�</span
-            >
-            <span>2024-04-15 18:10</span>
-          </div>
-          <div class="item">
-            <span
-              ><span style="color: #145ccd; font-weight: 600">路</span
-              >銆愬洓宸濈渷鎴愰兘甯傘�戝洓宸濈渷鎴愰兘鎴掓瘨搴峰鎵�鐥呮畫鎴掓瘨浜哄憳搴峰娲诲姩涓績缁翠慨鏀归�犻」鐩浜屾纾嬪晢鍏憡</span
-            >
-            <span>2024-04-15 18:10</span>
-          </div>
-          <div class="item">
-            <span
-              ><span style="color: #145ccd; font-weight: 600">路</span
-              >銆愬洓宸濈渷鎴愰兘甯傘�戣�佸共閮ㄦ椿鍔ㄤ腑蹇冭淇敼閫犻」鐩鍟嗗叕鍛�</span
-            >
-            <span>2024-04-15 18:10</span>
-          </div>
-          <div class="item">
-            <span
-              ><span style="color: #145ccd; font-weight: 600">路</span
-              >銆愬洓宸濈渷鎴愰兘甯傘�戦噾鐗涘尯鎶㈤櫓鏁戠伨宸ョ▼椤圭洰宸ョ▼闃熶紞鍌ㄥ搴擄紙鎴垮缓銆佸競鏀跨被锛夋嫑鏍囧叕鍛�</span
-            >
-            <span>2024-04-15 18:10</span>
-          </div> -->
-        </el-tab-pane>
+          鎰忓悜鍏紑 -->
+      <div class="item">
+        <span
+          ><span style="color: #145ccd; font-weight: 600">路</span
+          >銆愬洓宸濈渷鎴愰兘甯傘��2024骞寸煶鐩樿閬撲粯瀹剁鏉戠伯娌逛骇涓氬洯鍖哄強閰嶅鍩虹璁炬柦寤鸿椤圭洰纾嬪晢鍏憡</span
+        >
+        <span>2024-04-15 18:10</span>
+      </div>
+      <div class="item">
+        <span
+          ><span style="color: #145ccd; font-weight: 600">路</span
+          >銆愬洓宸濈渷鎴愰兘甯傘�戠唺鐚胺娓稿涓績灞�閮ㄦ敼閫犻」鐩鍟嗗叕鍛�</span
+        >
+        <span>2024-04-15 18:10</span>
+      </div>
+      <div class="item">
+        <span
+          ><span style="color: #145ccd; font-weight: 600">路</span
+          >銆愬洓宸濈渷鎴愰兘甯傘�戜腹鏅閬撴皯婀栫ぞ鍖虹孩鐧藉枩浜嬫湇鍔″満鎵�纾嬪晢鍏憡</span
+        >
+        <span>2024-04-15 18:10</span>
+      </div>
+      <div class="item">
+        <span
+          ><span style="color: #145ccd; font-weight: 600">路</span
+          >銆愬洓宸濈渷鎴愰兘甯傘�戞垚閮戒笢閮ㄦ柊鍖轰笁宀旀箹楂樼骇涓浣撹壓涓績鍓嶄复鏃跺仠杞﹀尯鍜屾鏍¢棬涓や晶闂ㄥ崼瀹ら棿鍖哄煙榛戝寲鍙婃帓姘存彁鍗囪В闄ゅ唴娑濋」鐩鍟嗗叕鍛�</span
+        >
+        <span>2024-04-15 18:10</span>
+      </div>
+      <div class="item">
+        <span
+          ><span style="color: #145ccd; font-weight: 600">路</span
+          >銆愬洓宸濈渷鎴愰兘甯傘�戝洓宸濈渷鎴愰兘鎴掓瘨搴峰鎵�鐥呮畫鎴掓瘨浜哄憳搴峰娲诲姩涓績缁翠慨鏀归�犻」鐩浜屾纾嬪晢鍏憡</span
+        >
+        <span>2024-04-15 18:10</span>
+      </div>
+      <div class="item">
+        <span
+          ><span style="color: #145ccd; font-weight: 600">路</span
+          >銆愬洓宸濈渷鎴愰兘甯傘�戣�佸共閮ㄦ椿鍔ㄤ腑蹇冭淇敼閫犻」鐩鍟嗗叕鍛�</span
+        >
+        <span>2024-04-15 18:10</span>
+      </div>
+      <div class="item">
+        <span
+          ><span style="color: #145ccd; font-weight: 600">路</span
+          >銆愬洓宸濈渷鎴愰兘甯傘�戦噾鐗涘尯鎶㈤櫓鏁戠伨宸ョ▼椤圭洰宸ョ▼闃熶紞鍌ㄥ搴擄紙鎴垮缓銆佸競鏀跨被锛夋嫑鏍囧叕鍛�</span
+        >
+        <span>2024-04-15 18:10</span>
+      </div>
+      <div class="item">
+        <span
+          ><span style="color: #145ccd; font-weight: 600">路</span
+          >銆愬洓宸濈渷鎴愰兘甯傘�戦噾鐗涘尯鎶㈤櫓鏁戠伨宸ョ▼椤圭洰宸ョ▼闃熶紞鍌ㄥ搴擄紙鎴垮缓銆佸競鏀跨被锛夋嫑鏍囧叕鍛�</span
+        >
+        <span>2024-04-15 18:10</span>
+      </div>
+      <!-- </el-tab-pane>
         <el-tab-pane label="宸ョ▼鎷涙爣" name="second">宸ョ▼鎷涙爣</el-tab-pane>
         <el-tab-pane label="璐х墿鎷涙爣" name="third">璐х墿鎷涙爣</el-tab-pane>
         <el-tab-pane label="鏈嶅姟鎷涙爣" name="fourth">鏈嶅姟鎷涙爣</el-tab-pane>
-        <el-tab-pane label="缃戜笂绔炰环" name="fourth">缃戜笂绔炰环</el-tab-pane>
-      </el-tabs>
+        <el-tab-pane label="缃戜笂绔炰环" name="fourth1">缃戜笂绔炰环</el-tab-pane>
+      </el-tabs> -->
     </div>
   </div>
   <div class="daixie">
@@ -140,7 +148,7 @@
   <div class="user">
     <div class="all">
       <div class="left">
-        <div class="item item1">
+        <div v-for="item in state.roleList" :key="item.id" class="item item1">
           <div class="box">
             <img
               width="18px"
@@ -148,65 +156,44 @@
               src="@/assets/home/car1.png"
               alt=""
             />
-            閲囪喘浜�
+            {{ item.name }}
           </div>
           <div>
-            <span class="hover:cursor-pointer" @click="toRegister">娉ㄥ唽</span
-            ><span class="m-2">|</span
-            ><span class="hover:cursor-pointer" @click="toLogin">鐧诲綍</span>
-          </div>
-        </div>
-        <div class="item">
-          <div class="box">
-            <img
-              width="18px"
-              height="18px"
-              src="@/assets/home/car.png"
-              alt=""
-            />
-            浠g悊鏈烘瀯
-          </div>
-          <div>
-            <span class="hover:cursor-pointer" @click="toRegister">娉ㄥ唽</span
-            ><span class="m-2">|</span
-            ><span class="hover:cursor-pointer" @click="toLogin">鐧诲綍</span>
-          </div>
-        </div>
-        <div class="item">
-          <div class="box">
-            <img
-              width="18px"
-              height="18px"
-              src="@/assets/home/car.png"
-              alt=""
-            />渚涘簲鍟�
-          </div>
-          <div>
-            <span class="hover:cursor-pointer" @click="toRegister">娉ㄥ唽</span
-            ><span class="m-2">|</span
-            ><span class="hover:cursor-pointer" @click="toLogin">鐧诲綍</span>
-          </div>
-        </div>
-        <div class="item">
-          <div class="box">
-            <img
-              width="18px"
-              height="18px"
-              src="@/assets/home/car.png"
-              alt=""
-            />璇勫涓撳
-          </div>
-          <div>
-            <span class="hover:cursor-pointer" @click="toRegister">娉ㄥ唽</span
-            ><span class="m-2">|</span
-            ><span class="hover:cursor-pointer" @click="toLogin">鐧诲綍</span>
+            <el-link
+              v-if="state.rolesCode.indexOf(item.code) !== -1"
+              :underline="false"
+              class="hover:cursor-pointer"
+              @click="toRegister"
+              >閫�鍑�</el-link
+            >
+            <el-link
+              v-else
+              :underline="false"
+              class="hover:cursor-pointer"
+              @click="toRegister"
+              >鐢宠</el-link
+            ><span class="m-2">|</span>
+            <el-link
+              v-if="state.rolesCode.indexOf(item.code) !== -1"
+              :underline="false"
+              class="hover:cursor-pointer"
+              @click="toWelcome"
+              >杩涘叆</el-link
+            >
+            <el-link
+              v-else
+              :underline="false"
+              class="hover:cursor-pointer"
+              :disabled="state.accessToken"
+              @click="toLogin"
+              >鐧诲綍</el-link
+            >
           </div>
         </div>
       </div>
       <div class="right" />
     </div>
   </div>
-
   <div class="more">
     <div class="content">
       <div class="item">
@@ -399,16 +386,45 @@
 </template>
 
 <script lang="ts" setup>
-import { ref } from "vue";
+import { onMounted, ref, computed, reactive } from "vue";
 import myFooter from "./component/myFooter.vue";
-let activeName = ref("first");
+import { useUserStoreHook } from "@/store/modules/user";
+import { exRole } from "@/api/register/index.ts";
+import { storageLocal, isString, isIncludeAllChildren } from "@pureadmin/utils";
+
+import { getToken } from "@/utils/auth";
 import { useRoute, useRouter } from "vue-router";
 defineOptions({
-  name: "Home"
+  name: "Main"
 });
+let activeName = ref("first");
+/** 瑙掕壊锛堝鏋滄樀绉颁负绌哄垯鏄剧ず鐢ㄦ埛鍚嶏級 */
+const getUseRoles = () => {
+  state.userInfo = storageLocal().getItem("user-info");
+  state.userInfo.exRoles.forEach(element => {
+    state.rolesCode.push(element.code);
+  });
+};
+const state = reactive({
+  roleList: [],
+  rolesCode: [],
+  userInfo: {},
+  accessToken: ""
+});
+onMounted(() => {
+  exRole().then(res => {
+    state.roleList = res.result;
+  });
+  getUseRoles();
+  state.accessToken = getToken().accessToken;
+});
+
 const router = useRouter();
 const toRegister = () => {
   router.push({ name: "Register" });
+};
+const toWelcome = () => {
+  router.push({ name: "Welcome" });
 };
 const toLogin = () => {
   router.push({ name: "Login" });
@@ -552,9 +568,12 @@
         justify-content: space-between;
         align-items: center;
         padding: 0 30px;
-        height: 25%;
+        height: 23%;
         text-align: left;
         color: #5f5f5f;
+        // box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;
+        border-radius: 6px;
+        margin-bottom: 10px;
         .box {
           display: flex;
           justify-content: center;
@@ -569,13 +588,13 @@
         color: #ffffff;
       }
     }
-    .left :first-child {
-      border-top-left-radius: 8px;
-      border-top-right-radius: 8px;
-    }
-    .left *:not(:first-child):not(:last-child) {
-      border-bottom: #c6c6c6 1px solid;
-    }
+    // .left :first-child {
+    //   border-top-left-radius: 8px;
+    //   border-top-right-radius: 8px;
+    // }
+    // .left *:not(:first-child):not(:last-child) {
+    //   border-bottom: #c6c6c6 1px solid;
+    // }
     .right {
       background: #a9b3c4;
       width: 75%;
@@ -721,4 +740,14 @@
     border-radius: 4px;
   }
 }
+a {
+  font-size: 16px;
+
+  // font-weight: 600;
+  color: #fff;
+}
+a:hover,
+a:active {
+  color: #fff;
+}
 </style>
diff --git a/src/views/item/component/editDialog.vue b/src/views/item/component/editDialog.vue
new file mode 100644
index 0000000..b54d199
--- /dev/null
+++ b/src/views/item/component/editDialog.vue
@@ -0,0 +1,193 @@
+锘�<script lang="ts" name="procurementComplaint" setup>
+import { ref, reactive, onMounted } from 'vue';
+import { ElMessage } from 'element-plus';
+import type { FormRules } from 'element-plus';
+import { formatDate } from '/@/utils/formatTime';
+import { useProcurementComplaintApi } from '/@/api/fb_p_complaints/procurementComplaint';
+import { log } from 'console';
+
+//鐖剁骇浼犻�掓潵鐨勫嚱鏁帮紝鐢ㄤ簬鍥炶皟
+const emit = defineEmits(['reloadTable']);
+const procurementComplaintApi = useProcurementComplaintApi();
+const ruleFormRef = ref();
+
+const state = reactive({
+	title: '',
+	loading: false,
+	showDialog: false,
+	ruleForm: {
+		complaints: [{ itemDescription: '' }],
+	} as any,
+	stores: {},
+	dropdownData: {} as any,
+});
+
+const handlingStatus = [
+	{ value: 0, label: '鍏跺畠' },
+	{ value: 1, label: '鎴愮珛' },
+	{ value: 2, label: '椹冲洖' },
+	{ value: 3, label: '閮ㄥ垎鎴愮珛' },
+];
+
+// 鑷娣诲姞鍏朵粬瑙勫垯
+const rules = ref<FormRules>({
+	projectCode: [{ required: true, message: '璇烽�夋嫨椤圭洰缂栧彿锛�', trigger: 'blur' }],
+	projectName: [{ required: true, message: '璇烽�夋嫨椤圭洰鍚嶇О锛�', trigger: 'blur' }],
+	decisionDate: [{ required: true, message: '璇烽�夋嫨鍐冲畾鏃ユ湡锛�', trigger: 'change' }],
+	purchaser: [{ required: true, message: '璇烽�夋嫨閲囪喘浜猴紒', trigger: 'blur' }],
+	procurementAgency: [{ required: true, message: '璇烽�夋嫨閲囪喘浠g悊鏈烘瀯锛�', trigger: 'blur' }],
+});
+
+// 椤甸潰鍔犺浇鏃�
+onMounted(async () => {});
+
+// 鎵撳紑寮圭獥
+const openDialog = async (row: any, title: string) => {
+	state.title = title;
+	row = row ?? { complaints: [{ itemDescription: '' }] };
+	state.ruleForm = row.id ? await procurementComplaintApi.detail(row.id).then((res) => res.data.result) : JSON.parse(JSON.stringify(row));
+	state.showDialog = true;
+	console.log(state.ruleForm.complaints, state.ruleForm.complaints.length);
+};
+
+// 鍏抽棴寮圭獥
+const closeDialog = () => {
+	emit('reloadTable');
+	state.showDialog = false;
+};
+
+// 鎻愪氦
+const submit = async () => {
+	ruleFormRef.value.validate(async (isValid: boolean, fields?: any) => {
+		if (isValid) {
+			let values = state.ruleForm;
+			await procurementComplaintApi[state.ruleForm.id ? 'update' : 'add'](values);
+			closeDialog();
+		} else {
+			ElMessage({
+				message: `琛ㄥ崟鏈�${Object.keys(fields).length}澶勯獙璇佸け璐ワ紝璇蜂慨鏀瑰悗鍐嶆彁浜,
+				type: 'error',
+			});
+		}
+	});
+};
+
+const changeComplaints = (index:any,txt: String) => {
+	if (txt == 'add') {
+		state.ruleForm.complaints.splice(index+1, 0, { itemDescription: '' })
+	} else {
+		state.ruleForm.complaints.splice(index, 1)
+	}
+};
+
+//灏嗗睘鎬ф垨鑰呭嚱鏁版毚闇茬粰鐖剁粍浠�
+defineExpose({ openDialog });
+</script>
+<template>
+  <div class="procurementComplaint-container">
+    <el-dialog v-model="state.showDialog" :width="900" draggable :close-on-click-modal="false">
+      <template #header>
+        <div style="color: #fff">
+          <span>{{ state.title }}</span>
+        </div>
+      </template>
+      <el-form :model="state.ruleForm" ref="ruleFormRef" label-width="auto" :rules="rules">
+        <el-row :gutter="35">
+          <el-form-item v-show="false">
+            <el-input v-model="state.ruleForm.id" />
+          </el-form-item>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+            <el-form-item label="鍐冲畾鏃ユ湡" prop="decisionDate">
+              <el-date-picker v-model="state.ruleForm.decisionDate" type="date" placeholder="璇烽�夋嫨鍐冲畾鏃ユ湡" />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+            <el-form-item label="椤圭洰鍚嶇О" prop="projectName">
+              <el-input v-model="state.ruleForm.projectName" placeholder="璇疯緭鍏ラ」鐩悕绉�" maxlength="200" show-word-limit
+                clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+            <el-form-item label="椤圭洰缂栧彿" prop="projectCode">
+              <el-input v-model="state.ruleForm.projectCode" placeholder="璇疯緭鍏ラ」鐩紪鍙�" maxlength="50" show-word-limit
+                clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+            <el-form-item label="閲囪喘浜�" prop="purchaser">
+              <el-input v-model="state.ruleForm.purchaser" placeholder="璇疯緭鍏ラ噰璐汉" maxlength="100" show-word-limit
+                clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+            <el-form-item label="閲囪喘浠g悊鏈烘瀯" prop="procurementAgency">
+              <el-input v-model="state.ruleForm.procurementAgency" placeholder="璇疯緭鍏ラ噰璐唬鐞嗘満鏋�" maxlength="100"
+                show-word-limit clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+            <el-form-item label="閲囪喘鐩戠潱閮ㄩ棬" prop="procurementSupervisionDepartment">
+              <el-input v-model="state.ruleForm.procurementSupervisionDepartment" placeholder="璇疯緭鍏ラ噰璐洃鐫i儴闂�"
+                maxlength="100" show-word-limit clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+            <el-form-item label="鎶曡瘔浜�" prop="complainant">
+              <el-input v-model="state.ruleForm.complainant" placeholder="璇疯緭鍏ユ姇璇変汉" maxlength="100" show-word-limit
+                clearable />
+            </el-form-item>
+          </el-col>
+          <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+            <el-form-item label="绾夸笂鍦板潃" prop="url">
+              <el-input v-model="state.ruleForm.url" placeholder="璇疯緭鍏ョ嚎涓婂湴鍧�" maxlength="255" show-word-limit clearable />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <template v-for="(item,index) in state.ruleForm.complaints" :key="index">
+            <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+              <el-form-item :label="`鎶曡瘔浜嬮」${index==0?'':index}`" prop="complaints">
+                <el-input v-model="item.itemDescription" type="textarea" :placeholder="`璇疯緭鍏ユ姇璇変簨椤�${index==0?'':index}`"
+                  maxlength="1000" show-word-limit clearable />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12" class="">
+              <el-form-item :label="`澶勭悊鎻忚堪${index==0?'':index}`" prop="complaints">
+                <el-input v-model="item.handlingResult" type="textarea" :placeholder="`璇疯緭鍏ュ鐞嗘弿杩�${index==0?'':index}`"
+                  maxlength="1000" show-word-limit clearable />
+              </el-form-item>
+            </el-col>
+            <el-col :xs="6" :sm="6" :md="6" :lg="6" :xl="6" class="mb20">
+              <el-form-item :label="`鎶曡瘔鐘舵��${index==0?'':index}`" prop="complaints">
+                <el-select v-model="item.handlingStatus">
+                  <el-option v-for="item in handlingStatus" :key="item.value" :label="item.label" :value="item.value" />
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="1" :sm="1" :md="1" :lg="1" :xl="1" class="mb20">
+              <el-button type="primary" @click="changeComplaints(index,'add')">+</el-button>
+            </el-col>
+            <el-col :xs="1" :sm="1" :md="1" :lg="1" :xl="1" class="mb20"
+              v-if="state.ruleForm.complaints&&state.ruleForm.complaints.length>1">
+              <el-button type="primary" @click="changeComplaints(index)">-</el-button>
+            </el-col>
+            <el-divider v-if="state.ruleForm.complaints&&state.ruleForm.complaints.length>1" />
+          </template>
+
+        </el-row>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="() => state.showDialog = false">鍙� 娑�</el-button>
+          <el-button @click="submit" type="primary" v-reclick="1000">纭� 瀹�</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+<style lang="scss" scoped>
+:deep(.el-select),
+:deep(.el-input-number) {
+	width: 100%;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/item/index.vue b/src/views/item/index.vue
new file mode 100644
index 0000000..fa46f25
--- /dev/null
+++ b/src/views/item/index.vue
@@ -0,0 +1,506 @@
+锘�<script lang="ts" setup name="procurementComplaint">
+import { ref, reactive, onMounted } from "vue";
+import { ElMessageBox, ElMessage } from "element-plus";
+// import { downloadStreamFile } from "@/utils/download";
+import { useProcurementComplaintApi } from "/@/api/fb_p_complaints/procurementComplaint";
+import editDialog from "/@/views/fb_p_complaints/procurementComplaint/component/editDialog.vue";
+import printDialog from "/@/views/system/print/component/hiprint/preview.vue";
+import ModifyRecord from "/@/components/table/modifyRecord.vue";
+import ImportData from "/@/components/table/importData.vue";
+import commonFunction from "@/utils/commonFunction";
+
+const { dateFormatYMD } = commonFunction();
+const procurementComplaintApi = useProcurementComplaintApi();
+const printDialogRef = ref();
+const editDialogRef = ref();
+const importDataRef = ref();
+const state = reactive({
+  exportLoading: false,
+  tableLoading: false,
+  stores: {},
+  showAdvanceQueryUI: false,
+  dropdownData: {} as any,
+  selectData: [] as any[],
+  tableQueryParams: {} as any,
+  tableParams: {
+    page: 1,
+    pageSize: 20,
+    total: 0,
+    field: "decisionDate", // 榛樿鐨勬帓搴忓瓧娈�
+    order: "descending", // 鎺掑簭鏂瑰悜
+    descStr: "descending" // 闄嶅簭鎺掑簭鐨勫叧閿瓧绗�
+  },
+  tableData: []
+});
+
+// 椤甸潰鍔犺浇鏃�
+onMounted(async () => {});
+
+// 鏌ヨ鎿嶄綔
+const handleQuery = async (params: any = {}) => {
+  state.tableLoading = true;
+  state.tableParams = Object.assign(state.tableParams, params);
+  const result = await procurementComplaintApi
+    .page(Object.assign(state.tableQueryParams, state.tableParams))
+    .then(res => res.data.result);
+  state.tableParams.total = result?.total;
+  state.tableData = result?.items ?? [];
+  state.tableLoading = false;
+};
+
+// 鍒楁帓搴�
+const sortChange = async (column: any) => {
+  state.tableParams.field = column.prop;
+  state.tableParams.order = column.order;
+  await handleQuery();
+};
+
+// 鍒犻櫎
+const delProcurementComplaint = (row: any) => {
+  ElMessageBox.confirm(`纭畾瑕佸垹闄ゅ悧?`, "鎻愮ず", {
+    confirmButtonText: "纭畾",
+    cancelButtonText: "鍙栨秷",
+    type: "warning"
+  })
+    .then(async () => {
+      await procurementComplaintApi.delete({ id: row.id });
+      handleQuery();
+      ElMessage.success("鍒犻櫎鎴愬姛");
+    })
+    .catch(() => {});
+};
+
+// 鎵归噺鍒犻櫎
+const batchDelProcurementComplaint = () => {
+  ElMessageBox.confirm(
+    `纭畾瑕佸垹闄�${state.selectData.length}鏉¤褰曞悧?`,
+    "鎻愮ず",
+    {
+      confirmButtonText: "纭畾",
+      cancelButtonText: "鍙栨秷",
+      type: "warning"
+    }
+  )
+    .then(async () => {
+      await procurementComplaintApi
+        .batchDelete(state.selectData.map(u => ({ id: u.id })))
+        .then(res => {
+          ElMessage.success(`鎴愬姛鎵归噺鍒犻櫎${res.data.result}鏉¤褰昤);
+          handleQuery();
+        });
+    })
+    .catch(() => {});
+};
+
+// 瀵煎嚭鏁版嵁
+const exportProcurementComplaintCommand = async (command: string) => {
+  try {
+    state.exportLoading = true;
+    if (command === "select") {
+      const params = Object.assign(
+        {},
+        state.tableQueryParams,
+        state.tableParams,
+        { selectKeyList: state.selectData.map(u => u.id) }
+      );
+      await procurementComplaintApi
+        .exportData(params)
+        .then(res => downloadStreamFile(res));
+    } else if (command === "current") {
+      const params = Object.assign(
+        {},
+        state.tableQueryParams,
+        state.tableParams
+      );
+      await procurementComplaintApi
+        .exportData(params)
+        .then(res => downloadStreamFile(res));
+    } else if (command === "all") {
+      const params = Object.assign(
+        {},
+        state.tableQueryParams,
+        state.tableParams,
+        { page: 1, pageSize: 99999999 }
+      );
+      await procurementComplaintApi
+        .exportData(params)
+        .then(res => downloadStreamFile(res));
+    }
+  } finally {
+    state.exportLoading = false;
+  }
+};
+
+handleQuery();
+</script>
+<template>
+  <div v-loading="state.exportLoading" class="procurementComplaint-container">
+    <el-card shadow="hover" :body-style="{ paddingBottom: '0' }">
+      <el-form ref="queryForm" :model="state.tableQueryParams" labelWidth="90">
+        <el-row>
+          <el-col :xs="24" :sm="12" :md="12" :lg="5" :xl="4" class="mb10">
+            <el-form-item label="鍐冲畾鏃ユ湡">
+              <el-date-picker
+                v-model="state.tableQueryParams.decisionDateRange"
+                type="daterange"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                start-placeholder="寮�濮嬫棩鏈�"
+                end-placeholder="缁撴潫鏃ユ湡"
+                :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col
+            v-if="state.showAdvanceQueryUI"
+            :xs="24"
+            :sm="12"
+            :md="12"
+            :lg="4"
+            :xl="4"
+            class="mb10"
+          >
+            <el-form-item label="椤圭洰鍚嶇О">
+              <el-input
+                v-model="state.tableQueryParams.projectName"
+                clearable
+                placeholder="璇疯緭鍏ラ」鐩悕绉�"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col
+            v-if="state.showAdvanceQueryUI"
+            :xs="24"
+            :sm="12"
+            :md="12"
+            :lg="4"
+            :xl="4"
+            class="mb10"
+          >
+            <el-form-item label="椤圭洰缂栧彿">
+              <el-input
+                v-model="state.tableQueryParams.projectCode"
+                clearable
+                placeholder="璇疯緭鍏ラ」鐩紪鍙�"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col
+            v-if="state.showAdvanceQueryUI"
+            :xs="24"
+            :sm="12"
+            :md="12"
+            :lg="4"
+            :xl="4"
+            class="mb10"
+          >
+            <el-form-item label="閲囪喘浜�">
+              <el-input
+                v-model="state.tableQueryParams.purchaser"
+                clearable
+                placeholder="璇疯緭鍏ラ噰璐汉"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col
+            v-if="state.showAdvanceQueryUI"
+            :xs="24"
+            :sm="12"
+            :md="12"
+            :lg="4"
+            :xl="4"
+            class="mb10"
+          >
+            <el-form-item label="閲囪喘浠g悊鏈烘瀯">
+              <el-input
+                v-model="state.tableQueryParams.procurementAgency"
+                clearable
+                placeholder="璇疯緭鍏ラ噰璐唬鐞嗘満鏋�"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col
+            v-if="state.showAdvanceQueryUI"
+            :xs="24"
+            :sm="12"
+            :md="12"
+            :lg="5"
+            :xl="4"
+            class="mb10"
+          >
+            <el-form-item label="閲囪喘鐩戠潱閮ㄩ棬">
+              <el-input
+                v-model="
+                  state.tableQueryParams.procurementSupervisionDepartment
+                "
+                clearable
+                placeholder="璇疯緭鍏ラ噰璐洃鐫i儴闂�"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col
+            v-if="state.showAdvanceQueryUI"
+            :xs="24"
+            :sm="12"
+            :md="12"
+            :lg="4"
+            :xl="4"
+            class="mb10"
+          >
+            <el-form-item label="鎶曡瘔浜�">
+              <el-input
+                v-model="state.tableQueryParams.complainant"
+                clearable
+                placeholder="璇疯緭鍏ユ姇璇変汉"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col
+            v-if="state.showAdvanceQueryUI"
+            :xs="24"
+            :sm="12"
+            :md="12"
+            :lg="4"
+            :xl="4"
+            class="mb10"
+          >
+            <el-form-item label="鎶曡瘔浜嬮」">
+              <el-input
+                v-model="state.tableQueryParams.keyword"
+                clearable
+                placeholder="璇疯緭鍏ユ姇璇変簨椤�"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col
+            v-if="state.showAdvanceQueryUI"
+            :xs="24"
+            :sm="12"
+            :md="12"
+            :lg="4"
+            :xl="4"
+            class="mb10"
+          >
+            <el-form-item label="鏄惁鎴愮珛">
+              <el-select
+                v-model="state.tableQueryParams.status"
+                placeholder="璇烽�夋嫨"
+                clearable
+              >
+                <el-option label="鎴愮珛" value="Valid" />
+                <el-option label="椹冲洖" value="Rejected" />
+                <el-option label="鍏跺畠" value="Other" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+
+          <!-- <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="4" class="mb10">
+            <el-form-item label="鍏抽敭瀛�">
+              <el-input v-model="state.tableQueryParams.keyword" clearable placeholder="璇疯緭鍏ユā绯婃煡璇㈠叧閿瓧"/>
+            </el-form-item>
+          </el-col> -->
+          <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="4" class="mb10">
+            <el-form-item>
+              <el-button-group style="display: flex; align-items: center">
+                <el-button
+                  v-reclick="1000"
+                  type="primary"
+                  icon="ele-Search"
+                  @click="handleQuery"
+                >
+                  鏌ヨ
+                </el-button>
+                <el-button
+                  icon="ele-Refresh"
+                  @click="() => (state.tableQueryParams = {})"
+                >
+                  閲嶇疆
+                </el-button>
+                <el-button
+                  v-if="!state.showAdvanceQueryUI"
+                  icon="ele-ZoomIn"
+                  style="margin-left: 5px"
+                  @click="() => (state.showAdvanceQueryUI = true)"
+                >
+                  楂樼骇鏌ヨ
+                </el-button>
+                <el-button
+                  v-if="state.showAdvanceQueryUI"
+                  icon="ele-ZoomOut"
+                  style="margin-left: 5px"
+                  @click="() => (state.showAdvanceQueryUI = false)"
+                >
+                  闅愯棌
+                </el-button>
+                <el-button
+                  type="danger"
+                  style="margin-left: 5px"
+                  icon="ele-Delete"
+                  :disabled="state.selectData.length == 0"
+                  @click="batchDelProcurementComplaint"
+                >
+                  鍒犻櫎
+                </el-button>
+                <el-button
+                  type="primary"
+                  style="margin-left: 5px"
+                  icon="ele-Plus"
+                  @click="
+                    editDialogRef.openDialog(null, '鏂板鏀垮簻閲囪喘鎶曡瘔鏁版嵁澶勭悊')
+                  "
+                >
+                  鏂板
+                </el-button>
+                <!-- <el-dropdown :show-timeout="70" :hide-timeout="50" @command="exportProcurementComplaintCommand">
+                  <el-button type="primary" style="margin-left:5px;" icon="ele-FolderOpened" v-reclick="20000"
+                    v-auth="'procurementComplaint:export'"> 瀵煎嚭 </el-button>
+                  <template #dropdown>
+                    <el-dropdown-menu>
+                      <el-dropdown-item command="select"
+                        :disabled="state.selectData.length == 0">瀵煎嚭閫変腑</el-dropdown-item>
+                      <el-dropdown-item command="current">瀵煎嚭鏈〉</el-dropdown-item>
+                      <el-dropdown-item command="all">瀵煎嚭鍏ㄩ儴</el-dropdown-item>
+                    </el-dropdown-menu>
+                  </template>
+                </el-dropdown>
+                <el-button type="warning" style="margin-left:5px;" icon="ele-MostlyCloudy"
+                  @click="importDataRef.openDialog()" v-auth="'procurementComplaint:import'"> 瀵煎叆 </el-button> -->
+              </el-button-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </el-card>
+    <el-card class="full-table" shadow="hover" style="margin-top: 5px">
+      <el-table
+        v-loading="state.tableLoading"
+        :data="state.tableData"
+        :default-sort="{ prop: 'decisionDate', order: 'descending' }"
+        style="width: 100%"
+        tooltip-effect="light"
+        row-key="id"
+        border
+        @selection-change="
+          (val: any[]) => {
+            state.selectData = val;
+          }
+        "
+        @sort-change="sortChange"
+      >
+        <el-table-column type="selection" width="40" align="center" />
+        <el-table-column type="index" label="搴忓彿" width="55" align="center" />
+        <el-table-column
+          prop="decisionDate"
+          label="鍐冲畾鏃ユ湡"
+          width="90"
+          show-overflow-tooltip
+          sortable
+        >
+          <template #default="{ row }">
+            <span>{{ dateFormatYMD(null, null, row.decisionDate) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="projectName"
+          label="椤圭洰鍚嶇О"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="projectCode"
+          label="椤圭洰缂栧彿"
+          width="135"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="purchaser"
+          label="閲囪喘浜�"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="procurementAgency"
+          label="閲囪喘浠g悊鏈烘瀯"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="complainant"
+          label="鎶曡瘔浜�"
+          show-overflow-tooltip
+        />
+        <el-table-column
+          prop="procurementSupervisionDepartment"
+          label="閲囪喘鐩戠潱閮ㄩ棬"
+          width="140"
+          show-overflow-tooltip
+        />
+        <!-- <el-table-column prop='complaints' label='鏄惁鎴愮珛' show-overflow-tooltip /> -->
+        <el-table-column prop="url" label="绾夸笂鍦板潃" show-overflow-tooltip>
+          <template #default="{ row }">
+            <el-link underline :href="row.url" target="_blank">{{
+              row.url
+            }}</el-link>
+          </template>
+        </el-table-column>
+        <!-- <el-table-column label="淇敼璁板綍" width="100" align="center" show-overflow-tooltip>
+          <template #default="scope">
+            <ModifyRecord :data="scope.row" />
+          </template>
+        </el-table-column> -->
+        <el-table-column
+          label="鎿嶄綔"
+          width="70"
+          align="center"
+          fixed="right"
+          show-overflow-tooltip
+        >
+          <template #default="scope">
+            <el-button
+              icon="ele-Edit"
+              size="small"
+              text
+              type="primary"
+              @click="
+                editDialogRef.openDialog(scope.row, '缂栬緫鏀垮簻閲囪喘鎶曡瘔鏁版嵁澶勭悊')
+              "
+            />
+            <el-button
+              icon="ele-Delete"
+              size="small"
+              text
+              type="primary"
+              @click="delProcurementComplaint(scope.row)"
+            />
+          </template>
+        </el-table-column>
+      </el-table>
+      <el-pagination
+        v-model:currentPage="state.tableParams.page"
+        v-model:page-size="state.tableParams.pageSize"
+        layout="total, sizes, prev, pager, next, jumper"
+        :page-sizes="[10, 20, 50, 100, 200, 500]"
+        :total="state.tableParams.total"
+        size="small"
+        background
+        @size-change="(val: any) => handleQuery({ pageSize: val })"
+        @current-change="(val: any) => handleQuery({ page: val })"
+      />
+      <ImportData
+        ref="importDataRef"
+        :import="procurementComplaintApi.importData"
+        :download="procurementComplaintApi.downloadTemplate"
+        @refresh="handleQuery"
+      />
+      <printDialog
+        ref="printDialogRef"
+        :title="'鎵撳嵃鏀垮簻閲囪喘鎶曡瘔鏁版嵁澶勭悊'"
+        @reloadTable="handleQuery"
+      />
+      <editDialog ref="editDialogRef" @reloadTable="handleQuery" />
+    </el-card>
+  </div>
+</template>
+<style scoped>
+:deep(.el-input),
+:deep(.el-select),
+:deep(.el-input-number) {
+  width: 100%;
+}
+</style>
diff --git a/src/views/login/index.vue b/src/views/login/index.vue
index 15a2618..a9ca3a2 100644
--- a/src/views/login/index.vue
+++ b/src/views/login/index.vue
@@ -172,7 +172,7 @@
             return initRouter().then(() => {
               disabled.value = true;
               router
-                .push(getTopMenu(true)?.path)
+                .replace("index")
                 .then(() => {
                   message("鐧诲綍鎴愬姛", { type: "success" });
                 })
diff --git a/types/index.d.ts b/types/index.d.ts
index 404601a..fb58067 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -14,7 +14,8 @@
 type ForDataType<T> = {
   [P in T]?: ForDataType<T[P]>;
 };
-
+// 鐢虫槑 鏁扮粍
+declare type EmptyArrayType<T = any> = T[];
 type AnyFunction<T> = (...args: any[]) => T;
 
 type PropType<T> = VuePropType<T>;

--
Gitblit v1.9.1