Kaynağa Gözat

调用记录,接口管理

zouzs 1 hafta önce
ebeveyn
işleme
4f7b3dd07f

+ 0 - 0
src/api/system/user.ts → src/api/system/ipAccount.ts


+ 122 - 0
src/api/system/ipInterface.ts

@@ -0,0 +1,122 @@
+import { http } from "@/utils/http";
+import { interfaceUrlApi } from "../utils";
+
+export interface BasicResponseModel<T = any> {
+  code: number;
+  msg: string;
+  list: T;
+  data: T;
+  total: number;
+}
+
+/**
+ * 获取接口列表
+ * @param query
+ */
+export const getIpInterfaceList = (query?: object) => {
+  return http.get<BasicResponseModel, any>(
+    interfaceUrlApi("ipInterface/list"),
+    {
+      params: query
+    }
+  );
+};
+
+/**
+ * 新增或编辑接口
+ * @param data
+ */
+export const addOrEditIpInterface = (data?: object) => {
+  return http.post<BasicResponseModel, any>(
+    interfaceUrlApi("ipInterface/saveOrUpdate"),
+    {
+      data
+    }
+  );
+};
+
+/**
+ * 删除接口
+ * @param id
+ */
+export const deleteIpInterface = (id: number) => {
+  return http.request<BasicResponseModel>(
+    "delete",
+    interfaceUrlApi(`ipInterface/delete/${id}`)
+  );
+};
+
+/**
+ * 查询账号下关联的接口列表
+ * @param query
+ */
+export const getIpAccountInterfaceList = (query?: object) => {
+  return http.post<BasicResponseModel, any>(
+    interfaceUrlApi("ipInterface/account/ref/list"),
+    {
+      data: query
+    }
+  );
+};
+
+/**
+ * 接口下拉列表
+ * @param query
+ */
+export const getIpInterfaceOptionList = (query?: object) => {
+  return http.post<BasicResponseModel, any>(
+    interfaceUrlApi("ipInterface/optionList"),
+    {
+      params: query
+    }
+  );
+};
+
+/**
+ * 保存账号关联的接口
+ * @param data
+ */
+export const addOrEditIpAccountInterfaceRef = (data?: object) => {
+  return http.post<BasicResponseModel, any>(
+    interfaceUrlApi("ipInterface/interfaceConfig"),
+    {
+      data
+    }
+  );
+};
+
+/**
+ * 切换接口状态
+ * @param data
+ */
+export const switchIpInterfaceStatus = (data?: object) => {
+  return http.post<BasicResponseModel, any>(
+    interfaceUrlApi(`ipInterface/switchStatus`),
+    {
+      data
+    }
+  );
+};
+
+/**
+ * 切换账号关联的接口状态
+ * @param data
+ */
+export const switchIpAccountInterfaceStatus = (data?: object) => {
+  return http.post<BasicResponseModel, any>(
+    interfaceUrlApi(`ipInterface/account/interface/ref/switchStatus`),
+    {
+      data
+    }
+  );
+};
+
+/**
+ * 生成token
+ */
+export const generateIpAccountToken = () => {
+  return http.request<BasicResponseModel>(
+    "post",
+    interfaceUrlApi(`ipInterface/token/generate`)
+  );
+};

+ 45 - 0
src/api/system/ipInterfaceCall.ts

@@ -0,0 +1,45 @@
+import { http } from "@/utils/http";
+import { interfaceUrlApi } from "../utils";
+
+export interface BasicResponseModel<T = any> {
+  code: number;
+  msg: string;
+  list: T;
+  data: T;
+  total: number;
+}
+
+/**
+ * 获取调用记录列表
+ * @param query
+ */
+export const getIpInterfaceCallList = (query?: object) => {
+  return http.get<BasicResponseModel, any>(
+    interfaceUrlApi("ipInterface/call/list"),
+    {
+      params: query
+    }
+  );
+};
+
+/**
+ * 根据ID获取调用记录详细信息
+ * @param id
+ */
+export const getIpInterfaceCallDetailById = (id: string) => {
+  return http.request<BasicResponseModel>(
+    "get",
+    interfaceUrlApi(`ipInterface/call/detail/${id}`)
+  );
+};
+
+/**
+ * 查询接口回调记录
+ * @param id
+ */
+export const getIpInterfaceCallRecord = (id: string) => {
+  return http.request<BasicResponseModel>(
+    "get",
+    interfaceUrlApi(`ipInterface/call/callback/history/${id}`)
+  );
+};

+ 18 - 0
src/router/modules/ipAccount.ts

@@ -0,0 +1,18 @@
+// 最简代码,也就是这些字段必须有
+export default {
+  path: "/ipAccount",
+  meta: {
+    title: "账户管理",
+    showLink: false
+  },
+  children: [
+    {
+      path: "/ipAccount/ipAccountInterface",
+      name: "IpAccountInterface",
+      component: () => import("@/views/ipAccount/ipAccountInterface.vue"),
+      meta: {
+        title: "Token管理"
+      }
+    }
+  ]
+} as RouteConfigsTable;

+ 19 - 0
src/router/modules/ipInterfaceCall.ts

@@ -0,0 +1,19 @@
+// 最简代码,也就是这些字段必须有
+export default {
+  path: "/ipInterfaceCall",
+  meta: {
+    title: "调用记录",
+    showLink: false
+  },
+  children: [
+    {
+      path: "/ipInterfaceCall/ipInterfaceCallDetail",
+      name: "IpInterfaceCallDetail",
+      component: () =>
+        import("@/views/ipInterfaceCall/ipInterfaceCallDetail.vue"),
+      meta: {
+        title: "接口调用明细"
+      }
+    }
+  ]
+} as RouteConfigsTable;

+ 63 - 6
src/views/user/index.vue → src/views/ipAccount/index.vue

@@ -10,7 +10,7 @@
         showNumber: 3
       }"
       :table="{
-        actionBar: { buttons, type: 'link', width: 140 },
+        actionBar: { buttons, type: 'link', width: 180 },
         adaptive: { offsetBottom: 50 },
         onFormChange: handleTableChange
       }"
@@ -59,12 +59,17 @@ import {
   deleteIpAccount,
   getIpAccountList,
   switchIpAccountStatus
-} from "@/api/system/user";
+} from "@/api/system/ipAccount";
+import { isString } from "@pureadmin/utils";
+import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
+import { useRouter } from "vue-router";
 
 defineOptions({
-  name: "User"
+  name: "IpAccountIndex"
 });
 
+const router = useRouter();
+
 const plusPageInstance = ref<PlusPageInstance | null>(null);
 
 const getList = async (query: Record<string, any>) => {
@@ -127,9 +132,20 @@ const tableConfig: PlusColumn[] = [
     editable: true,
     hideInSearch: true
   },
+  {
+    label: "状态",
+    prop: "status",
+    valueType: "select",
+    options: [
+      { label: "正常", value: "normal" },
+      { label: "停用", value: "disable" }
+    ],
+    hideInTable: true
+  },
   {
     label: "备注",
-    prop: "remark"
+    prop: "remark",
+    hideInSearch: true
   },
   {
     label: "创建时间",
@@ -166,14 +182,19 @@ const state = reactive<State>({
   selectedIds: [],
   isCreate: false,
   form: {},
-  rules: {}
+  rules: {
+    accNo: [{ required: true, message: "请输入账户号", trigger: "blur" }]
+  }
 });
 
 const columns: PlusColumn[] = [
   {
     label: "账户号",
     prop: "accNo",
-    valueType: "input"
+    valueType: "input",
+    fieldProps: {
+      disabled: computed(() => !state.isCreate)
+    }
   },
   {
     label: "状态",
@@ -262,6 +283,42 @@ buttons.value = [
       state.dialogVisible = true;
     }
   },
+  {
+    // 修改
+    text: "管理接口",
+    code: "interface",
+    // props v0.1.16 版本新增函数类型
+    props: {
+      type: "primary"
+    },
+    onClick(val) {
+      console.log("handleClick", val.row.accNo);
+      let params = {
+        accNo: val.row.accNo,
+        accountId: val.row.id
+      };
+      Object.keys(params).forEach(param => {
+        if (!isString(params[param])) {
+          params[param] = params[param].toString();
+        }
+      });
+      // 保存信息到标签页
+      useMultiTagsStoreHook().handleTags("push", {
+        path: `/ipAccount/ipAccountInterface`,
+        name: "IpAccountInterface",
+        query: params,
+        meta: {
+          title: `Token管理`,
+          // 如果使用的是非国际化精简版title可以像下面这么写
+          // title: `No.${index} - 详情信息`,
+          // 最大打开标签数
+          dynamicLevel: 1
+        }
+      });
+      // 路由跳转
+      router.push({ name: "IpAccountInterface", query: params });
+    }
+  },
   {
     // 删除
     text: "删除",

+ 552 - 0
src/views/ipAccount/ipAccountInterface.vue

@@ -0,0 +1,552 @@
+<template>
+  <div>
+    <PlusPage
+      ref="plusPageInstance"
+      :columns="tableConfig"
+      :request="getList"
+      :is-card="true"
+      :search="{
+        labelWidth: 100,
+        showNumber: 3,
+        defaultValues: defaultValues
+      }"
+      :table="{
+        actionBar: { buttons, type: 'link', width: 180 },
+        adaptive: { offsetBottom: 50 },
+        onFormChange: handleTableChange
+      }"
+      :pageInfoMap="{ page: 'pageNum', pageSize: 'pageSize' }"
+    >
+      <template #table-title>
+        <el-row class="button-row">
+          <el-button size="default" type="success" @click="handleCreate">
+            新增
+          </el-button>
+        </el-row>
+      </template>
+    </PlusPage>
+    <!-- 弹窗编辑 -->
+    <PlusDialogForm
+      ref="dialogForm"
+      v-model="form"
+      v-model:visible="dialogVisible"
+      :form="{
+        columns,
+        labelPosition: 'right',
+        labelWidth: 100,
+        rowProps: { gutter: 20 },
+        colProps: { span: 24 },
+        rules
+      }"
+      :dialog="{ title: dialogTitle + '菜单', width: 800, confirmLoading }"
+      @confirm="handleSubmit"
+      @close="handleClose"
+    />
+    <PlusDialog
+      v-model="detailsVisible"
+      title="密钥"
+      :hasFooter="false"
+      width="400"
+    >
+      <PlusDescriptions
+        :column="24"
+        :columns="descriptionsColumns"
+        :data="descriptionsData"
+      />
+    </PlusDialog>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { computed, onMounted, reactive, ref, toRefs, h } from "vue";
+import type { FormRules } from "element-plus";
+import { ElMessage, ElMessageBox, ElInput, ElButton } from "element-plus";
+import {
+  type FieldValues,
+  type PlusColumn,
+  PlusDescriptions,
+  PlusDialog,
+  PlusDialogForm,
+  PlusPage,
+  PlusPageInstance,
+  useTable
+} from "plus-pro-components";
+import { deleteIpAccount } from "@/api/system/ipAccount";
+import {
+  switchIpAccountInterfaceStatus,
+  addOrEditIpAccountInterfaceRef,
+  generateIpAccountToken,
+  getIpAccountInterfaceList,
+  getIpInterfaceOptionList
+} from "@/api/system/ipInterface";
+import { isString } from "@pureadmin/utils";
+import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
+import { useRouter, useRoute } from "vue-router";
+
+defineOptions({
+  name: "IpAccountIndex"
+});
+
+const route = useRoute();
+const router = useRouter();
+
+onMounted(() => {
+  getInterfaceOptions();
+});
+
+const plusPageInstance = ref<PlusPageInstance | null>(null);
+
+const defaultValues = {
+  accountId: isString(route.query.accountId)
+    ? route.query.accountId.toString()
+    : "",
+  accNo: isString(route.query.accNo) ? route.query.accNo.toString() : ""
+};
+
+const getList = async (query: Record<string, any>) => {
+  let res = await getIpAccountInterfaceList(query);
+  return {
+    data: res.list,
+    total: res.total
+  };
+};
+
+// 重新请求列表接口
+const refresh = () => {
+  plusPageInstance.value?.getList();
+};
+
+const handleTableChange = (values: any) => {
+  console.log(values);
+  ElMessageBox.confirm("确定修改此数据吗?", "提示", {
+    confirmButtonText: "确定",
+    cancelButtonText: "取消",
+    type: "warning"
+  })
+    .then(async () => {
+      try {
+        let data = {
+          id: values.row.id,
+          status: values.row.status
+        };
+        let res = await switchIpAccountInterfaceStatus(data);
+        if (res.code === 200) {
+          ElMessage.success("修改成功");
+        } else {
+          ElMessage.error(res.msg);
+        }
+      } catch (e) {
+        ElMessage.error("修改失败");
+      }
+    })
+    .finally(() => {
+      refresh();
+    });
+};
+
+const dialogTitle = computed(() => (state.isCreate ? "新增" : "编辑"));
+
+// 表格数据
+const tableConfig: PlusColumn[] = [
+  {
+    label: "账户号",
+    prop: "accNo",
+    valueType: "input",
+    hideInTable: true
+  },
+  {
+    label: "账户id",
+    prop: "id",
+    hideInSearch: true,
+    hideInTable: true
+  },
+  {
+    label: "接口名称",
+    prop: "interfaceName",
+    hideInSearch: true
+  },
+  {
+    label: "接口厂商",
+    prop: "manufacturer",
+    hideInSearch: true
+  },
+  {
+    label: "状态",
+    prop: "status",
+    valueType: "switch",
+    fieldProps: {
+      activeValue: "normal",
+      inactiveValue: "disable"
+    },
+    editable: true,
+    hideInSearch: true
+  },
+  {
+    label: "状态",
+    prop: "status",
+    valueType: "select",
+    fieldProps: {
+      options: [
+        { label: "正常", value: "normal" },
+        { label: "禁用", value: "disable" }
+      ],
+      clearable: true
+    },
+    hideInTable: true
+  },
+  {
+    label: "备注",
+    prop: "remark",
+    hideInSearch: true
+  },
+  {
+    label: "是否回调",
+    prop: "callback",
+    valueType: "tag",
+    fieldProps: value => ({
+      type: value === true ? "success" : "info"
+    }),
+    formatter: value => (value === true ? "是" : "否"),
+    hideInSearch: true
+  },
+  {
+    label: "创建时间",
+    prop: "addTime",
+    valueType: "time-picker",
+    hideInSearch: true
+  },
+  {
+    label: "创建人",
+    prop: "addUserName",
+    hideInSearch: true
+  }
+];
+
+/*--------------------表单--------------------*/
+
+// 表单实例
+const dialogForm = ref(null);
+
+interface State {
+  dialogVisible: boolean;
+  detailsVisible: boolean;
+  confirmLoading: boolean;
+  selectedIds: number[];
+  isCreate: boolean;
+  form: {};
+  rules: FormRules;
+  descriptionsData: {};
+}
+
+const state = reactive<State>({
+  dialogVisible: false,
+  detailsVisible: false,
+  confirmLoading: false,
+  selectedIds: [],
+  isCreate: false,
+  form: {},
+  rules: {},
+  descriptionsData: {}
+});
+
+const interfaceOptions = ref<Array<{ label: string; value: string }>>([]);
+
+const getInterfaceOptions = async () => {
+  let res = await getIpInterfaceOptionList();
+  console.log(res);
+  interfaceOptions.value = res.data;
+};
+
+const columns: PlusColumn[] = [
+  {
+    label: "账户号",
+    prop: "accNo",
+    valueType: "input",
+    fieldProps: {
+      disabled: true
+    },
+    colProps: {
+      span: 12
+    }
+  },
+  {
+    label: "选择接口",
+    prop: "interfaceId",
+    valueType: "select",
+    fieldProps: {
+      activeValue: "normal",
+      inactiveValue: "disable"
+    },
+    options: computed(() => interfaceOptions.value),
+    optionsMap: {
+      label: "name",
+      value: "id"
+    },
+    colProps: {
+      span: 12
+    }
+  },
+  {
+    label: "是否回调",
+    prop: "callback",
+    valueType: "select",
+    fieldProps: {
+      options: [
+        { label: "是", value: true },
+        { label: "否", value: false }
+      ]
+    },
+    colProps: {
+      span: 12
+    }
+  },
+  {
+    label: "回调地址",
+    prop: "callbackUrl",
+    valueType: "input",
+    colProps: {
+      span: 12
+    }
+  },
+  {
+    label: "回调次数",
+    prop: "callbackNum",
+    valueType: "input-number",
+    fieldProps: {
+      min: 0
+    },
+    colProps: {
+      span: 12
+    }
+  },
+  {
+    label: "状态",
+    prop: "status",
+    valueType: "radio",
+    fieldProps: {
+      options: [
+        { label: "正常", value: "normal" },
+        { label: "禁用", value: "disable" }
+      ]
+    },
+    colProps: {
+      span: 12
+    }
+  },
+  {
+    label: "token",
+    prop: "token",
+    renderField: (_, onChange) => {
+      return h(
+        ElInput,
+        {
+          placeholder: "点击生成按钮获取token",
+          disabled: true,
+          // 返回VNode时,需要手动调用 renderField 的onChange 回调把值传给表单
+          onChange
+        },
+        {
+          append: () =>
+            h(
+              ElButton,
+              {
+                onClick: async () => {
+                  try {
+                    let res = await generateIpAccountToken();
+                    console.log(res);
+                    if (res.code === 200) {
+                      ElMessage.success("获取token成功");
+                      form.value = {
+                        ...form.value,
+                        token: res.data.token,
+                        secret: res.data.secret
+                      };
+                    } else {
+                      ElMessage.error(res.msg);
+                    }
+                  } catch (e) {
+                    ElMessage.error("获取token失败");
+                  }
+                }
+              },
+              { default: () => "生成" }
+            )
+        }
+      );
+    },
+    colProps: {
+      span: 12
+    }
+  },
+  {
+    label: "secret",
+    prop: "secret",
+    valueType: "input",
+    fieldProps: {
+      disabled: true,
+      placeholder: "点击生成按钮获取secret",
+      type: "textarea",
+      rows: 3
+    },
+    colProps: {
+      span: 12
+    }
+  },
+  {
+    label: "备注",
+    prop: "remark",
+    valueType: "input",
+    fieldProps: {
+      type: "textarea",
+      rows: 3
+    },
+    colProps: {
+      span: 12
+    }
+  }
+];
+
+const descriptionsColumns: PlusColumn[] = [
+  {
+    label: "token",
+    prop: "token",
+    descriptionsItemProps: {
+      span: 24,
+      className: "break-all"
+    }
+  },
+  {
+    label: "secret",
+    prop: "secret",
+    descriptionsItemProps: {
+      span: 24,
+      className: "break-all"
+    }
+  }
+];
+
+// 创建
+const handleCreate = (): void => {
+  form.value = {
+    ...defaultValues,
+    status: "normal"
+  };
+  state.isCreate = true;
+  state.dialogVisible = true;
+};
+
+const handleSubmit = async (values: FieldValues) => {
+  console.log(values, "Submit");
+  confirmLoading.value = true;
+  if (state.isCreate) {
+    try {
+      let params = form.value;
+      let res = await addOrEditIpAccountInterfaceRef(params);
+      if (res.code === 200) {
+        ElMessage.success("新增成功");
+        confirmLoading.value = false;
+        dialogVisible.value = false;
+        refresh();
+      } else {
+        ElMessage.error(res.msg);
+      }
+    } finally {
+      confirmLoading.value = false;
+    }
+  } else {
+    // 编辑
+    try {
+      let params = form.value;
+      let res = await addOrEditIpAccountInterfaceRef(params);
+      if (res.code === 200) {
+        ElMessage.success("修改成功");
+        confirmLoading.value = false;
+        dialogVisible.value = false;
+        refresh();
+      } else {
+        ElMessage.error(res.msg);
+      }
+    } finally {
+      confirmLoading.value = false;
+    }
+  }
+};
+
+const handleClose = () => {
+  console.log(dialogForm.value.formInstance);
+};
+
+const { buttons } = useTable();
+
+buttons.value = [
+  {
+    // 修改
+    text: "修改",
+    code: "edit",
+    // props v0.1.16 版本新增函数类型
+    props: {
+      type: "primary"
+    },
+    onClick(params) {
+      console.log(params.row);
+      let paramsRow = params.row;
+      Object.assign(paramsRow, defaultValues);
+      form.value = paramsRow;
+      state.isCreate = false;
+      state.dialogVisible = true;
+    }
+  },
+  {
+    // 修改
+    text: "查看密钥",
+    code: "interface",
+    // props v0.1.16 版本新增函数类型
+    props: {
+      type: "primary"
+    },
+    onClick(val) {
+      console.log(val);
+      detailsVisible.value = true;
+      descriptionsData.value = {
+        token: val.row.token,
+        secret: val.row.secret
+      };
+    }
+  },
+  {
+    // 删除
+    text: "删除",
+    code: "delete",
+    // props v0.1.16 版本新增计算属性支持
+    props: computed(() => ({ type: "danger" })),
+    confirm: {
+      options: {
+        draggable: true,
+        message: "确定删除此数据吗?"
+      }
+    },
+    onConfirm: async params => {
+      try {
+        let res = await deleteIpAccount(params.row.id);
+        if (res.code === 200) {
+          ElMessage.success("删除成功");
+          refresh();
+        } else {
+          ElMessage.error(res.msg);
+        }
+      } catch (e) {
+        ElMessage.error("删除失败");
+      }
+    }
+  }
+];
+
+const {
+  form,
+  confirmLoading,
+  rules,
+  dialogVisible,
+  detailsVisible,
+  descriptionsData
+} = toRefs(state);
+</script>

+ 415 - 0
src/views/ipInterface/index.vue

@@ -0,0 +1,415 @@
+<template>
+  <div>
+    <PlusPage
+      ref="plusPageInstance"
+      :columns="tableConfig"
+      :request="getList"
+      :is-card="true"
+      :search="{
+        labelWidth: 100,
+        showNumber: 3
+      }"
+      :table="{
+        actionBar: { buttons, type: 'link', width: 180 },
+        adaptive: { offsetBottom: 50 },
+        onFormChange: handleTableChange
+      }"
+      :pageInfoMap="{ page: 'pageNum', pageSize: 'pageSize' }"
+    >
+      <template #table-title>
+        <el-row class="button-row">
+          <el-button size="default" type="success" @click="handleCreate">
+            新增
+          </el-button>
+        </el-row>
+      </template>
+    </PlusPage>
+    <!-- 弹窗编辑 -->
+    <PlusDialogForm
+      ref="dialogForm"
+      v-model="form"
+      v-model:visible="dialogVisible"
+      :form="{
+        columns,
+        labelPosition: 'right',
+        labelWidth: 100,
+        rules
+      }"
+      :dialog="{ title: dialogTitle + '菜单', width: 600, confirmLoading }"
+      @confirm="handleSubmit"
+      @close="handleClose"
+    />
+    <PlusDialog
+      v-model="detailsVisible"
+      title="接口配置"
+      :hasFooter="false"
+      width="500"
+    >
+      <PlusDescriptions
+        :column="24"
+        :columns="descriptionsColumns"
+        :data="descriptionsData"
+      />
+    </PlusDialog>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { computed, reactive, ref, toRefs } from "vue";
+import type { FormRules } from "element-plus";
+import { ElMessage, ElMessageBox } from "element-plus";
+import {
+  type FieldValues,
+  type PlusColumn,
+  PlusDescriptions,
+  PlusDialog,
+  PlusDialogForm,
+  PlusPage,
+  PlusPageInstance,
+  useTable
+} from "plus-pro-components";
+import { isString } from "@pureadmin/utils";
+import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
+import { useRouter } from "vue-router";
+import {
+  addOrEditIpInterface,
+  deleteIpInterface,
+  getIpInterfaceList,
+  switchIpInterfaceStatus
+} from "@/api/system/ipInterface";
+
+defineOptions({
+  name: "IpInterfaceIndex"
+});
+
+const router = useRouter();
+
+const plusPageInstance = ref<PlusPageInstance | null>(null);
+
+const getList = async (query: Record<string, any>) => {
+  let res = await getIpInterfaceList(query);
+  return {
+    data: res.list,
+    total: res.total
+  };
+};
+
+// 重新请求列表接口
+const refresh = () => {
+  plusPageInstance.value?.getList();
+};
+
+const handleTableChange = (values: FieldValues) => {
+  console.log(values);
+  ElMessageBox.confirm("确定修改此数据吗?", "提示", {
+    confirmButtonText: "确定",
+    cancelButtonText: "取消",
+    type: "warning"
+  })
+    .then(async () => {
+      try {
+        let data = {
+          id: values.row.id,
+          status: values.row.status
+        };
+        let res = await switchIpInterfaceStatus(data);
+        if (res.code === 200) {
+          ElMessage.success("修改成功");
+        } else {
+          ElMessage.error(res.msg);
+        }
+      } catch (e) {
+        ElMessage.error("修改失败");
+      }
+    })
+    .finally(() => {
+      refresh();
+    });
+};
+
+const dialogTitle = computed(() => (state.isCreate ? "新增" : "编辑"));
+
+// 表格数据
+const tableConfig: PlusColumn[] = [
+  {
+    label: "接口名称",
+    prop: "interfaceName"
+  },
+  {
+    label: "接口编码",
+    prop: "interfaceNo",
+    hideInSearch: true
+  },
+  {
+    label: "接口厂商",
+    prop: "manufacturer",
+    hideInSearch: true
+  },
+  {
+    label: "状态",
+    prop: "status",
+    valueType: "switch",
+    fieldProps: {
+      activeValue: "normal",
+      inactiveValue: "disable"
+    },
+    editable: true,
+    hideInSearch: true
+  },
+  {
+    label: "状态",
+    prop: "status",
+    valueType: "select",
+    options: [
+      { label: "正常", value: "normal" },
+      { label: "停用", value: "disable" }
+    ],
+    hideInTable: true
+  },
+  {
+    label: "备注",
+    prop: "remark",
+    hideInSearch: true
+  },
+  {
+    label: "创建时间",
+    prop: "addTime",
+    valueType: "time-picker",
+    hideInSearch: true
+  },
+  {
+    label: "创建人",
+    prop: "addUserName",
+    hideInSearch: true
+  }
+];
+
+/*--------------------表单--------------------*/
+
+// 表单实例
+const dialogForm = ref(null);
+
+interface State {
+  dialogVisible: boolean;
+  detailsVisible: boolean;
+  confirmLoading: boolean;
+  selectedIds: number[];
+  isCreate: boolean;
+  form: {};
+  rules: FormRules;
+  descriptionsData: {};
+}
+
+const state = reactive<State>({
+  dialogVisible: false,
+  detailsVisible: false,
+  confirmLoading: false,
+  selectedIds: [],
+  isCreate: false,
+  form: {},
+  rules: {
+    accNo: [{ required: true, message: "请输入账户号", trigger: "blur" }]
+  },
+  descriptionsData: {}
+});
+
+const columns: PlusColumn[] = [
+  {
+    label: "接口名称",
+    prop: "interfaceName",
+    valueType: "input",
+    fieldProps: {
+      clearable: true
+    }
+  },
+  {
+    label: "接口编码",
+    prop: "interfaceNo",
+    valueType: "input",
+    fieldProps: {
+      clearable: true
+    }
+  },
+  {
+    label: "接口厂商",
+    prop: "manufacturer",
+    valueType: "input",
+    fieldProps: {
+      clearable: true
+    }
+  },
+  {
+    label: "状态",
+    prop: "status",
+    valueType: "radio",
+    fieldProps: {
+      options: [
+        { label: "正常", value: "normal" },
+        { label: "停用", value: "disable" }
+      ]
+    }
+  },
+  {
+    label: "接口配置",
+    prop: "interfaceConfig",
+    valueType: "textarea",
+    fieldProps: {
+      rows: 4
+    }
+  },
+  {
+    label: "备注",
+    prop: "remark",
+    valueType: "textarea",
+    fieldProps: {
+      rows: 4
+    }
+  }
+];
+
+const descriptionsColumns: PlusColumn[] = [
+  {
+    label: "接口配置",
+    prop: "interfaceConfig",
+    descriptionsItemProps: {
+      span: 24,
+      className: "break-all"
+    }
+  }
+];
+
+// 创建
+const handleCreate = (): void => {
+  form.value = {
+    status: "normal"
+  };
+  state.isCreate = true;
+  state.dialogVisible = true;
+};
+
+const handleSubmit = async (values: FieldValues) => {
+  console.log(values, "Submit");
+  confirmLoading.value = true;
+  if (state.isCreate) {
+    try {
+      let params = form.value;
+      let res = await addOrEditIpInterface(params);
+      if (res.code === 200) {
+        ElMessage.success("新增成功");
+        confirmLoading.value = false;
+        dialogVisible.value = false;
+      } else {
+        ElMessage.error(res.msg);
+      }
+    } finally {
+      confirmLoading.value = false;
+      refresh();
+    }
+  } else {
+    // 编辑
+    try {
+      let params = form.value;
+      let res = await addOrEditIpInterface(params);
+      if (res.code === 200) {
+        ElMessage.success("修改成功");
+        confirmLoading.value = false;
+        dialogVisible.value = false;
+        refresh();
+      } else {
+        ElMessage.error(res.msg);
+      }
+    } finally {
+      confirmLoading.value = false;
+      refresh();
+    }
+  }
+};
+
+const handleClose = () => {
+  console.log(dialogForm.value.formInstance);
+};
+
+// 参数预期管理
+const normalizeParams = (params: Record<string, any>) => {
+  return {
+    interfaceName: params.interfaceName ?? null,
+    interfaceNo: params.interfaceNo ?? null,
+    manufacturer: params.manufacturer ?? null,
+    status: params.status ?? null,
+    remark: params.remark ?? null,
+    interfaceConfig: params.interfaceConfig ?? null,
+    id: params.id ?? null
+  };
+};
+
+const { buttons } = useTable();
+
+buttons.value = [
+  {
+    // 修改
+    text: "修改",
+    code: "edit",
+    // props v0.1.16 版本新增函数类型
+    props: {
+      type: "primary"
+    },
+    onClick(params) {
+      // form.value = params.row;
+      Object.assign(form.value, normalizeParams(params.row));
+      state.isCreate = false;
+      state.dialogVisible = true;
+    }
+  },
+  {
+    // 修改
+    text: "查看配置",
+    code: "config",
+    // props v0.1.16 版本新增函数类型
+    props: {
+      type: "primary"
+    },
+    onClick(val) {
+      console.log(val);
+      detailsVisible.value = true;
+      descriptionsData.value = {
+        interfaceConfig: val.row.interfaceConfig
+      };
+    }
+  },
+  {
+    // 删除
+    text: "删除",
+    code: "delete",
+    // props v0.1.16 版本新增计算属性支持
+    props: computed(() => ({ type: "danger" })),
+    confirm: {
+      options: {
+        draggable: true,
+        message: "确定删除此数据吗?"
+      }
+    },
+    onConfirm: async params => {
+      try {
+        let res = await deleteIpInterface(params.row.id);
+        if (res.code === 200) {
+          ElMessage.success("删除成功");
+          refresh();
+        } else {
+          ElMessage.error(res.msg);
+        }
+      } catch (e) {
+        ElMessage.error("删除失败");
+      }
+    }
+  }
+];
+
+const {
+  form,
+  confirmLoading,
+  rules,
+  dialogVisible,
+  detailsVisible,
+  descriptionsData
+} = toRefs(state);
+</script>

+ 129 - 0
src/views/ipInterfaceCall/index.vue

@@ -0,0 +1,129 @@
+<template>
+  <div>
+    <PlusPage
+      ref="plusPageInstance"
+      :columns="tableConfig"
+      :request="getList"
+      :is-card="true"
+      :search="{
+        labelWidth: 100,
+        showNumber: 3
+      }"
+      :table="{
+        actionBar: { buttons, type: 'link', width: 180 },
+        adaptive: { offsetBottom: 50 },
+        onFormChange: handleTableChange
+      }"
+      :pageInfoMap="{ page: 'pageNum', pageSize: 'pageSize' }"
+    />
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref } from "vue";
+import {
+  type FieldValues,
+  type PlusColumn,
+  PlusPage,
+  PlusPageInstance,
+  useTable
+} from "plus-pro-components";
+import { isString } from "@pureadmin/utils";
+import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
+import { useRouter } from "vue-router";
+import { getIpInterfaceCallList } from "@/api/system/ipInterfaceCall";
+
+defineOptions({
+  name: "IpInterfaceCallIndex"
+});
+
+const router = useRouter();
+
+const plusPageInstance = ref<PlusPageInstance | null>(null);
+
+const getList = async (query: Record<string, any>) => {
+  let res = await getIpInterfaceCallList(query);
+  return {
+    data: res.list,
+    total: res.total
+  };
+};
+
+const handleTableChange = (values: FieldValues) => {
+  console.log("表格参数变化:", values);
+};
+
+// 表格数据
+const tableConfig: PlusColumn[] = [
+  {
+    label: "调用编号",
+    prop: "id"
+  },
+  {
+    label: "账户编号",
+    prop: "accountNo"
+  },
+  {
+    label: "调用接口",
+    prop: "interfaceName"
+  },
+  {
+    label: "接口厂商",
+    prop: "manufacturer",
+    hideInSearch: true
+  },
+  {
+    label: "调用状态",
+    prop: "status",
+    hideInSearch: true
+  },
+  {
+    label: "回调状态",
+    prop: "callbackStatus",
+    hideInSearch: true
+  },
+  {
+    label: "创建时间",
+    prop: "addTime",
+    valueType: "time-picker",
+    hideInSearch: true
+  }
+];
+
+const { buttons } = useTable();
+
+buttons.value = [
+  {
+    // 修改
+    text: "查看日志",
+    code: "interface",
+    // props v0.1.16 版本新增函数类型
+    props: {
+      type: "primary"
+    },
+    onClick(val) {
+      console.log("handleClick", val.row);
+      let params = {
+        id: val.row.id
+      };
+      Object.keys(params).forEach(param => {
+        if (!isString(params[param])) {
+          params[param] = params[param].toString();
+        }
+      });
+      // 保存信息到标签页
+      useMultiTagsStoreHook().handleTags("push", {
+        path: `/ipInterfaceCall/ipInterfaceCallDetail`,
+        name: "IpInterfaceCallDetail",
+        query: params,
+        meta: {
+          title: `接口调用明细`,
+          dynamicLevel: 1
+        }
+      });
+      // 路由跳转
+      router.push({ name: "IpInterfaceCallDetail", query: params });
+    }
+  }
+];
+</script>

+ 181 - 0
src/views/ipInterfaceCall/ipInterfaceCallDetail.vue

@@ -0,0 +1,181 @@
+<script setup lang="ts">
+import { useRoute } from "vue-router";
+import { onMounted, computed, ref } from "vue";
+import {
+  getIpInterfaceCallDetailById,
+  getIpInterfaceCallRecord
+} from "@/api/system/ipInterfaceCall";
+import { PlusForm, PlusTable, useTable } from "plus-pro-components";
+import type { PlusColumn, FieldValues } from "plus-pro-components";
+
+defineOptions({
+  name: "IpInterfaceCallDetail"
+});
+const route = useRoute();
+
+console.log(route.query);
+
+onMounted(() => {
+  getDetail();
+});
+
+const getDetail = async () => {
+  let id: any = route.query.id;
+  let res = await getIpInterfaceCallDetailById(id);
+  let res2 = await getIpInterfaceCallRecord(id);
+  console.log(res, res2);
+  Object.assign(form.value, res.data);
+  tableData.value = res2.data;
+};
+
+const columns: PlusColumn[] = [
+  {
+    label: "调用编号",
+    width: 120,
+    prop: "id",
+    valueType: "input",
+    fieldProps: {
+      placeholder: "无",
+      disabled: true
+    },
+    colProps: { span: 8 }
+  },
+  {
+    label: "账户编号",
+    width: 120,
+    prop: "accountNo",
+    valueType: "input",
+    fieldProps: {
+      placeholder: "无",
+      disabled: true
+    },
+    colProps: { span: 8 }
+  },
+  {
+    label: "调用接口",
+    width: 120,
+    prop: "interfaceName",
+    valueType: "input",
+    fieldProps: {
+      placeholder: "无",
+      disabled: true
+    },
+    colProps: { span: 8 }
+  }
+];
+
+const columns1: PlusColumn[] = [
+  {
+    label: "接口参数",
+    prop: "interfaceParam",
+    valueType: "input",
+    fieldProps: {
+      placeholder: "无",
+      disabled: true
+    },
+    colProps: { span: 12 }
+  },
+  {
+    label: "配置参数",
+    prop: "configParam",
+    valueType: "input",
+    fieldProps: {
+      placeholder: "无",
+      disabled: true
+    },
+    colProps: { span: 12 }
+  },
+  {
+    label: "请求参数",
+    prop: "requestParam",
+    fieldProps: {
+      placeholder: "无",
+      type: "textarea",
+      rows: 4,
+      disabled: true
+    },
+    colProps: { span: 12 }
+  },
+  {
+    label: "相应结果",
+    prop: "responseParam",
+    fieldProps: {
+      placeholder: "无",
+      type: "textarea",
+      rows: 4,
+      disabled: true
+    },
+    colProps: { span: 12 }
+  }
+];
+
+const columns2: PlusColumn[] = [
+  {
+    label: "回调地址",
+    prop: "callbackUrl"
+  },
+  {
+    label: "请求参数",
+    prop: "requestParam"
+  },
+  {
+    label: "回调时间",
+    prop: "addTime"
+  },
+  {
+    label: "状态",
+    width: 120,
+    prop: "status",
+    valueType: "select",
+    options: [
+      { name: "处理中", value: "handle" },
+      { name: "成功", value: "success" },
+      { name: "失败", value: "fail" }
+    ]
+  },
+  {
+    label: "相应结果",
+    prop: "responseParam"
+  },
+  {
+    label: "响应时间",
+    prop: "updateTime"
+  }
+];
+
+const form = ref<FieldValues>({});
+
+const { tableData } = useTable();
+</script>
+
+<template>
+  <div>
+    <el-card class="w-full h-full">
+      <PlusForm
+        v-model="form"
+        :columns="columns"
+        :hasFooter="false"
+        :row-props="{ gutter: 20 }"
+        :col-props="{ span: 24 }"
+      />
+      <el-card class="mt-2" header="请求记录">
+        <PlusForm
+          v-model="form"
+          :hasFooter="false"
+          :columns="columns1"
+          :row-props="{ gutter: 20 }"
+          :col-props="{ span: 24 }"
+        />
+      </el-card>
+      <el-card class="mt-5" header="回调记录">
+        <PlusTable
+          :columns="columns2"
+          :data="tableData"
+          :table-props="{ height: '400px' }"
+        />
+      </el-card>
+    </el-card>
+  </div>
+</template>
+
+<style scoped lang="scss"></style>

+ 1 - 4
vite.config.ts

@@ -29,10 +29,7 @@ export default ({ mode }: ConfigEnv): UserConfigExport => {
           // 这里填写后端地址
           target: "http://192.168.1.168:20000",
           changeOrigin: true,
-          rewrite: path => {
-            console.log(path);
-            return path.replace(/^\/api/, "");
-          }
+          rewrite: path => path.replace(/^\/api/, "")
         }
       },
       // 预热文件以提前转换和缓存结果,降低启动期间的初始页面加载时长并防止转换瀑布