瀏覽代碼

feat: 指标接口

ystl_myq 7 月之前
父節點
當前提交
047023d679

+ 2 - 1
package.json

@@ -77,7 +77,8 @@
     "vue": "^3.4.21",
     "vue-router": "^4.3.0",
     "vue-tippy": "^6.4.1",
-    "vue-types": "^5.1.1"
+    "vue-types": "^5.1.1",
+    "xlsx": "^0.18.5"
   },
   "devDependencies": {
     "@commitlint/cli": "^19.2.1",

+ 72 - 0
pnpm-lock.yaml

@@ -92,6 +92,9 @@ importers:
       vue-types:
         specifier: ^5.1.1
         version: 5.1.1(vue@3.4.21(typescript@5.4.3))
+      xlsx:
+        specifier: ^0.18.5
+        version: 0.18.5
     devDependencies:
       '@commitlint/cli':
         specifier: ^19.2.1
@@ -1264,6 +1267,10 @@ packages:
     engines: {node: '>=0.4.0'}
     hasBin: true
 
+  adler-32@1.3.1:
+    resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==}
+    engines: {node: '>=0.8'}
+
   ajv@6.12.6:
     resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
 
@@ -1408,6 +1415,10 @@ packages:
   caniuse-lite@1.0.30001600:
     resolution: {integrity: sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==}
 
+  cfb@1.2.2:
+    resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==}
+    engines: {node: '>=0.8'}
+
   chalk@2.4.2:
     resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
     engines: {node: '>=4'}
@@ -1451,6 +1462,10 @@ packages:
     resolution: {integrity: sha512-+mxuCHo7ESOQadlsyMjmPZ4hGBtvQzmNGHfLdBNvXKbnRhtmOTslU4XF2cyFSaOCHaaF26ba2CGjU6lpeIFB0w==}
     hasBin: true
 
+  codepage@1.15.0:
+    resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==}
+    engines: {node: '>=0.8'}
+
   color-convert@1.9.3:
     resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
 
@@ -1542,6 +1557,11 @@ packages:
       typescript:
         optional: true
 
+  crc-32@1.2.2:
+    resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
+    engines: {node: '>=0.8'}
+    hasBin: true
+
   cross-spawn@7.0.3:
     resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
     engines: {node: '>= 8'}
@@ -1958,6 +1978,10 @@ packages:
     resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
     engines: {node: '>= 6'}
 
+  frac@1.1.2:
+    resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==}
+    engines: {node: '>=0.8'}
+
   fraction.js@4.3.7:
     resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
 
@@ -3332,6 +3356,10 @@ packages:
     resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
     engines: {node: '>= 10.x'}
 
+  ssf@0.11.2:
+    resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==}
+    engines: {node: '>=0.8'}
+
   stable@0.1.8:
     resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==}
     deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility'
@@ -3756,6 +3784,14 @@ packages:
     resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==}
     engines: {node: '>=12'}
 
+  wmf@1.0.2:
+    resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==}
+    engines: {node: '>=0.8'}
+
+  word@0.3.0:
+    resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==}
+    engines: {node: '>=0.8'}
+
   wrap-ansi@7.0.0:
     resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
     engines: {node: '>=10'}
@@ -3775,6 +3811,11 @@ packages:
     resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
 
+  xlsx@0.18.5:
+    resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==}
+    engines: {node: '>=0.8'}
+    hasBin: true
+
   xml-name-validator@4.0.0:
     resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
     engines: {node: '>=12'}
@@ -4866,6 +4907,8 @@ snapshots:
 
   acorn@8.11.3: {}
 
+  adler-32@1.3.1: {}
+
   ajv@6.12.6:
     dependencies:
       fast-deep-equal: 3.1.3
@@ -5028,6 +5071,11 @@ snapshots:
 
   caniuse-lite@1.0.30001600: {}
 
+  cfb@1.2.2:
+    dependencies:
+      adler-32: 1.3.1
+      crc-32: 1.2.2
+
   chalk@2.4.2:
     dependencies:
       ansi-styles: 3.2.1
@@ -5080,6 +5128,8 @@ snapshots:
 
   cloc@2.11.0: {}
 
+  codepage@1.15.0: {}
+
   color-convert@1.9.3:
     dependencies:
       color-name: 1.1.3
@@ -5164,6 +5214,8 @@ snapshots:
     optionalDependencies:
       typescript: 5.4.3
 
+  crc-32@1.2.2: {}
+
   cross-spawn@7.0.3:
     dependencies:
       path-key: 3.1.1
@@ -5713,6 +5765,8 @@ snapshots:
       combined-stream: 1.0.8
       mime-types: 2.1.35
 
+  frac@1.1.2: {}
+
   fraction.js@4.3.7: {}
 
   framesync@6.1.2:
@@ -6973,6 +7027,10 @@ snapshots:
 
   split2@4.2.0: {}
 
+  ssf@0.11.2:
+    dependencies:
+      frac: 1.1.2
+
   stable@0.1.8: {}
 
   std-env@3.7.0:
@@ -7484,6 +7542,10 @@ snapshots:
     dependencies:
       string-width: 5.1.2
 
+  wmf@1.0.2: {}
+
+  word@0.3.0: {}
+
   wrap-ansi@7.0.0:
     dependencies:
       ansi-styles: 4.3.0
@@ -7509,6 +7571,16 @@ snapshots:
       imurmurhash: 0.1.4
       signal-exit: 4.1.0
 
+  xlsx@0.18.5:
+    dependencies:
+      adler-32: 1.3.1
+      cfb: 1.2.2
+      codepage: 1.15.0
+      crc-32: 1.2.2
+      ssf: 0.11.2
+      wmf: 1.0.2
+      word: 0.3.0
+
   xml-name-validator@4.0.0: {}
 
   y18n@5.0.8: {}

+ 30 - 0
src/api/download.ts

@@ -0,0 +1,30 @@
+// / 下载模板
+import axios from "axios";
+const FLIE_URL = import.meta.env.VITE_BASE_URL + "/quota/downloaQuotaTemplate";
+import { ElMessage } from "element-plus";
+export const GetdownloadDataRosterTemplateApi = async () => {
+  const token = localStorage.getItem("token") || "";
+  try {
+    const response = await axios.get(FLIE_URL, {
+      responseType: "blob", // 确保接收的是二进制数据
+      headers: {
+        satoken: token // 将 token 添加到请求头
+      }
+    });
+    // 创建 Blob 对象并生成下载链接
+    const blob = new Blob([response.data], {
+      type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+    });
+    const link = document.createElement("a");
+    link.href = URL.createObjectURL(blob);
+    link.download = "模板.xlsx"; // 文件名
+    document.body.appendChild(link);
+    link.click();
+    // 清理 DOM
+    document.body.removeChild(link);
+    URL.revokeObjectURL(link.href);
+    ElMessage.success("模板下载成功");
+  } catch (error) {
+    ElMessage.error("模板下载失败,请重试");
+  }
+};

+ 38 - 0
src/api/indexDefine.ts

@@ -0,0 +1,38 @@
+import { http } from "@/utils/http";
+// 指标列表
+type QuotaPage = {
+  code: number;
+  msg: string;
+  data: boolean;
+};
+type QuotaPageList = {
+  code: number;
+  msg: string;
+  data: Array<any>;
+};
+// 分页查询
+export const getQuotaPageList = params => {
+  return http.request<QuotaPageList>("get", "/quota/getQuotaPageList", {
+    params
+  });
+};
+// 添加
+export const addQuota = data => {
+  return http.request<QuotaPage>("post", "/quota/addQuota", { data });
+};
+// 删除
+export const delQuota = id => {
+  return http.request<QuotaPage>("get", `/quota/delQuota/id=${id}`);
+};
+// 修改
+export const postUpdateDept = data => {
+  return http.request<QuotaPage>("post", "/quota/updateQuota", { data });
+};
+// // 下载
+export const GetdownloadDataRosterTemplate = () => {
+  return http.request<any>("get", "/quota/downloaQuotaTemplate");
+};
+// 批量导入
+export const postImportQuotaTemplate = data => {
+  return http.request<QuotaPage>("post", "/quota/importQuotaTemplate", data);
+};

+ 69 - 32
src/views/indexDefine/children/components/dialog.vue

@@ -1,33 +1,67 @@
 <script setup lang="ts">
 import { reactive, computed, ref } from "vue";
 import { ElMessage } from "element-plus";
+import { addQuota } from "@/api/indexDefine";
 const emit = defineEmits(["closeDialog"]);
 const visible = ref(false);
 const ruleFormRef = ref(null);
 const form = reactive({
   name: "",
-  region: "",
-  date1: "",
-  date2: "",
-  delivery: false,
-  type: [],
-  resource: "",
-  desc: ""
+  categoryName: "",
+  define: "",
+  caliber: "",
+  source: "",
+  statue: null
+});
+const msgName = ref("");
+const addQuotaApi = async () => {
+  ruleFormRef.value.validate(async (valid: boolean) => {
+    if (valid) {
+      const { code, msg } = await addQuota(form);
+      if (code === 200) {
+        ElMessage({
+          message: "添加成功",
+          type: "success"
+        });
+        emit("closeDialog");
+      }
+      if (code === 10027) {
+        msgName.value = msg;
+        // rules.name[0].message = msg; // 将 msg 设置为 name 字段的错误信息
+        // ruleFormRef.value.validateField("name"); // 触发验证以显示错误消息
+      }
+    }
+  });
+};
+const rules = reactive({
+  name: [{ required: true, message: "请填写指标名称", trigger: "blur" }],
+  define: [{ required: true, message: "请填写指标分类", trigger: "blur" }],
+  categoryName: [
+    { required: true, message: "请填写指标定义", trigger: "blur" }
+  ],
+  caliber: [{ required: true, message: "请填写指标口径", trigger: "blur" }],
+  source: [{ required: true, message: "来源", trigger: "blur" }],
+  statue: [{ required: true, message: "请填写选择状态", trigger: "blur" }]
 });
 const close = () => {
   // 请关闭弹框
+  console.log(visible.value);
   visible.value = false;
 };
 const save = () => {
-  // 保存
-  ElMessage({
-    message: "保存成功",
-    type: "success"
-  });
-  emit("closeDialog");
+  addQuotaApi();
 };
 const open = () => {
   // 打开弹框
+  const form = {
+    name: "",
+    categoryName: "",
+    define: "",
+    caliber: "",
+    source: "",
+    statue: null
+  };
+  msgName.value = "";
   visible.value = true;
   console.log("打开弹框");
 };
@@ -44,55 +78,52 @@ defineExpose({
         :model="form"
         label-position="right"
         label-width="auto"
+        :rules="rules"
         style="max-width: 600px"
       >
-        <el-form-item label="指标名称">
+        <el-form-item label="指标名称" prop="name">
           <el-input
             v-model="form.name"
             autocomplete="off"
             placeholder="请输入"
           />
+          <el-text v-if="msgName" class="absolute top-6 msgName" type="warning">
+            指标名称已存在,请更换一个名称
+          </el-text>
         </el-form-item>
         <el-form-item label="指标分类">
-          <el-select v-model="form.region" placeholder="请选择">
+          <el-select v-model="form.categoryName" placeholder="请选择">
             <el-option label="Zone No.1" value="shanghai" />
             <el-option label="Zone No.2" value="beijing" />
           </el-select>
         </el-form-item>
-        <el-form-item label="指标定义">
+        <el-form-item label="指标定义" prop="define">
           <el-input
-            v-model="form.name"
+            v-model="form.define"
             type="textarea"
             autocomplete="off"
             placeholder="请输入"
           />
         </el-form-item>
-        <el-form-item label="指标口径">
+        <el-form-item label="指标口径" prop="caliber">
           <el-input
-            v-model="form.name"
+            v-model="form.caliber"
             type="textarea"
             autocomplete="off"
             placeholder="请输入"
           />
         </el-form-item>
         <el-form-item label="来源">
-          <el-select v-model="form.region" placeholder="请选择">
+          <el-select v-model="form.source" placeholder="请选择">
             <el-option label="Zone No.1" value="shanghai" />
             <el-option label="Zone No.2" value="beijing" />
           </el-select>
         </el-form-item>
-        <el-form-item label="SQL语句">
-          <el-input
-            v-model="form.name"
-            type="textarea"
-            autocomplete="off"
-            placeholder="请输入"
-          />
-        </el-form-item>
-        <el-form-item label="状态">
-          <el-select v-model="form.region" placeholder="请选择">
-            <el-option label="Zone No.1" value="shanghai" />
-            <el-option label="Zone No.2" value="beijing" />
+        <el-form-item label="状态" prop="statue">
+          <el-select v-model="form.statue" placeholder="请选择">
+            <el-option label="草稿" value="0" />
+            <el-option label="发布" value="1" />
+            <el-option label="下架" value="2" />
           </el-select>
         </el-form-item>
       </el-form>
@@ -105,3 +136,9 @@ defineExpose({
     </template>
   </el-dialog>
 </template>
+
+<style lang="scss" scope>
+.msgName {
+  font-size: 10px;
+}
+</style>

+ 23 - 3
src/views/indexDefine/children/components/editDrawer.vue

@@ -1,15 +1,22 @@
 <script setup lang="ts">
 import { ref, reactive } from "vue";
-import { ElMessageBox } from "element-plus";
+import { ElMessage, ElMessageBox } from "element-plus";
 import type { DrawerProps, FormItemProps, FormProps } from "element-plus";
+import { postUpdateDept } from "@/api/indexDefine";
+const emit = defineEmits(["EditDrawer"]);
+
 // const itemLabelPosition = ref<FormItemProps["labelPosition"]>("");
 const drawer = ref(false);
 const disabledShow = ref<any>(true);
 const direction = ref<DrawerProps["direction"]>("rtl");
 const formLabelAlign = reactive({
+  id: "",
   name: "",
-  region: "",
-  type: ""
+  categoryName: "",
+  define: "",
+  caliber: "",
+  source: "",
+  statue: null
 });
 const handleClose = (done: () => void) => {
   ElMessageBox.confirm("配置项未保存,确认关闭", {
@@ -22,12 +29,25 @@ const handleClose = (done: () => void) => {
 function cancelClick() {
   disabledShow.value = true;
 }
+// 确认
+const postUpdateDeptApi = async () => {
+  const { code } = await postUpdateDept(formLabelAlign);
+  if (code === 200) {
+    ElMessage({
+      message: "添加成功",
+      type: "success"
+    });
+    emit("EditDrawer");
+  }
+};
 function confirmClick() {
   console.log(1111);
   disabledShow.value = true;
   drawer.value = false;
+  postUpdateDeptApi();
 }
 const open = row => {
+  Object.assign(formLabelAlign, row);
   drawer.value = true;
 };
 // 编辑

+ 56 - 47
src/views/indexDefine/children/define.vue

@@ -2,7 +2,7 @@
 defineOptions({
   name: "IndexDefine"
 });
-import { ref, markRaw } from "vue";
+import { ref, reactive, markRaw } from "vue";
 import dialogVue from "./components/dialog.vue";
 import editDrawer from "./components/editDrawer.vue";
 import logDrawer from "./components/logDrawer.vue";
@@ -11,6 +11,7 @@ import { Edit, More } from "@element-plus/icons-vue";
 import { ElMessage, ElMessageBox } from "element-plus";
 import { Delete, Check } from "@element-plus/icons-vue";
 import { Search } from "@element-plus/icons-vue";
+import { getQuotaPageList, delQuota } from "@/api/indexDefine";
 const value = ref("");
 const dialogShow = ref();
 const EditdrawerShow = ref();
@@ -40,39 +41,35 @@ const options = [
     label: "Option5"
   }
 ];
-const tableData = [
-  {
-    date: "2016-05-03",
-    name: "Tom",
-    address: "No. 189, Grove St, Los Angeles",
-    show: false
-  },
-  {
-    date: "2016-05-02",
-    name: "Tom",
-    address: "No. 189, Grove St, Los Angeles",
-    show: false
-  },
-  {
-    date: "2016-05-04",
-    name: "Tom",
-    address: "No. 189, Grove St, Los Angeles",
-    show: false
-  },
-  {
-    date: "2016-05-01",
-    name: "Tom",
-    address: "No. 189, Grove St, Los Angeles",
-    show: false
-  }
-];
 const currentPage4 = ref(5);
 const pageSize4 = ref(100);
+const params = reactive({
+  params: {
+    pageNumber: 1,
+    pageSize: 10
+  },
+  records: [],
+  total: 0
+});
+// 分页
+const getQuotaPageListApi = async () => {
+  const { code, data } = await getQuotaPageList(params.params);
+  console.log("code", data);
+  if (code === 200) {
+    params.records = data.records;
+    params.total = data.totalRow;
+  }
+};
+getQuotaPageListApi();
 const handleSizeChange = (val: number) => {
-  console.log(`${val} items per page`);
+  console.log("a4val1111", val);
+  params.params.pageSize = val;
+  getQuotaPageListApi();
 };
 const handleCurrentChange = (val: number) => {
-  console.log(`current page: ${val}`);
+  console.log("a4va2222222", val);
+  params.params.pageNumber = val;
+  getQuotaPageListApi();
 };
 const showDialog = ref(false);
 const newAddIndex = () => {
@@ -81,14 +78,25 @@ const newAddIndex = () => {
 };
 const close = () => {
   showDialog.value = false;
+  getQuotaPageListApi();
 };
 // 编辑
 const setEdit = row => {
   EditshowDrawer.value = true;
-  EditdrawerShow.value.open();
+  EditdrawerShow.value.open(row);
   console.log(row);
 };
 // 删除
+const delQuotaApi = async row => {
+  const { code } = await delQuota(row.id);
+  if (code === 200) {
+    ElMessage({
+      type: "success",
+      message: "删除成功"
+    });
+    getQuotaPageListApi();
+  }
+};
 const setDelete = row => {
   console.log(row);
   ElMessageBox.confirm("指标删除后无法恢复", "确定要删除这项指标吗", {
@@ -98,10 +106,7 @@ const setDelete = row => {
     icon: markRaw(Delete)
   })
     .then(() => {
-      ElMessage({
-        type: "success",
-        message: "删除成功"
-      });
+      delQuotaApi(row);
     })
     .catch(() => {
       ElMessage({
@@ -168,7 +173,11 @@ const offShelf = row => {
     <IndexDefineImport v-if="sizeImport" @handleImport="GoSizeImport" />
     <div v-else>
       <!-- 指标详情 -->
-      <editDrawer ref="EditdrawerShow" v-model:drawerValue="EditshowDrawer" />
+      <editDrawer
+        ref="EditdrawerShow"
+        v-model:drawerValue="EditshowDrawer"
+        @closeEditDialog="getQuotaPageListApi"
+      />
       <!-- 新建 -->
       <dialogVue
         ref="dialogShow"
@@ -229,10 +238,10 @@ const offShelf = row => {
         </div>
       </div>
       <div class="mt-8">
-        <el-table :data="tableData" style="width: 100%">
-          <el-table-column prop="date" label="指标编号" width="100" />
+        <el-table :data="params.records" style="width: 100%">
+          <el-table-column prop="id" label="指标编号" width="100" />
           <el-table-column prop="name" label="指标名称" />
-          <el-table-column prop="address" label="指标分类" />
+          <el-table-column prop="categoryName" label="指标分类" />
           <el-table-column prop="address" label="状态">
             <template #default="{ row }">
               <el-tag type="primary" effect="dark">
@@ -248,18 +257,18 @@ const offShelf = row => {
             <template #default="{ row }">
               <!-- <el-button link :icon="Edit" /> -->
               <el-dropdown trigger="click">
-                <span class="el-dropdown-link navbar-bg-hover select-none">
-                  <el-icon @click="setEdit(row)"><Edit /></el-icon>
+                <span class="el-dropdown-link navbar-bg-hover select-none pt-1">
+                  <el-text type="primary" @click="setEdit(row)">编辑</el-text>
                 </span>
               </el-dropdown>
               <el-dropdown class="ml-2" trigger="click">
-                <span class="el-dropdown-link navbar-bg-hover select-none">
-                  <el-icon><More /></el-icon>
+                <span class="el-dropdown-link navbar-bg-hover select-none pt-1">
+                  <el-text type="primary">更多</el-text>
                 </span>
                 <template #dropdown>
                   <el-dropdown-menu class="setting">
                     <el-dropdown-item @click="setDelete(row)">
-                      删除
+                      <el-text type="danger">删除</el-text>
                     </el-dropdown-item>
                     <el-dropdown-item @click="release(row)">
                       发布
@@ -280,11 +289,11 @@ const offShelf = row => {
       </div>
       <div class="float-right mt-8">
         <el-pagination
-          v-model:current-page="currentPage4"
-          v-model:page-size="pageSize4"
-          :page-sizes="[100, 200, 300, 400]"
+          v-model:current-page="params.params.pageNumber"
+          v-model:page-size="params.params.pageSize"
+          :page-sizes="[10, 15, 20, 25]"
           layout="total, sizes, prev, pager, next, jumper"
-          :total="400"
+          :total="params.total"
           @size-change="handleSizeChange"
           @current-change="handleCurrentChange"
         />

+ 82 - 38
src/views/indexDefine/children/import/index.vue

@@ -1,51 +1,94 @@
 <script setup lang="ts">
-import { ref } from "vue";
 defineOptions({
   name: "IndexDefineImport"
 });
+import { ref } from "vue";
+import * as XLSX from "xlsx";
+import { postImportQuotaTemplate } from "@/api/indexDefine";
+import { GetdownloadDataRosterTemplateApi } from "@/api/download";
+import { ElMessage } from "element-plus";
+
 const emit = defineEmits(["handleImport"]);
 const uploadShow = ref(true);
-const uploadFile = () => {
-  uploadShow.value = !uploadShow.value;
-};
-const tableData = [
-  {
-    date: "2016-05-03",
-    name: "Tom",
-    address: "No. 189, Grove St, Los Angeles"
-  },
-  {
-    date: "2016-05-02",
-    name: "Tom",
-    address: "No. 189, Grove St, Los Angeles"
-  },
-  {
-    date: "2016-05-04",
-    name: "Tom",
-    address: "No. 189, Grove St, Los Angeles"
-  },
-  {
-    date: "2016-05-01",
-    name: "Tom",
-    address: "No. 189, Grove St, Los Angeles"
+const fileDocument = ref<File | null>(null); // 存储文件
+
+// 上传文件函数
+const uploadFile = async () => {
+  if (!fileDocument.value) {
+    ElMessage.error("请先上传文件");
+    return;
   }
-];
+
+  try {
+    const formData = new FormData();
+    formData.append("file", fileDocument.value); // 将文件添加到 FormData 中
+
+    const { code } = await postImportQuotaTemplate(formData); // 发送 FormData
+    if (code === 200) {
+      ElMessage.success("上传成功");
+      emit("handleImport");
+    }
+  } catch (error) {
+    console.error("上传文件时出错:", error);
+    ElMessage.error("上传文件时出错,请检查文件格式");
+  }
+};
+
+const tableHeaders = ref<any>([]);
+const tableData = ref<any>([
+  { name: "" },
+  { defin: "" },
+  { caliber: "" },
+  { type: "" },
+  { from: "" }
+]);
+
 const backDefine = () => {
   emit("handleImport");
 };
+
+// 处理文件上传并解析 Excel 内容
+const handleUploadChange = (file: File) => {
+  fileDocument.value = file; // 保存文件
+  const reader = new FileReader();
+
+  reader.onload = e => {
+    const data = new Uint8Array(e.target?.result as ArrayBuffer);
+    const workbook = XLSX.read(data, { type: "array" }); // 读取 Excel 文件
+    const firstSheetName = workbook.SheetNames[0]; // 获取第一个工作表名
+    const worksheet = workbook.Sheets[firstSheetName]; // 获取第一个工作表
+    const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 }); // 将工作表转为 JSON
+
+    if (jsonData.length > 0) {
+      tableHeaders.value = jsonData[0]; // 表头
+      tableData.value = jsonData.slice(1).map(row => {
+        const rowData = {};
+        tableHeaders.value.forEach((header, index) => {
+          rowData[header] = row[index] !== undefined ? row[index] : null; // 填充缺失值
+        });
+        return rowData;
+      });
+      ElMessage.success("文件上传成功");
+      uploadShow.value = false; // 隐藏上传区域,显示数据表
+    } else {
+      ElMessage.error("文件为空或格式不正确");
+    }
+  };
+
+  reader.readAsArrayBuffer(file); // 读取文件为 ArrayBuffer
+};
 </script>
 
 <template>
   <div>
     <div class="w-3/4 m-auto mt-4">
       <div class="w-full bg p-3">
-        <el-button class="float-right" @click="backDefine">返回</el-button>
+        <!-- <el-button class="float-right" @click="backDefine">返回</el-button> -->
         <h5>1.下载导入模板</h5>
-
         <p class="text-xs mt-2 text">根据提升信息完善表格内容</p>
-        <el-button class="mt-2"
-          ><el-icon><Download /></el-icon>下载空的模板表格</el-button
-        >
+        <el-button class="mt-2" @click="GetdownloadDataRosterTemplateApi">
+          <el-icon> <Download /> </el-icon>下载空的模板表格
+        </el-button>
       </div>
       <div class="w-full mt-4 bg p-3">
         <h5>2.上传完善后的模板</h5>
@@ -56,8 +99,9 @@ const backDefine = () => {
           <el-upload
             class="upload-demo"
             drag
-            action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
             multiple
+            :before-upload="file => handleUploadChange(file)"
+            :show-file-list="false"
           >
             <el-icon class="el-icon--upload"><upload-filled /></el-icon>
             <div class="el-upload__text">
@@ -72,15 +116,16 @@ const backDefine = () => {
             style="width: 100%"
             max-height="250"
           >
-            <el-table-column prop="date" label="指标编号" width="180" />
-            <el-table-column prop="name" label="指标名称" width="180" />
-            <el-table-column prop="address" label="指标分类" />
-            <el-table-column prop="address" label="指标定义" />
-            <el-table-column prop="address" label="指标口径" />
+            <el-table-column
+              v-for="header in tableHeaders"
+              :key="header"
+              :label="header"
+              :prop="header"
+            />
           </el-table>
         </div>
         <div class="float-right">
-          <el-button>取消</el-button>
+          <el-button @click="backDefine">取消</el-button>
           <el-button type="primary" @click="uploadFile">确认</el-button>
         </div>
         <p class="h-11 no-select">.</p>
@@ -88,7 +133,6 @@ const backDefine = () => {
     </div>
   </div>
 </template>
-
 <style lang="scss" scoped>
 .bg {
   background-color: #f8f9fa;

+ 2 - 2
src/views/login/index.vue

@@ -41,8 +41,8 @@ dataThemeChange();
 const { title } = useNav();
 
 const ruleForm = reactive({
-  username: "",
-  password: ""
+  username: "admin",
+  password: "123456"
 });
 const handleBlur = () => {
   // @ts-ignore