| | |
| | | <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> |
| | |
| | | 导出 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" /> |
| | |
| | | </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> |
| | |
| | | <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> |
| | |
| | | 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" |
| | |
| | | <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"> |
| | |
| | | </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> |
| | |
| | | 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; |
| | |
| | | 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); |
| | |
| | | mobile: "", |
| | | gender: "", |
| | | companyName: "", |
| | | statusEnabled: true, |
| | | }); |
| | | const originalStatus = ref<number>(1); |
| | | |
| | | function indexMethod(idx: number) { |
| | | return (page.value - 1) * size.value + idx + 1; |
| | |
| | | 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 : "加载详情失败"); |
| | |
| | | form.mobile = ""; |
| | | form.gender = ""; |
| | | form.companyName = ""; |
| | | form.statusEnabled = true; |
| | | originalStatus.value = 1; |
| | | } |
| | | |
| | | async function submitEdit() { |
| | |
| | | } |
| | | 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(); |
| | |
| | | } |
| | | }) |
| | | .catch(() => {}); |
| | | } |
| | | |
| | | function onStatusSwitchChange(row: VisitorRow, checked: string | number | boolean) { |
| | | const status = checked ? 1 : 0; |
| | | patchStatus(row, status); |
| | | } |
| | | |
| | | function confirmDelete(row: VisitorRow) { |
| | |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 12px; |
| | | height: calc(100vh - 170px); |
| | | min-height: calc(100vh - 170px); |
| | | } |
| | | |
| | | .search-card, |
| | |
| | | |
| | | .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 { |
| | |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-top: 14px; |
| | | flex: none; |
| | | } |
| | | |
| | | .pager-total { |