tuqin
2026-10-29 000ec7fa68e3d46975a311ed2d3dde740073c44b
feat(LIMS): 系统配置页加审计日志与系统参数两个 Tab

- 系统参数 Tab:按分类/参数名筛选,列表展示分类/参数键/参数名/当前值/默认值/说明,可编辑
- 审计日志 Tab:按模块/动作/操作人筛选,列表展示时间/模块/动作/业务编号/说明/字段/旧值/新值/操作人/IP/结果
- 新增参数编辑弹窗(分类/参数键/参数名/参数值/值类型/默认值/说明)
- 新增 setting.js / auditLog.js 两个 API
已添加2个文件
已修改1个文件
194 ■■■■■ 文件已修改
src/api/lims/auditLog.js 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/lims/setting.js 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/lims/systemConfig/index.vue 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/lims/auditLog.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
// å®¡è®¡æ—¥å¿—接口
import request from '@/utils/request'
export function listAuditLog(query) {
    return request({ url: '/lims/auditLog/listPage', method: 'get', params: query })
}
export function getAuditLog(id) {
    return request({ url: '/lims/auditLog/' + id, method: 'get' })
}
export function addAuditLog(data) {
    return request({ url: '/lims/auditLog/add', method: 'post', data: data })
}
export function updateAuditLog(data) {
    return request({ url: '/lims/auditLog/update', method: 'post', data: data })
}
export function delAuditLog(ids) {
    return request({ url: '/lims/auditLog/delete', method: 'delete', data: ids })
}
src/api/lims/setting.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
// ç³»ç»Ÿå‚数接口
import request from '@/utils/request'
export function listSetting(query) {
    return request({ url: '/lims/setting/listPage', method: 'get', params: query })
}
export function getSetting(id) {
    return request({ url: '/lims/setting/' + id, method: 'get' })
}
export function addSetting(data) {
    return request({ url: '/lims/setting/add', method: 'post', data: data })
}
export function updateSetting(data) {
    return request({ url: '/lims/setting/update', method: 'post', data: data })
}
export function delSetting(ids) {
    return request({ url: '/lims/setting/delete', method: 'delete', data: ids })
}
src/views/lims/systemConfig/index.vue
@@ -92,6 +92,54 @@
          @pagination="paginationStd"
        />
      </el-tab-pane>
      <!-- ==================== Tab4: ç³»ç»Ÿå‚æ•° ==================== -->
      <el-tab-pane label="系统参数" name="setting">
        <div class="search_form">
          <div>
            <span class="search_title">分类:</span>
            <el-select v-model="setSearch.category" style="width: 150px" placeholder="全部" clearable @change="loadSetting">
              <el-option label="采集" value="collect" /><el-option label="清洗" value="clean" />
              <el-option label="预警" value="alert" /><el-option label="安全" value="security" />
              <el-option label="样品" value="sample" /><el-option label="试剂" value="reagent" /><el-option label="界面" value="ui" />
            </el-select>
            <span class="search_title" style="margin-left: 16px">参数名:</span>
            <el-input v-model="setSearch.settingName" style="width: 180px" placeholder="请输入" clearable @change="loadSetting" />
            <el-button type="primary" style="margin-left: 10px" @click="loadSetting">搜索</el-button>
          </div>
          <div>
            <el-button type="primary" @click="openSetForm('add')">新增参数</el-button>
            <el-button @click="loadSetting">刷新</el-button>
          </div>
        </div>
        <PIMTable rowKey="id" :column="setColumns" :tableData="setData" :page="setPage"
          :tableLoading="setLoading" @pagination="paginationSet" />
      </el-tab-pane>
      <!-- ==================== Tab5: å®¡è®¡æ—¥å¿— ==================== -->
      <el-tab-pane label="审计日志" name="auditLog">
        <div class="search_form">
          <div>
            <span class="search_title">模块:</span>
            <el-input v-model="auditSearch.module" style="width: 150px" placeholder="如 æ ·å“ç®¡ç†" clearable @change="loadAudit" />
            <span class="search_title" style="margin-left: 16px">动作:</span>
            <el-select v-model="auditSearch.action" style="width: 150px" placeholder="全部" clearable @change="loadAudit">
              <el-option label="新增" value="create" /><el-option label="修改" value="update" />
              <el-option label="删除" value="delete" /><el-option label="出库" value="stock_out" />
              <el-option label="入库" value="stock_in" /><el-option label="分配资源" value="assign_resource" />
              <el-option label="处理告警" value="handle_alert" />
            </el-select>
            <span class="search_title" style="margin-left: 16px">操作人:</span>
            <el-input v-model="auditSearch.operator" style="width: 140px" placeholder="请输入" clearable @change="loadAudit" />
            <el-button type="primary" style="margin-left: 10px" @click="loadAudit">搜索</el-button>
          </div>
          <div>
            <el-button @click="loadAudit">刷新</el-button>
          </div>
        </div>
        <PIMTable rowKey="id" :column="auditColumns" :tableData="auditData" :page="auditPage"
          :tableLoading="auditLoading" @pagination="paginationAudit" />
      </el-tab-pane>
    </el-tabs>
    <!-- ==================== æ£€æµ‹é¡¹ç›®è¡¨å• ==================== -->
@@ -185,6 +233,33 @@
      </template>
    </el-dialog>
  </div>
    <!-- ===== ç³»ç»Ÿå‚数编辑 ===== -->
    <el-dialog v-model="setDialogVisible" :title="setOpType === 'add' ? '新增参数' : '编辑参数'" width="600px">
      <el-form :model="setForm" label-position="top">
        <el-row :gutter="16">
          <el-col :span="12"><el-form-item label="分类"><el-input v-model="setForm.category" placeholder="collect/clean/alert/security" /></el-form-item></el-col>
          <el-col :span="12"><el-form-item label="参数键"><el-input v-model="setForm.settingKey" /></el-form-item></el-col>
          <el-col :span="12"><el-form-item label="参数名"><el-input v-model="setForm.settingName" /></el-form-item></el-col>
          <el-col :span="12"><el-form-item label="参数值"><el-input v-model="setForm.settingValue" /></el-form-item></el-col>
          <el-col :span="12">
            <el-form-item label="值类型">
              <el-select v-model="setForm.valueType" style="width: 100%">
                <el-option label="字符串" value="string" /><el-option label="数字" value="number" />
                <el-option label="布尔" value="boolean" /><el-option label="下拉" value="select" />
                <el-option label="JSON" value="json" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12"><el-form-item label="默认值"><el-input v-model="setForm.defaultValue" /></el-form-item></el-col>
          <el-col :span="24"><el-form-item label="说明"><el-input v-model="setForm.description" type="textarea" :rows="2" /></el-form-item></el-col>
        </el-row>
      </el-form>
      <template #footer>
        <el-button @click="setDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="submitSet">确定</el-button>
      </template>
    </el-dialog>
</template>
<script setup>
@@ -195,6 +270,8 @@
import {
  listJudgmentStandard, getJudgmentStandard, addJudgmentStandard, updateJudgmentStandard, delJudgmentStandard,
} from "@/api/lims/judgmentStandard";
import { listSetting, getSetting, addSetting, updateSetting, delSetting } from "@/api/lims/setting";
import { listAuditLog } from "@/api/lims/auditLog";
const activeTab = ref("testItem");
const itemOptions = ref([]);
@@ -418,7 +495,80 @@
  doDelStd(ids);
};
// ==================== â‘¨ ç³»ç»Ÿå‚æ•° ====================
const setSearch = ref({});
const setData = ref([]);
const setLoading = ref(false);
const setPage = reactive({ pageNum: 1, pageSize: 10, total: 0 });
const setColumns = ref([
  { label: "分类", prop: "category", width: 100 },
  { label: "参数键", prop: "settingKey", width: 220 },
  { label: "参数名", prop: "settingName", width: 160 },
  { label: "当前值", prop: "settingValue", width: 140 },
  { label: "默认值", prop: "defaultValue", width: 110 },
  { label: "说明", prop: "description", showOverflowTooltip: true },
  {
    dataType: "action", label: "操作", align: "center", fixed: "right", width: 100,
    operation: [{ name: "编辑", type: "text", clickFun: (row) => openSetForm("edit", row) }],
  },
]);
const loadSetting = () => {
  setLoading.value = true;
  listSetting({ ...setSearch.value, ...setPage }).then((res) => {
    setLoading.value = false;
    setData.value = res.data.records || [];
    setPage.total = res.data.total || 0;
  }).catch(() => (setLoading.value = false));
};
const paginationSet = (p) => { setPage.pageNum = p.pageNum; setPage.pageSize = p.pageSize; loadSetting(); };
const setDialogVisible = ref(false);
const setOpType = ref("add");
const setForm = ref({});
const openSetForm = (type, row) => {
  setOpType.value = type;
  setForm.value = type === "edit" ? { ...row } : { valueType: "string", editable: "1", sortNo: 100 };
  setDialogVisible.value = true;
};
const submitSet = () => {
  const fn = setOpType.value === "add" ? addSetting : updateSetting;
  fn(setForm.value).then(() => {
    ElMessage.success("保存成功");
    setDialogVisible.value = false;
    loadSetting();
  });
};
// ==================== â‘§ å®¡è®¡æ—¥å¿— ====================
const auditSearch = ref({});
const auditData = ref([]);
const auditLoading = ref(false);
const auditPage = reactive({ pageNum: 1, pageSize: 20, total: 0 });
const auditColumns = ref([
  { label: "时间", prop: "operateTime", width: 160 },
  { label: "模块", prop: "module", width: 110 },
  { label: "动作", prop: "action", width: 130 },
  { label: "业务编号", prop: "bizCode", width: 140 },
  { label: "说明", prop: "description", showOverflowTooltip: true },
  { label: "字段", prop: "fieldName", width: 100 },
  { label: "旧值", prop: "oldValue", width: 100 },
  { label: "新值", prop: "newValue", width: 100 },
  { label: "操作人", prop: "operator", width: 100 },
  { label: "IP", prop: "operatorIp", width: 130 },
  { label: "结果", prop: "execResult", width: 80 },
]);
const loadAudit = () => {
  auditLoading.value = true;
  listAuditLog({ ...auditSearch.value, ...auditPage }).then((res) => {
    auditLoading.value = false;
    auditData.value = res.data.records || [];
    auditPage.total = res.data.total || 0;
  }).catch(() => (auditLoading.value = false));
};
const paginationAudit = (p) => { auditPage.pageNum = p.pageNum; auditPage.pageSize = p.pageSize; loadAudit(); };
onMounted(() => {
  loadSetting();
  loadAudit();
  loadItem();
  loadItemOptions();
  loadUnit();