林小张 3 天之前
父节点
当前提交
c46c17692d

+ 44 - 0
src/api/system/about/index.ts

@@ -0,0 +1,44 @@
+import request from '@/utils/request';
+
+// 查询关于我们列表
+export function listAbout(query: any) {
+  return request({
+    url: '/system/about/list',
+    method: 'get',
+    params: query
+  });
+}
+
+// 查询关于我们详细
+export function getAbout(id: number) {
+  return request({
+    url: '/system/about/' + id,
+    method: 'get'
+  });
+}
+
+// 新增关于我们
+export function addAbout(data: any) {
+  return request({
+    url: '/system/about',
+    method: 'post',
+    data: data
+  });
+}
+
+// 修改关于我们
+export function updateAbout(data: any) {
+  return request({
+    url: '/system/about',
+    method: 'put',
+    data: data
+  });
+}
+
+// 删除关于我们
+export function delAbout(id: number | number[]) {
+  return request({
+    url: '/system/about/' + id,
+    method: 'delete'
+  });
+}

+ 44 - 0
src/api/system/navigation/index.ts

@@ -0,0 +1,44 @@
+import request from '@/utils/request';
+
+// 查询平台导航列表
+export function listNavigation(query: any) {
+  return request({
+    url: '/system/navigation/list',
+    method: 'get',
+    params: query
+  });
+}
+
+// 查询平台导航详细
+export function getNavigation(id: number) {
+  return request({
+    url: '/system/navigation/' + id,
+    method: 'get'
+  });
+}
+
+// 新增平台导航
+export function addNavigation(data: any) {
+  return request({
+    url: '/system/navigation',
+    method: 'post',
+    data: data
+  });
+}
+
+// 修改平台导航
+export function updateNavigation(data: any) {
+  return request({
+    url: '/system/navigation',
+    method: 'put',
+    data: data
+  });
+}
+
+// 删除平台导航
+export function delNavigation(id: number | number[]) {
+  return request({
+    url: '/system/navigation/' + id,
+    method: 'delete'
+  });
+}

+ 44 - 0
src/api/system/platformConfig/index.ts

@@ -0,0 +1,44 @@
+import request from '@/utils/request';
+
+// 查询平台配置列表
+export function listPlatformConfig(query: any) {
+  return request({
+    url: '/system/platformConfig/list',
+    method: 'get',
+    params: query
+  });
+}
+
+// 查询平台配置详细
+export function getPlatformConfig(id: number) {
+  return request({
+    url: '/system/platformConfig/' + id,
+    method: 'get'
+  });
+}
+
+// 新增平台配置
+export function addPlatformConfig(data: any) {
+  return request({
+    url: '/system/platformConfig',
+    method: 'post',
+    data: data
+  });
+}
+
+// 修改平台配置
+export function updatePlatformConfig(data: any) {
+  return request({
+    url: '/system/platformConfig',
+    method: 'put',
+    data: data
+  });
+}
+
+// 删除平台配置
+export function delPlatformConfig(id: number | number[]) {
+  return request({
+    url: '/system/platformConfig/' + id,
+    method: 'delete'
+  });
+}

+ 44 - 0
src/api/system/terms/index.ts

@@ -0,0 +1,44 @@
+import request from '@/utils/request';
+
+// 查询事项与条款列表
+export function listTerms(query: any) {
+  return request({
+    url: '/system/terms/list',
+    method: 'get',
+    params: query
+  });
+}
+
+// 查询事项与条款详细
+export function getTerms(id: number) {
+  return request({
+    url: '/system/terms/' + id,
+    method: 'get'
+  });
+}
+
+// 新增事项与条款
+export function addTerms(data: any) {
+  return request({
+    url: '/system/terms',
+    method: 'post',
+    data: data
+  });
+}
+
+// 修改事项与条款
+export function updateTerms(data: any) {
+  return request({
+    url: '/system/terms',
+    method: 'put',
+    data: data
+  });
+}
+
+// 删除事项与条款
+export function delTerms(id: number | number[]) {
+  return request({
+    url: '/system/terms/' + id,
+    method: 'delete'
+  });
+}

+ 165 - 0
src/views/system/about/index.vue

@@ -0,0 +1,165 @@
+<template>
+  <div class="p-2">
+    <el-card shadow="hover">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
+          </el-col>
+          <right-toolbar @query-table="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" :data="aboutList" border>
+        <el-table-column label="标题" align="center" prop="title" :show-overflow-tooltip="true" />
+        <el-table-column label="排序" align="center" prop="sort" width="80" />
+        <el-table-column label="创建时间" align="center" prop="createTime" width="180" />
+        <el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-button link type="primary" @click="handleUpdate(scope.row)">编辑</el-button>
+            <el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total > 0"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        :total="total"
+        @pagination="getList"
+      />
+    </el-card>
+
+    <!-- 添加或修改对话框 -->
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="800px" append-to-body>
+      <el-form ref="aboutFormRef" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="标题" prop="title">
+          <el-input v-model="form.title" placeholder="请输入标题" />
+        </el-form-item>
+        <el-form-item label="排序" prop="sort">
+          <el-input-number v-model="form.sort" controls-position="right" :min="0" />
+        </el-form-item>
+        <el-form-item label="内容" prop="content">
+          <el-input
+            v-model="form.content"
+            type="textarea"
+            :rows="10"
+            placeholder="请输入内容(支持HTML)"
+          />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="About" lang="ts">
+import { listAbout, getAbout, addAbout, updateAbout, delAbout } from '@/api/system/about';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const aboutList = ref<any[]>([]);
+const loading = ref(false);
+const total = ref(0);
+
+const queryParams = ref({
+  pageNum: 1,
+  pageSize: 10
+});
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const aboutFormRef = ref<ElFormInstance>();
+
+const initFormData = {
+  id: undefined as number | undefined,
+  title: '',
+  content: '',
+  sort: 0
+};
+
+const form = ref({ ...initFormData });
+
+const rules = reactive({
+  title: [{ required: true, message: '标题不能为空', trigger: 'blur' }],
+  content: [{ required: true, message: '内容不能为空', trigger: 'blur' }]
+});
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true;
+  try {
+    const res = await listAbout(queryParams.value);
+    aboutList.value = res.rows;
+    total.value = res.total;
+  } finally {
+    loading.value = false;
+  }
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  aboutFormRef.value?.resetFields();
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加关于我们';
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row: any) => {
+  reset();
+  const res = await getAbout(row.id);
+  form.value = res.data;
+  dialog.visible = true;
+  dialog.title = '修改关于我们';
+};
+
+/** 提交按钮 */
+const submitForm = () => {
+  aboutFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      if (form.value.id) {
+        await updateAbout(form.value);
+        proxy?.$modal.msgSuccess('修改成功');
+      } else {
+        await addAbout(form.value);
+        proxy?.$modal.msgSuccess('新增成功');
+      }
+      dialog.visible = false;
+      getList();
+    }
+  });
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row: any) => {
+  await proxy?.$modal.confirm('是否确认删除标题为"' + row.title + '"的数据项?');
+  await delAbout(row.id);
+  proxy?.$modal.msgSuccess('删除成功');
+  getList();
+};
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 184 - 0
src/views/system/aboutUs/index.vue

@@ -0,0 +1,184 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="标题" prop="title">
+              <el-input v-model="queryParams.title" placeholder="请输入标题" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="hover">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:about:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:about:remove']">删除</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="标题" prop="title" />
+        <el-table-column label="排序" prop="sort" width="80" />
+        <el-table-column label="操作" width="150" align="center">
+          <template #default="scope">
+            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:about:edit']">修改</el-button>
+            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:about:remove']">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+
+    <!-- 添加或修改对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
+      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="标题" prop="title">
+          <el-input v-model="form.title" placeholder="请输入标题" />
+        </el-form-item>
+        <el-form-item label="内容" prop="content">
+          <el-input v-model="form.content" type="textarea" :rows="6" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="排序" prop="sort">
+          <el-input-number v-model="form.sort" :min="0" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="AboutUs" lang="ts">
+import { listAbout, getAbout, addAbout, updateAbout, delAbout } from '@/api/system/about';
+import { ComponentInternalInstance, getCurrentInstance, ref, reactive, toRefs } from 'vue';
+import { ElForm } from 'element-plus';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const dataList = ref([]);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<number | string>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref(ElForm);
+const formRef = ref(ElForm);
+
+const dialog = reactive({ visible: false, title: '' });
+
+const data = reactive({
+  form: {} as any,
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    title: undefined
+  },
+  rules: {
+    title: [{ required: true, message: '标题不能为空', trigger: 'blur' }],
+    content: [{ required: true, message: '内容不能为空', trigger: 'blur' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+const getList = async () => {
+  loading.value = true;
+  const res = await listAbout(queryParams.value);
+  dataList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+const resetQuery = () => {
+  queryFormRef.value.resetFields();
+  handleQuery();
+};
+
+const handleSelectionChange = (selection: any[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length !== 1;
+  multiple.value = !selection.length;
+};
+
+const reset = () => {
+  form.value = {
+    id: undefined,
+    title: undefined,
+    content: undefined,
+    sort: 0
+  };
+  formRef.value?.resetFields();
+};
+
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加关于我们';
+};
+
+const handleUpdate = async (row: any) => {
+  reset();
+  const id = row.id || ids.value[0];
+  const res = await getAbout(id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = '修改关于我们';
+};
+
+const submitForm = () => {
+  formRef.value.validate(async (valid: boolean) => {
+    if (valid) {
+      if (form.value.id) {
+        await updateAbout(form.value);
+        proxy?.$modal.msgSuccess('修改成功');
+      } else {
+        await addAbout(form.value);
+        proxy?.$modal.msgSuccess('新增成功');
+      }
+      dialog.visible = false;
+      getList();
+    }
+  });
+};
+
+const handleDelete = async (row?: any) => {
+  const deleteIds = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除?');
+  await delAbout(deleteIds);
+  proxy?.$modal.msgSuccess('删除成功');
+  getList();
+};
+
+const cancel = () => {
+  dialog.visible = false;
+  reset();
+};
+
+getList();
+</script>

+ 158 - 0
src/views/system/basicSetting/index.vue

@@ -0,0 +1,158 @@
+<template>
+  <div class="p-2">
+    <el-card shadow="hover">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:platformConfig:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:platformConfig:remove']">删除</el-button>
+          </el-col>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="配置键" prop="configKey" />
+        <el-table-column label="配置名称" prop="name" />
+        <el-table-column label="配置值" prop="value" show-overflow-tooltip />
+        <el-table-column label="操作" width="150" align="center">
+          <template #default="scope">
+            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:platformConfig:edit']">修改</el-button>
+            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:platformConfig:remove']">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+
+    <!-- 添加或修改对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="配置键" prop="configKey">
+          <el-input v-model="form.configKey" placeholder="请输入配置键" />
+        </el-form-item>
+        <el-form-item label="配置名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入配置名称" />
+        </el-form-item>
+        <el-form-item label="配置值" prop="value">
+          <el-input v-model="form.value" type="textarea" placeholder="请输入配置值" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="BasicSetting" lang="ts">
+import { listPlatformConfig, getPlatformConfig, addPlatformConfig, updatePlatformConfig, delPlatformConfig } from '@/api/system/platformConfig';
+import { ComponentInternalInstance, getCurrentInstance, ref, reactive, toRefs } from 'vue';
+import { ElForm } from 'element-plus';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const dataList = ref([]);
+const loading = ref(true);
+const ids = ref<Array<number | string>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const formRef = ref(ElForm);
+
+const dialog = reactive({ visible: false, title: '' });
+
+const data = reactive({
+  form: {} as any,
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    configType: '0'
+  },
+  rules: {
+    configKey: [{ required: true, message: '配置键不能为空', trigger: 'blur' }],
+    name: [{ required: true, message: '配置名称不能为空', trigger: 'blur' }],
+    value: [{ required: true, message: '配置值不能为空', trigger: 'blur' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+const getList = async () => {
+  loading.value = true;
+  const res = await listPlatformConfig(queryParams.value);
+  dataList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+const handleSelectionChange = (selection: any[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length !== 1;
+  multiple.value = !selection.length;
+};
+
+const reset = () => {
+  form.value = {
+    id: undefined,
+    configType: '0',
+    configKey: undefined,
+    name: undefined,
+    value: undefined
+  };
+  formRef.value?.resetFields();
+};
+
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加基本配置';
+};
+
+const handleUpdate = async (row: any) => {
+  reset();
+  const id = row.id || ids.value[0];
+  const res = await getPlatformConfig(id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = '修改基本配置';
+};
+
+const submitForm = () => {
+  formRef.value.validate(async (valid: boolean) => {
+    if (valid) {
+      if (form.value.id) {
+        await updatePlatformConfig(form.value);
+        proxy?.$modal.msgSuccess('修改成功');
+      } else {
+        await addPlatformConfig(form.value);
+        proxy?.$modal.msgSuccess('新增成功');
+      }
+      dialog.visible = false;
+      getList();
+    }
+  });
+};
+
+const handleDelete = async (row?: any) => {
+  const deleteIds = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除?');
+  await delPlatformConfig(deleteIds);
+  proxy?.$modal.msgSuccess('删除成功');
+  getList();
+};
+
+const cancel = () => {
+  dialog.visible = false;
+  reset();
+};
+
+getList();
+</script>

+ 210 - 0
src/views/system/bottomNav/index.vue

@@ -0,0 +1,210 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="导航名称" prop="navigationName">
+              <el-input v-model="queryParams.navigationName" placeholder="请输入导航名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否启用" prop="isEnable">
+              <el-select v-model="queryParams.isEnable" placeholder="请选择" clearable>
+                <el-option label="是" value="0" />
+                <el-option label="否" value="1" />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="hover">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:navigation:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:navigation:remove']">删除</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="导航名称" prop="navigationName" />
+        <el-table-column label="链接地址" prop="url" show-overflow-tooltip />
+        <el-table-column label="排序" prop="sort" width="80" />
+        <el-table-column label="是否启用" prop="isEnable" width="100">
+          <template #default="scope">
+            <el-tag :type="scope.row.isEnable === '0' ? 'success' : 'danger'">
+              {{ scope.row.isEnable === '0' ? '是' : '否' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="150" align="center">
+          <template #default="scope">
+            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:navigation:edit']">修改</el-button>
+            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:navigation:remove']">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+
+    <!-- 添加或修改对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="导航名称" prop="navigationName">
+          <el-input v-model="form.navigationName" placeholder="请输入导航名称" />
+        </el-form-item>
+        <el-form-item label="链接地址" prop="url">
+          <el-input v-model="form.url" placeholder="请输入链接地址" />
+        </el-form-item>
+        <el-form-item label="排序" prop="sort">
+          <el-input-number v-model="form.sort" :min="0" />
+        </el-form-item>
+        <el-form-item label="是否启用" prop="isEnable">
+          <el-radio-group v-model="form.isEnable">
+            <el-radio value="0">是</el-radio>
+            <el-radio value="1">否</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="BottomNav" lang="ts">
+import { listNavigation, getNavigation, addNavigation, updateNavigation, delNavigation } from '@/api/system/navigation';
+import { ComponentInternalInstance, getCurrentInstance, ref, reactive, toRefs } from 'vue';
+import { ElForm } from 'element-plus';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const dataList = ref([]);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<number | string>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref(ElForm);
+const formRef = ref(ElForm);
+
+const dialog = reactive({ visible: false, title: '' });
+
+const data = reactive({
+  form: {} as any,
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    navType: 'footer',
+    navigationName: undefined,
+    isEnable: undefined
+  },
+  rules: {
+    navigationName: [{ required: true, message: '导航名称不能为空', trigger: 'blur' }],
+    url: [{ required: true, message: '链接地址不能为空', trigger: 'blur' }],
+    sort: [{ required: true, message: '排序不能为空', trigger: 'blur' }],
+    isEnable: [{ required: true, message: '请选择是否启用', trigger: 'change' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+const getList = async () => {
+  loading.value = true;
+  const res = await listNavigation(queryParams.value);
+  dataList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+const resetQuery = () => {
+  queryFormRef.value.resetFields();
+  handleQuery();
+};
+
+const handleSelectionChange = (selection: any[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length !== 1;
+  multiple.value = !selection.length;
+};
+
+const reset = () => {
+  form.value = {
+    id: undefined,
+    navType: 'footer',
+    navigationName: undefined,
+    url: undefined,
+    sort: 0,
+    isEnable: '0'
+  };
+  formRef.value?.resetFields();
+};
+
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加底部导航';
+};
+
+const handleUpdate = async (row: any) => {
+  reset();
+  const id = row.id || ids.value[0];
+  const res = await getNavigation(id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = '修改底部导航';
+};
+
+const submitForm = () => {
+  formRef.value.validate(async (valid: boolean) => {
+    if (valid) {
+      if (form.value.id) {
+        await updateNavigation(form.value);
+        proxy?.$modal.msgSuccess('修改成功');
+      } else {
+        await addNavigation(form.value);
+        proxy?.$modal.msgSuccess('新增成功');
+      }
+      dialog.visible = false;
+      getList();
+    }
+  });
+};
+
+const handleDelete = async (row?: any) => {
+  const deleteIds = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除?');
+  await delNavigation(deleteIds);
+  proxy?.$modal.msgSuccess('删除成功');
+  getList();
+};
+
+const cancel = () => {
+  dialog.visible = false;
+  reset();
+};
+
+getList();
+</script>

+ 210 - 0
src/views/system/floatNav/index.vue

@@ -0,0 +1,210 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="导航名称" prop="navigationName">
+              <el-input v-model="queryParams.navigationName" placeholder="请输入导航名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否启用" prop="isEnable">
+              <el-select v-model="queryParams.isEnable" placeholder="请选择" clearable>
+                <el-option label="是" value="0" />
+                <el-option label="否" value="1" />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="hover">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:navigation:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:navigation:remove']">删除</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="导航名称" prop="navigationName" />
+        <el-table-column label="链接地址" prop="url" show-overflow-tooltip />
+        <el-table-column label="排序" prop="sort" width="80" />
+        <el-table-column label="是否启用" prop="isEnable" width="100">
+          <template #default="scope">
+            <el-tag :type="scope.row.isEnable === '0' ? 'success' : 'danger'">
+              {{ scope.row.isEnable === '0' ? '是' : '否' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="150" align="center">
+          <template #default="scope">
+            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:navigation:edit']">修改</el-button>
+            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:navigation:remove']">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+
+    <!-- 添加或修改对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="导航名称" prop="navigationName">
+          <el-input v-model="form.navigationName" placeholder="请输入导航名称" />
+        </el-form-item>
+        <el-form-item label="链接地址" prop="url">
+          <el-input v-model="form.url" placeholder="请输入链接地址" />
+        </el-form-item>
+        <el-form-item label="排序" prop="sort">
+          <el-input-number v-model="form.sort" :min="0" />
+        </el-form-item>
+        <el-form-item label="是否启用" prop="isEnable">
+          <el-radio-group v-model="form.isEnable">
+            <el-radio value="0">是</el-radio>
+            <el-radio value="1">否</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="FloatNav" lang="ts">
+import { listNavigation, getNavigation, addNavigation, updateNavigation, delNavigation } from '@/api/system/navigation';
+import { ComponentInternalInstance, getCurrentInstance, ref, reactive, toRefs } from 'vue';
+import { ElForm } from 'element-plus';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const dataList = ref([]);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<number | string>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref(ElForm);
+const formRef = ref(ElForm);
+
+const dialog = reactive({ visible: false, title: '' });
+
+const data = reactive({
+  form: {} as any,
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    navType: 'float',
+    navigationName: undefined,
+    isEnable: undefined
+  },
+  rules: {
+    navigationName: [{ required: true, message: '导航名称不能为空', trigger: 'blur' }],
+    url: [{ required: true, message: '链接地址不能为空', trigger: 'blur' }],
+    sort: [{ required: true, message: '排序不能为空', trigger: 'blur' }],
+    isEnable: [{ required: true, message: '请选择是否启用', trigger: 'change' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+const getList = async () => {
+  loading.value = true;
+  const res = await listNavigation(queryParams.value);
+  dataList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+const resetQuery = () => {
+  queryFormRef.value.resetFields();
+  handleQuery();
+};
+
+const handleSelectionChange = (selection: any[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length !== 1;
+  multiple.value = !selection.length;
+};
+
+const reset = () => {
+  form.value = {
+    id: undefined,
+    navType: 'float',
+    navigationName: undefined,
+    url: undefined,
+    sort: 0,
+    isEnable: '0'
+  };
+  formRef.value?.resetFields();
+};
+
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加浮动导航';
+};
+
+const handleUpdate = async (row: any) => {
+  reset();
+  const id = row.id || ids.value[0];
+  const res = await getNavigation(id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = '修改浮动导航';
+};
+
+const submitForm = () => {
+  formRef.value.validate(async (valid: boolean) => {
+    if (valid) {
+      if (form.value.id) {
+        await updateNavigation(form.value);
+        proxy?.$modal.msgSuccess('修改成功');
+      } else {
+        await addNavigation(form.value);
+        proxy?.$modal.msgSuccess('新增成功');
+      }
+      dialog.visible = false;
+      getList();
+    }
+  });
+};
+
+const handleDelete = async (row?: any) => {
+  const deleteIds = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除?');
+  await delNavigation(deleteIds);
+  proxy?.$modal.msgSuccess('删除成功');
+  getList();
+};
+
+const cancel = () => {
+  dialog.visible = false;
+  reset();
+};
+
+getList();
+</script>

+ 210 - 0
src/views/system/homeNav/index.vue

@@ -0,0 +1,210 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="导航名称" prop="navigationName">
+              <el-input v-model="queryParams.navigationName" placeholder="请输入导航名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否启用" prop="isEnable">
+              <el-select v-model="queryParams.isEnable" placeholder="请选择" clearable>
+                <el-option label="是" value="0" />
+                <el-option label="否" value="1" />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="hover">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:navigation:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:navigation:remove']">删除</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="导航名称" prop="navigationName" />
+        <el-table-column label="链接地址" prop="url" show-overflow-tooltip />
+        <el-table-column label="排序" prop="sort" width="80" />
+        <el-table-column label="是否启用" prop="isEnable" width="100">
+          <template #default="scope">
+            <el-tag :type="scope.row.isEnable === '0' ? 'success' : 'danger'">
+              {{ scope.row.isEnable === '0' ? '是' : '否' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="150" align="center">
+          <template #default="scope">
+            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:navigation:edit']">修改</el-button>
+            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:navigation:remove']">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+
+    <!-- 添加或修改对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="导航名称" prop="navigationName">
+          <el-input v-model="form.navigationName" placeholder="请输入导航名称" />
+        </el-form-item>
+        <el-form-item label="链接地址" prop="url">
+          <el-input v-model="form.url" placeholder="请输入链接地址" />
+        </el-form-item>
+        <el-form-item label="排序" prop="sort">
+          <el-input-number v-model="form.sort" :min="0" />
+        </el-form-item>
+        <el-form-item label="是否启用" prop="isEnable">
+          <el-radio-group v-model="form.isEnable">
+            <el-radio value="0">是</el-radio>
+            <el-radio value="1">否</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="HomeNav" lang="ts">
+import { listNavigation, getNavigation, addNavigation, updateNavigation, delNavigation } from '@/api/system/navigation';
+import { ComponentInternalInstance, getCurrentInstance, ref, reactive, toRefs } from 'vue';
+import { ElForm } from 'element-plus';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const dataList = ref([]);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<number | string>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref(ElForm);
+const formRef = ref(ElForm);
+
+const dialog = reactive({ visible: false, title: '' });
+
+const data = reactive({
+  form: {} as any,
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    navType: 'home',
+    navigationName: undefined,
+    isEnable: undefined
+  },
+  rules: {
+    navigationName: [{ required: true, message: '导航名称不能为空', trigger: 'blur' }],
+    url: [{ required: true, message: '链接地址不能为空', trigger: 'blur' }],
+    sort: [{ required: true, message: '排序不能为空', trigger: 'blur' }],
+    isEnable: [{ required: true, message: '请选择是否启用', trigger: 'change' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+const getList = async () => {
+  loading.value = true;
+  const res = await listNavigation(queryParams.value);
+  dataList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+const resetQuery = () => {
+  queryFormRef.value.resetFields();
+  handleQuery();
+};
+
+const handleSelectionChange = (selection: any[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length !== 1;
+  multiple.value = !selection.length;
+};
+
+const reset = () => {
+  form.value = {
+    id: undefined,
+    navType: 'home',
+    navigationName: undefined,
+    url: undefined,
+    sort: 0,
+    isEnable: '0'
+  };
+  formRef.value?.resetFields();
+};
+
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加首页导航';
+};
+
+const handleUpdate = async (row: any) => {
+  reset();
+  const id = row.id || ids.value[0];
+  const res = await getNavigation(id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = '修改首页导航';
+};
+
+const submitForm = () => {
+  formRef.value.validate(async (valid: boolean) => {
+    if (valid) {
+      if (form.value.id) {
+        await updateNavigation(form.value);
+        proxy?.$modal.msgSuccess('修改成功');
+      } else {
+        await addNavigation(form.value);
+        proxy?.$modal.msgSuccess('新增成功');
+      }
+      dialog.visible = false;
+      getList();
+    }
+  });
+};
+
+const handleDelete = async (row?: any) => {
+  const deleteIds = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除?');
+  await delNavigation(deleteIds);
+  proxy?.$modal.msgSuccess('删除成功');
+  getList();
+};
+
+const cancel = () => {
+  dialog.visible = false;
+  reset();
+};
+
+getList();
+</script>

+ 210 - 0
src/views/system/innerNav/index.vue

@@ -0,0 +1,210 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="导航名称" prop="navigationName">
+              <el-input v-model="queryParams.navigationName" placeholder="请输入导航名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否启用" prop="isEnable">
+              <el-select v-model="queryParams.isEnable" placeholder="请选择" clearable>
+                <el-option label="是" value="0" />
+                <el-option label="否" value="1" />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="hover">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:navigation:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:navigation:remove']">删除</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="导航名称" prop="navigationName" />
+        <el-table-column label="链接地址" prop="url" show-overflow-tooltip />
+        <el-table-column label="排序" prop="sort" width="80" />
+        <el-table-column label="是否启用" prop="isEnable" width="100">
+          <template #default="scope">
+            <el-tag :type="scope.row.isEnable === '0' ? 'success' : 'danger'">
+              {{ scope.row.isEnable === '0' ? '是' : '否' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="150" align="center">
+          <template #default="scope">
+            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:navigation:edit']">修改</el-button>
+            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:navigation:remove']">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+
+    <!-- 添加或修改对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="导航名称" prop="navigationName">
+          <el-input v-model="form.navigationName" placeholder="请输入导航名称" />
+        </el-form-item>
+        <el-form-item label="链接地址" prop="url">
+          <el-input v-model="form.url" placeholder="请输入链接地址" />
+        </el-form-item>
+        <el-form-item label="排序" prop="sort">
+          <el-input-number v-model="form.sort" :min="0" />
+        </el-form-item>
+        <el-form-item label="是否启用" prop="isEnable">
+          <el-radio-group v-model="form.isEnable">
+            <el-radio value="0">是</el-radio>
+            <el-radio value="1">否</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="InnerNav" lang="ts">
+import { listNavigation, getNavigation, addNavigation, updateNavigation, delNavigation } from '@/api/system/navigation';
+import { ComponentInternalInstance, getCurrentInstance, ref, reactive, toRefs } from 'vue';
+import { ElForm } from 'element-plus';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const dataList = ref([]);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<number | string>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref(ElForm);
+const formRef = ref(ElForm);
+
+const dialog = reactive({ visible: false, title: '' });
+
+const data = reactive({
+  form: {} as any,
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    navType: 'inner',
+    navigationName: undefined,
+    isEnable: undefined
+  },
+  rules: {
+    navigationName: [{ required: true, message: '导航名称不能为空', trigger: 'blur' }],
+    url: [{ required: true, message: '链接地址不能为空', trigger: 'blur' }],
+    sort: [{ required: true, message: '排序不能为空', trigger: 'blur' }],
+    isEnable: [{ required: true, message: '请选择是否启用', trigger: 'change' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+const getList = async () => {
+  loading.value = true;
+  const res = await listNavigation(queryParams.value);
+  dataList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+const resetQuery = () => {
+  queryFormRef.value.resetFields();
+  handleQuery();
+};
+
+const handleSelectionChange = (selection: any[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length !== 1;
+  multiple.value = !selection.length;
+};
+
+const reset = () => {
+  form.value = {
+    id: undefined,
+    navType: 'inner',
+    navigationName: undefined,
+    url: undefined,
+    sort: 0,
+    isEnable: '0'
+  };
+  formRef.value?.resetFields();
+};
+
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加内页导航';
+};
+
+const handleUpdate = async (row: any) => {
+  reset();
+  const id = row.id || ids.value[0];
+  const res = await getNavigation(id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = '修改内页导航';
+};
+
+const submitForm = () => {
+  formRef.value.validate(async (valid: boolean) => {
+    if (valid) {
+      if (form.value.id) {
+        await updateNavigation(form.value);
+        proxy?.$modal.msgSuccess('修改成功');
+      } else {
+        await addNavigation(form.value);
+        proxy?.$modal.msgSuccess('新增成功');
+      }
+      dialog.visible = false;
+      getList();
+    }
+  });
+};
+
+const handleDelete = async (row?: any) => {
+  const deleteIds = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除?');
+  await delNavigation(deleteIds);
+  proxy?.$modal.msgSuccess('删除成功');
+  getList();
+};
+
+const cancel = () => {
+  dialog.visible = false;
+  reset();
+};
+
+getList();
+</script>

+ 158 - 0
src/views/system/loginSetting/index.vue

@@ -0,0 +1,158 @@
+<template>
+  <div class="p-2">
+    <el-card shadow="hover">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:platformConfig:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:platformConfig:remove']">删除</el-button>
+          </el-col>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="配置键" prop="configKey" />
+        <el-table-column label="配置名称" prop="name" />
+        <el-table-column label="配置值" prop="value" show-overflow-tooltip />
+        <el-table-column label="操作" width="150" align="center">
+          <template #default="scope">
+            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:platformConfig:edit']">修改</el-button>
+            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:platformConfig:remove']">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+
+    <!-- 添加或修改对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="配置键" prop="configKey">
+          <el-input v-model="form.configKey" placeholder="请输入配置键" />
+        </el-form-item>
+        <el-form-item label="配置名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入配置名称" />
+        </el-form-item>
+        <el-form-item label="配置值" prop="value">
+          <el-input v-model="form.value" type="textarea" placeholder="请输入配置值" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="LoginSetting" lang="ts">
+import { listPlatformConfig, getPlatformConfig, addPlatformConfig, updatePlatformConfig, delPlatformConfig } from '@/api/system/platformConfig';
+import { ComponentInternalInstance, getCurrentInstance, ref, reactive, toRefs } from 'vue';
+import { ElForm } from 'element-plus';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const dataList = ref([]);
+const loading = ref(true);
+const ids = ref<Array<number | string>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const formRef = ref(ElForm);
+
+const dialog = reactive({ visible: false, title: '' });
+
+const data = reactive({
+  form: {} as any,
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    configType: '1'
+  },
+  rules: {
+    configKey: [{ required: true, message: '配置键不能为空', trigger: 'blur' }],
+    name: [{ required: true, message: '配置名称不能为空', trigger: 'blur' }],
+    value: [{ required: true, message: '配置值不能为空', trigger: 'blur' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+const getList = async () => {
+  loading.value = true;
+  const res = await listPlatformConfig(queryParams.value);
+  dataList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+const handleSelectionChange = (selection: any[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length !== 1;
+  multiple.value = !selection.length;
+};
+
+const reset = () => {
+  form.value = {
+    id: undefined,
+    configType: '1',
+    configKey: undefined,
+    name: undefined,
+    value: undefined
+  };
+  formRef.value?.resetFields();
+};
+
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加登录配置';
+};
+
+const handleUpdate = async (row: any) => {
+  reset();
+  const id = row.id || ids.value[0];
+  const res = await getPlatformConfig(id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = '修改登录配置';
+};
+
+const submitForm = () => {
+  formRef.value.validate(async (valid: boolean) => {
+    if (valid) {
+      if (form.value.id) {
+        await updatePlatformConfig(form.value);
+        proxy?.$modal.msgSuccess('修改成功');
+      } else {
+        await addPlatformConfig(form.value);
+        proxy?.$modal.msgSuccess('新增成功');
+      }
+      dialog.visible = false;
+      getList();
+    }
+  });
+};
+
+const handleDelete = async (row?: any) => {
+  const deleteIds = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除?');
+  await delPlatformConfig(deleteIds);
+  proxy?.$modal.msgSuccess('删除成功');
+  getList();
+};
+
+const cancel = () => {
+  dialog.visible = false;
+  reset();
+};
+
+getList();
+</script>

+ 191 - 0
src/views/system/navigation/index.vue

@@ -0,0 +1,191 @@
+<template>
+  <div class="p-2">
+    <el-card shadow="hover">
+      <template #header>
+        <el-tabs v-model="activeTab" @tab-change="handleTabChange">
+          <el-tab-pane label="首页导航" name="home" />
+          <el-tab-pane label="内页导航" name="inner" />
+          <el-tab-pane label="搜索导航" name="search" />
+          <el-tab-pane label="底部导航" name="footer" />
+          <el-tab-pane label="浮动导航" name="float" />
+        </el-tabs>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
+          </el-col>
+          <right-toolbar @query-table="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" :data="navList" border>
+        <el-table-column label="导航名称" align="center" prop="navigationName" :show-overflow-tooltip="true" />
+        <el-table-column label="链接地址" align="center" prop="url" :show-overflow-tooltip="true" />
+        <el-table-column label="排序" align="center" prop="sort" width="80" />
+        <el-table-column label="是否启用" align="center" prop="isEnable" width="100">
+          <template #default="scope">
+            <el-tag :type="scope.row.isEnable === 1 ? 'success' : 'info'">
+              {{ scope.row.isEnable === 1 ? '启用' : '禁用' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-button link type="primary" @click="handleUpdate(scope.row)">编辑</el-button>
+            <el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total > 0"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        :total="total"
+        @pagination="getList"
+      />
+    </el-card>
+
+    <!-- 添加或修改对话框 -->
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
+      <el-form ref="navFormRef" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="导航名称" prop="navigationName">
+          <el-input v-model="form.navigationName" placeholder="请输入导航名称" />
+        </el-form-item>
+        <el-form-item label="链接地址" prop="url">
+          <el-input v-model="form.url" placeholder="请输入链接地址" />
+        </el-form-item>
+        <el-form-item label="排序" prop="sort">
+          <el-input-number v-model="form.sort" controls-position="right" :min="0" />
+        </el-form-item>
+        <el-form-item label="是否启用" prop="isEnable">
+          <el-radio-group v-model="form.isEnable">
+            <el-radio :value="1">启用</el-radio>
+            <el-radio :value="0">禁用</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Navigation" lang="ts">
+import { listNavigation, getNavigation, addNavigation, updateNavigation, delNavigation } from '@/api/system/navigation';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const navList = ref<any[]>([]);
+const loading = ref(false);
+const total = ref(0);
+const activeTab = ref('home');
+
+const queryParams = ref({
+  pageNum: 1,
+  pageSize: 10,
+  navType: 'home'
+});
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const navFormRef = ref<ElFormInstance>();
+
+const initFormData = {
+  id: undefined as number | undefined,
+  navType: 'home',
+  navigationName: '',
+  url: '',
+  sort: 0,
+  isEnable: 1
+};
+
+const form = ref({ ...initFormData });
+
+const rules = reactive({
+  navigationName: [{ required: true, message: '导航名称不能为空', trigger: 'blur' }],
+  url: [{ required: true, message: '链接地址不能为空', trigger: 'blur' }]
+});
+
+/** Tab 切换 */
+const handleTabChange = (tabName: string) => {
+  queryParams.value.navType = tabName;
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true;
+  try {
+    const res = await listNavigation(queryParams.value);
+    navList.value = res.rows;
+    total.value = res.total;
+  } finally {
+    loading.value = false;
+  }
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData, navType: activeTab.value };
+  navFormRef.value?.resetFields();
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加导航';
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row: any) => {
+  reset();
+  const res = await getNavigation(row.id);
+  form.value = res.data;
+  dialog.visible = true;
+  dialog.title = '修改导航';
+};
+
+/** 提交按钮 */
+const submitForm = () => {
+  navFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      if (form.value.id) {
+        await updateNavigation(form.value);
+        proxy?.$modal.msgSuccess('修改成功');
+      } else {
+        await addNavigation(form.value);
+        proxy?.$modal.msgSuccess('新增成功');
+      }
+      dialog.visible = false;
+      getList();
+    }
+  });
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row: any) => {
+  await proxy?.$modal.confirm('是否确认删除导航名称为"' + row.navigationName + '"的数据项?');
+  await delNavigation(row.id);
+  proxy?.$modal.msgSuccess('删除成功');
+  getList();
+};
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 181 - 0
src/views/system/platformConfig/index.vue

@@ -0,0 +1,181 @@
+<template>
+  <div class="p-2">
+    <el-card shadow="hover">
+      <template #header>
+        <el-tabs v-model="activeTab" @tab-change="handleTabChange">
+          <el-tab-pane label="基本设置" name="basic" />
+          <el-tab-pane label="登录设置" name="login" />
+        </el-tabs>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
+          </el-col>
+          <right-toolbar @query-table="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" :data="configList" border>
+        <el-table-column label="配置名称" align="center" prop="name" :show-overflow-tooltip="true" />
+        <el-table-column label="配置键" align="center" prop="configKey" :show-overflow-tooltip="true" />
+        <el-table-column label="配置值" align="center" prop="value" :show-overflow-tooltip="true" />
+        <el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-button link type="primary" @click="handleUpdate(scope.row)">编辑</el-button>
+            <el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total > 0"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        :total="total"
+        @pagination="getList"
+      />
+    </el-card>
+
+    <!-- 添加或修改对话框 -->
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
+      <el-form ref="configFormRef" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="配置名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入配置名称" />
+        </el-form-item>
+        <el-form-item label="配置键" prop="configKey">
+          <el-input v-model="form.configKey" placeholder="请输入配置键" />
+        </el-form-item>
+        <el-form-item label="配置值" prop="value">
+          <el-input v-model="form.value" type="textarea" :rows="3" placeholder="请输入配置值" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="PlatformConfig" lang="ts">
+import { listPlatformConfig, getPlatformConfig, addPlatformConfig, updatePlatformConfig, delPlatformConfig } from '@/api/system/platformConfig';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const configList = ref<any[]>([]);
+const loading = ref(false);
+const total = ref(0);
+const activeTab = ref('basic');
+
+// 配置类型映射:basic=1, login=2
+const configTypeMap: Record<string, number> = {
+  basic: 1,
+  login: 2
+};
+
+const queryParams = ref({
+  pageNum: 1,
+  pageSize: 10,
+  configType: 1
+});
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const configFormRef = ref<ElFormInstance>();
+
+const initFormData = {
+  id: undefined as number | undefined,
+  configType: 1,
+  configKey: '',
+  name: '',
+  value: ''
+};
+
+const form = ref({ ...initFormData });
+
+const rules = reactive({
+  name: [{ required: true, message: '配置名称不能为空', trigger: 'blur' }],
+  configKey: [{ required: true, message: '配置键不能为空', trigger: 'blur' }],
+  value: [{ required: true, message: '配置值不能为空', trigger: 'blur' }]
+});
+
+/** Tab 切换 */
+const handleTabChange = (tabName: string) => {
+  queryParams.value.configType = configTypeMap[tabName] || 1;
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true;
+  try {
+    const res = await listPlatformConfig(queryParams.value);
+    configList.value = res.rows;
+    total.value = res.total;
+  } finally {
+    loading.value = false;
+  }
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData, configType: queryParams.value.configType };
+  configFormRef.value?.resetFields();
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加配置';
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row: any) => {
+  reset();
+  const res = await getPlatformConfig(row.id);
+  form.value = res.data;
+  dialog.visible = true;
+  dialog.title = '修改配置';
+};
+
+/** 提交按钮 */
+const submitForm = () => {
+  configFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      if (form.value.id) {
+        await updatePlatformConfig(form.value);
+        proxy?.$modal.msgSuccess('修改成功');
+      } else {
+        await addPlatformConfig(form.value);
+        proxy?.$modal.msgSuccess('新增成功');
+      }
+      dialog.visible = false;
+      getList();
+    }
+  });
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row: any) => {
+  await proxy?.$modal.confirm('是否确认删除配置"' + row.name + '"?');
+  await delPlatformConfig(row.id);
+  proxy?.$modal.msgSuccess('删除成功');
+  getList();
+};
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 210 - 0
src/views/system/searchNav/index.vue

@@ -0,0 +1,210 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="导航名称" prop="navigationName">
+              <el-input v-model="queryParams.navigationName" placeholder="请输入导航名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否启用" prop="isEnable">
+              <el-select v-model="queryParams.isEnable" placeholder="请选择" clearable>
+                <el-option label="是" value="0" />
+                <el-option label="否" value="1" />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="hover">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:navigation:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:navigation:remove']">删除</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="导航名称" prop="navigationName" />
+        <el-table-column label="链接地址" prop="url" show-overflow-tooltip />
+        <el-table-column label="排序" prop="sort" width="80" />
+        <el-table-column label="是否启用" prop="isEnable" width="100">
+          <template #default="scope">
+            <el-tag :type="scope.row.isEnable === '0' ? 'success' : 'danger'">
+              {{ scope.row.isEnable === '0' ? '是' : '否' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="150" align="center">
+          <template #default="scope">
+            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:navigation:edit']">修改</el-button>
+            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:navigation:remove']">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+
+    <!-- 添加或修改对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="导航名称" prop="navigationName">
+          <el-input v-model="form.navigationName" placeholder="请输入导航名称" />
+        </el-form-item>
+        <el-form-item label="链接地址" prop="url">
+          <el-input v-model="form.url" placeholder="请输入链接地址" />
+        </el-form-item>
+        <el-form-item label="排序" prop="sort">
+          <el-input-number v-model="form.sort" :min="0" />
+        </el-form-item>
+        <el-form-item label="是否启用" prop="isEnable">
+          <el-radio-group v-model="form.isEnable">
+            <el-radio value="0">是</el-radio>
+            <el-radio value="1">否</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="SearchNav" lang="ts">
+import { listNavigation, getNavigation, addNavigation, updateNavigation, delNavigation } from '@/api/system/navigation';
+import { ComponentInternalInstance, getCurrentInstance, ref, reactive, toRefs } from 'vue';
+import { ElForm } from 'element-plus';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const dataList = ref([]);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<number | string>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref(ElForm);
+const formRef = ref(ElForm);
+
+const dialog = reactive({ visible: false, title: '' });
+
+const data = reactive({
+  form: {} as any,
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    navType: 'search',
+    navigationName: undefined,
+    isEnable: undefined
+  },
+  rules: {
+    navigationName: [{ required: true, message: '导航名称不能为空', trigger: 'blur' }],
+    url: [{ required: true, message: '链接地址不能为空', trigger: 'blur' }],
+    sort: [{ required: true, message: '排序不能为空', trigger: 'blur' }],
+    isEnable: [{ required: true, message: '请选择是否启用', trigger: 'change' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+const getList = async () => {
+  loading.value = true;
+  const res = await listNavigation(queryParams.value);
+  dataList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+const resetQuery = () => {
+  queryFormRef.value.resetFields();
+  handleQuery();
+};
+
+const handleSelectionChange = (selection: any[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length !== 1;
+  multiple.value = !selection.length;
+};
+
+const reset = () => {
+  form.value = {
+    id: undefined,
+    navType: 'search',
+    navigationName: undefined,
+    url: undefined,
+    sort: 0,
+    isEnable: '0'
+  };
+  formRef.value?.resetFields();
+};
+
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加搜索导航';
+};
+
+const handleUpdate = async (row: any) => {
+  reset();
+  const id = row.id || ids.value[0];
+  const res = await getNavigation(id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = '修改搜索导航';
+};
+
+const submitForm = () => {
+  formRef.value.validate(async (valid: boolean) => {
+    if (valid) {
+      if (form.value.id) {
+        await updateNavigation(form.value);
+        proxy?.$modal.msgSuccess('修改成功');
+      } else {
+        await addNavigation(form.value);
+        proxy?.$modal.msgSuccess('新增成功');
+      }
+      dialog.visible = false;
+      getList();
+    }
+  });
+};
+
+const handleDelete = async (row?: any) => {
+  const deleteIds = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除?');
+  await delNavigation(deleteIds);
+  proxy?.$modal.msgSuccess('删除成功');
+  getList();
+};
+
+const cancel = () => {
+  dialog.visible = false;
+  reset();
+};
+
+getList();
+</script>

+ 165 - 0
src/views/system/terms/index.vue

@@ -0,0 +1,165 @@
+<template>
+  <div class="p-2">
+    <el-card shadow="hover">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
+          </el-col>
+          <right-toolbar @query-table="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" :data="termsList" border>
+        <el-table-column label="条款类型" align="center" prop="type" :show-overflow-tooltip="true" />
+        <el-table-column label="排序" align="center" prop="sort" width="80" />
+        <el-table-column label="创建时间" align="center" prop="createTime" width="180" />
+        <el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-button link type="primary" @click="handleUpdate(scope.row)">编辑</el-button>
+            <el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total > 0"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        :total="total"
+        @pagination="getList"
+      />
+    </el-card>
+
+    <!-- 添加或修改对话框 -->
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="800px" append-to-body>
+      <el-form ref="termsFormRef" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="条款类型" prop="type">
+          <el-input v-model="form.type" placeholder="请输入条款类型名称" />
+        </el-form-item>
+        <el-form-item label="排序" prop="sort">
+          <el-input-number v-model="form.sort" controls-position="right" :min="0" />
+        </el-form-item>
+        <el-form-item label="内容" prop="content">
+          <el-input
+            v-model="form.content"
+            type="textarea"
+            :rows="10"
+            placeholder="请输入条款内容(支持HTML)"
+          />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Terms" lang="ts">
+import { listTerms, getTerms, addTerms, updateTerms, delTerms } from '@/api/system/terms';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const termsList = ref<any[]>([]);
+const loading = ref(false);
+const total = ref(0);
+
+const queryParams = ref({
+  pageNum: 1,
+  pageSize: 10
+});
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const termsFormRef = ref<ElFormInstance>();
+
+const initFormData = {
+  id: undefined as number | undefined,
+  type: '',
+  content: '',
+  sort: 0
+};
+
+const form = ref({ ...initFormData });
+
+const rules = reactive({
+  type: [{ required: true, message: '条款类型不能为空', trigger: 'blur' }],
+  content: [{ required: true, message: '条款内容不能为空', trigger: 'blur' }]
+});
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true;
+  try {
+    const res = await listTerms(queryParams.value);
+    termsList.value = res.rows;
+    total.value = res.total;
+  } finally {
+    loading.value = false;
+  }
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  termsFormRef.value?.resetFields();
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加条款';
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row: any) => {
+  reset();
+  const res = await getTerms(row.id);
+  form.value = res.data;
+  dialog.visible = true;
+  dialog.title = '修改条款';
+};
+
+/** 提交按钮 */
+const submitForm = () => {
+  termsFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      if (form.value.id) {
+        await updateTerms(form.value);
+        proxy?.$modal.msgSuccess('修改成功');
+      } else {
+        await addTerms(form.value);
+        proxy?.$modal.msgSuccess('新增成功');
+      }
+      dialog.visible = false;
+      getList();
+    }
+  });
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row: any) => {
+  await proxy?.$modal.confirm('是否确认删除该条款?');
+  await delTerms(row.id);
+  proxy?.$modal.msgSuccess('删除成功');
+  getList();
+};
+
+onMounted(() => {
+  getList();
+});
+</script>