puzhibing
2026-08-28 e92cd56bb56b111c1afe9922191f9897215ff6b0
frontend-admin/src/views/VisitReasonsSettingsView.vue
@@ -5,36 +5,68 @@
      <el-button v-permission="'config:visit-reasons:create'" type="primary" @click="openCreate">新增</el-button>
    </div>
    <el-table :data="rows" v-loading="loading" stripe border>
      <el-table-column label="序号" width="72" type="index" :index="indexMethod" />
      <el-table-column prop="reasonName" label="来访事由" min-width="220" show-overflow-tooltip />
      <el-table-column label="创建时间" width="180">
        <template #default="{ row }">{{ formatTime(row.createTime) }}</template>
      </el-table-column>
      <el-table-column label="操作" width="160" fixed="right">
        <template #default="{ row }">
          <div class="table-ops">
            <el-button v-permission="'config:visit-reasons:update'" type="primary" link @click="openEdit(row)">编辑</el-button>
            <el-button v-permission="'config:visit-reasons:delete'" type="danger" link @click="confirmDelete(row)">删除</el-button>
          </div>
        </template>
      </el-table-column>
    </el-table>
    <div class="table-wrap">
      <el-table :data="rows" v-loading="loading" stripe border height="100%">
        <el-table-column label="序号" width="72" type="index" :index="indexMethod" />
        <el-table-column prop="reasonName" label="来访事由" min-width="220" show-overflow-tooltip />
        <el-table-column prop="sortOrder" label="排序" width="100" />
        <el-table-column label="创建时间" width="180">
          <template #default="{ row }">{{ formatTime(row.createTime) }}</template>
        </el-table-column>
        <el-table-column label="操作" width="160" fixed="right">
          <template #default="{ row }">
            <div class="table-ops">
              <el-button
                v-if="!isOtherReason(row)"
                v-permission="'config:visit-reasons:update'"
                type="primary"
                link
                @click="openEdit(row)"
              >
                编辑
              </el-button>
              <el-button
                v-if="!isOtherReason(row)"
                v-permission="'config:visit-reasons:delete'"
                type="primary"
                link
                @click="confirmDelete(row)"
              >
                删除
              </el-button>
            </div>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <el-pagination
      class="pager"
      background
      layout="prev, pager, next"
      layout="sizes, prev, pager, next"
      :total="total"
      :page-size="size"
      :page-sizes="[10, 20, 50, 100]"
      v-model:current-page="page"
      @current-change="load"
      @size-change="onSizeChange"
    />
    <el-dialog v-model="dlg" :title="dlgTitle" width="460px" destroy-on-close>
      <el-form :model="form" label-width="92px">
        <el-form-item label="来访事由" required>
          <el-input v-model="form.reasonName" maxlength="128" show-word-limit placeholder="请输入来访事由" />
          <el-input v-model="form.reasonName" maxlength="15" placeholder="请输入15个字以内" />
        </el-form-item>
        <el-form-item label="排序" required>
          <el-input-number
            v-model="form.sortOrder"
            :min="0"
            :max="999999"
            :step="10"
            :controls="false"
            placeholder="请输入排序数字"
            class="w-full"
          />
        </el-form-item>
      </el-form>
      <template #footer>
@@ -56,11 +88,14 @@
import { onMounted, reactive, ref } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import http from "../api/http";
import { normalizeFormData } from "../utils/formHelper";
type Row = {
  id: number;
  uuid: string;
  reasonCode?: string;
  reasonName: string;
  sortOrder: number;
  createTime: string;
};
@@ -78,6 +113,7 @@
const form = reactive({
  uuid: "",
  reasonName: "",
  sortOrder: 0,
});
function indexMethod(i: number) {
@@ -87,6 +123,10 @@
function formatTime(s: string) {
  if (!s) return "";
  return s.replace("T", " ").slice(0, 19);
}
function isOtherReason(row: Row) {
  return row.reasonCode === "OTHER" || row.reasonName === "其他";
}
async function load() {
@@ -109,14 +149,25 @@
  editingId.value = null;
  form.uuid = "";
  form.reasonName = "";
  form.sortOrder = rows.value.reduce((max, row) => Math.max(max, Number(row.sortOrder) || 0), 0) + 10;
  dlg.value = true;
}
function onSizeChange(nextSize: number) {
  size.value = nextSize;
  page.value = 1;
  load();
}
function openEdit(row: Row) {
  if (isOtherReason(row)) {
    return;
  }
  dlgTitle.value = "编辑来访事由";
  editingId.value = row.id;
  form.uuid = row.uuid;
  form.reasonName = row.reasonName || "";
  form.sortOrder = Number(row.sortOrder) || 0;
  dlg.value = true;
}
@@ -126,16 +177,26 @@
    ElMessage.warning("请填写来访事由");
    return;
  }
  if (form.sortOrder == null || Number(form.sortOrder) < 0) {
    ElMessage.warning("请输入排序数字");
    return;
  }
  saving.value = true;
  try {
    // 处理表单数据:字符串 null/undefined 转为空字符串
    const normalized = normalizeFormData({
      reasonName: form.reasonName,
      sortOrder: Number(form.sortOrder) || 0,
    });
    if (editingId.value == null) {
      await http.post("/config/visit-reasons/manage", { reasonName });
      await http.post("/config/visit-reasons/manage", normalized);
      ElMessage.success("已新增");
      page.value = 1;
    } else {
      await http.put(`/config/visit-reasons/manage/${editingId.value}`, {
        uuid: form.uuid,
        reasonName,
        ...normalized,
      });
      ElMessage.success("已保存");
    }
@@ -149,6 +210,9 @@
}
function confirmDelete(row: Row) {
  if (isOtherReason(row)) {
    return;
  }
  ElMessageBox.confirm(`确认删除来访事由「${row.reasonName}」?`, "删除确认", { type: "warning" })
    .then(async () => {
      try {
@@ -173,12 +237,17 @@
<style scoped>
.page {
  padding: 0;
  display: flex;
  flex-direction: column;
  height: calc(100vh - 190px);
  min-height: 420px;
}
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
  flex: none;
}
.section-title {
  font-size: 16px;
@@ -188,8 +257,13 @@
  border-left: 3px solid #409eff;
  color: #303133;
}
.table-wrap {
  flex: 1;
  min-height: 0;
}
.pager {
  margin-top: 12px;
  justify-content: flex-end;
  flex: none;
}
</style>