puzhibing
2026-08-28 e92cd56bb56b111c1afe9922191f9897215ff6b0
frontend-admin/src/views/VisitorInfoView.vue
@@ -4,13 +4,13 @@
      <div class="panel-title">访客信息列表</div>
      <el-form class="search-grid" @submit.prevent="doSearch">
        <el-form-item label="用户名称">
          <el-input v-model="filters.userName" placeholder="请输入内容" clearable />
          <el-input v-model="filters.userName" placeholder="请输入用户名称" clearable />
        </el-form-item>
        <el-form-item label="用户电话">
          <el-input v-model="filters.mobile" placeholder="请输入内容" clearable />
          <el-input v-model="filters.mobile" placeholder="请输入用户电话" clearable />
        </el-form-item>
        <el-form-item label="所属公司">
          <el-input v-model="filters.companyName" placeholder="请输入内容" clearable />
          <el-input v-model="filters.companyName" placeholder="请输入所属公司" clearable />
        </el-form-item>
        <el-form-item label="状态">
          <el-select v-model="filters.status" placeholder="请选择" clearable>
@@ -48,7 +48,8 @@
          导出 Excel
        </el-button>
      </div>
      <el-table :data="rows" v-loading="loading" stripe border>
      <div class="table-wrap">
        <el-table :data="rows" v-loading="loading" stripe border height="100%">
        <el-table-column label="序号" width="68" type="index" :index="indexMethod" />
        <el-table-column prop="userName" label="用户" min-width="120" show-overflow-tooltip />
        <el-table-column prop="gender" label="性别" width="88" align="center" />
@@ -61,7 +62,15 @@
        </el-table-column>
        <el-table-column label="状态" width="92" align="center">
          <template #default="{ row }">
            <el-tag :type="row.status === 1 ? 'success' : 'info'">
            <el-switch
              v-permission="'sys:visitor-users:status'"
              :model-value="row.status === 1"
              inline-prompt
              active-text="启用"
              inactive-text="禁用"
              @change="onStatusSwitchChange(row, $event)"
            />
            <el-tag v-if="!auth.hasPermission('sys:visitor-users:status')" :type="row.status === 1 ? 'success' : 'info'">
              {{ row.status === 1 ? "启用" : "禁用" }}
            </el-tag>
          </template>
@@ -75,23 +84,12 @@
          <template #default="{ row }">
            <div class="table-ops">
              <el-button v-permission="'sys:visitor-users:update'" type="primary" link @click="openEdit(row)">编辑</el-button>
              <el-button
                v-permission="'sys:visitor-users:status'"
                v-if="row.status === 1"
                type="warning"
                link
                @click="patchStatus(row, 0)"
              >
                禁用
              </el-button>
              <el-button v-else v-permission="'sys:visitor-users:status'" type="success" link @click="patchStatus(row, 1)">
                启用
              </el-button>
              <el-button v-permission="'sys:visitor-users:delete'" type="danger" link @click="confirmDelete(row)">删除</el-button>
              <el-button v-permission="'sys:visitor-users:delete'" type="primary" link @click="confirmDelete(row)">删除</el-button>
            </div>
          </template>
        </el-table-column>
      </el-table>
        </el-table>
      </div>
      <div class="pager-wrap">
        <div class="pager-total">共 {{ total }} 条</div>
@@ -100,7 +98,7 @@
          layout="sizes, prev, pager, next"
          :total="total"
          :page-size="size"
          :page-sizes="[10, 16, 20, 50, 100]"
          :page-sizes="[10, 20, 50, 100]"
          v-model:current-page="page"
          @current-change="load"
          @size-change="onSizeChange"
@@ -114,7 +112,7 @@
          <el-input v-model="form.userName" maxlength="30" placeholder="请输入" />
        </el-form-item>
        <el-form-item label="用户电话" required>
          <el-input v-model="form.mobile" maxlength="11" placeholder="11位数字" />
          <el-input v-model="form.mobile" maxlength="11" placeholder="请输入11位手机号" />
        </el-form-item>
        <el-form-item label="性别">
          <el-radio-group v-model="form.gender">
@@ -125,6 +123,14 @@
        </el-form-item>
        <el-form-item label="所属公司">
          <el-input v-model="form.companyName" maxlength="128" placeholder="请输入" />
        </el-form-item>
        <el-form-item label="状态">
          <el-switch
            v-model="form.statusEnabled"
            inline-prompt
            active-text="启用"
            inactive-text="禁用"
          />
        </el-form-item>
      </el-form>
      <template #footer>
@@ -140,6 +146,8 @@
import { ElMessage, ElMessageBox } from "element-plus";
import { Refresh, Search } from "@element-plus/icons-vue";
import http from "../api/http";
import { normalizeFormData } from "../utils/formHelper";
import { useAuthStore } from "../stores/auth";
type VisitorRow = {
  id: number;
@@ -166,9 +174,10 @@
const loading = ref(false);
const saving = ref(false);
const exporting = ref(false);
const auth = useAuthStore();
const rows = ref<VisitorRow[]>([]);
const page = ref(1);
const size = ref(16);
const size = ref(10);
const total = ref(0);
const registerDateRange = ref<string[]>([]);
const dlg = ref(false);
@@ -187,7 +196,9 @@
  mobile: "",
  gender: "",
  companyName: "",
  statusEnabled: true,
});
const originalStatus = ref<number>(1);
function indexMethod(idx: number) {
  return (page.value - 1) * size.value + idx + 1;
@@ -299,6 +310,8 @@
    form.mobile = detail.mobile || "";
    form.gender = detail.gender || "";
    form.companyName = detail.companyName || "";
    form.statusEnabled = detail.status === 1;
    originalStatus.value = detail.status ?? 1;
    dlg.value = true;
  } catch (e: unknown) {
    ElMessage.error(e instanceof Error ? e.message : "加载详情失败");
@@ -312,6 +325,8 @@
  form.mobile = "";
  form.gender = "";
  form.companyName = "";
  form.statusEnabled = true;
  originalStatus.value = 1;
}
async function submitEdit() {
@@ -334,13 +349,22 @@
  }
  saving.value = true;
  try {
    await http.put(`/sys/visitor-users/${editingId.value}`, {
    const payload = normalizeFormData({
      uuid: form.uuid,
      userName: form.userName.trim(),
      mobile: form.mobile.trim(),
      gender: form.gender || undefined,
      companyName: form.companyName.trim() || undefined,
    });
    await http.put(`/sys/visitor-users/${editingId.value}`, payload);
    const nextStatus = form.statusEnabled ? 1 : 0;
    if (nextStatus !== originalStatus.value) {
      const statusPayload = normalizeFormData({
        uuid: form.uuid,
        status: nextStatus,
      });
      await http.patch(`/sys/visitor-users/${editingId.value}/status`, statusPayload);
    }
    ElMessage.success("已保存");
    dlg.value = false;
    load();
@@ -364,6 +388,11 @@
      }
    })
    .catch(() => {});
}
function onStatusSwitchChange(row: VisitorRow, checked: string | number | boolean) {
  const status = checked ? 1 : 0;
  patchStatus(row, status);
}
function confirmDelete(row: VisitorRow) {
@@ -390,6 +419,8 @@
  display: flex;
  flex-direction: column;
  gap: 12px;
  height: calc(100vh - 170px);
  min-height: calc(100vh - 170px);
}
.search-card,
@@ -447,12 +478,23 @@
.table-card {
  padding: 14px 16px 12px;
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}
.table-toolbar {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 12px;
  flex: none;
}
.table-wrap {
  flex: 1;
  min-height: 0;
}
.pager-wrap {
@@ -460,6 +502,7 @@
  justify-content: space-between;
  align-items: center;
  margin-top: 14px;
  flex: none;
}
.pager-total {