1954 lines
59 KiB
Vue
1954 lines
59 KiB
Vue
<template>
|
||
<div class="check-project-settings">
|
||
<!-- 左侧导航栏 -->
|
||
<div class="sidebar">
|
||
<div class="sidebar-header">
|
||
<h3>检查项目管理</h3>
|
||
</div>
|
||
<div class="sidebar-menu">
|
||
<!-- 明确列出所有导航项 -->
|
||
<button
|
||
class="menu-item active"
|
||
@click="handleMenuClick('检查类型')"
|
||
>
|
||
<span class="menu-icon">📋</span>
|
||
<span class="menu-text">检查类型</span>
|
||
</button>
|
||
<button
|
||
class="menu-item"
|
||
@click="handleMenuClick('检查方法')"
|
||
>
|
||
<span class="menu-icon">🔬</span>
|
||
<span class="menu-text">检查方法</span>
|
||
</button>
|
||
<button
|
||
class="menu-item"
|
||
@click="handleMenuClick('检查部位')"
|
||
>
|
||
<span class="menu-icon">🎯</span>
|
||
<span class="menu-text">检查部位</span>
|
||
</button>
|
||
<button
|
||
class="menu-item"
|
||
@click="handleMenuClick('套餐设置')"
|
||
>
|
||
<span class="menu-icon">📦</span>
|
||
<span class="menu-text">套餐设置</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 主内容区域 -->
|
||
<div class="content">
|
||
<!-- 套餐管理和套餐设置 -->
|
||
<template v-if="activeMenu === '套餐设置'">
|
||
<!-- 套餐设置界面(默认显示) -->
|
||
<PackageSettings
|
||
v-if="packageView === 'settings'"
|
||
:mode="packageMode"
|
||
:package-data="currentPackageData"
|
||
@switch-to-management="handleSwitchToManagement"
|
||
@save-success="handleSaveSuccess"
|
||
/>
|
||
|
||
<!-- 套餐管理界面(列表) -->
|
||
<PackageManagement
|
||
v-else
|
||
@switch-to-settings="handleSwitchToSettings"
|
||
/>
|
||
</template>
|
||
<!-- 检查类型的表格视图 -->
|
||
<template v-if="activeMenu === '检查类型'">
|
||
<div class="header">
|
||
<h1>{{ activeMenu }}管理</h1>
|
||
<div class="header-actions">
|
||
<button class="btn btn-add-new" @click="handleAddNewRow">+
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th style="width: 50px;">行</th>
|
||
<th style="width: 100px;">*编码</th>
|
||
<th style="width: 150px;">*名称</th>
|
||
<th style="width: 150px;">*检查类型</th>
|
||
<th style="width: 120px;">选择部位</th>
|
||
<th style="width: 150px;">*执行科室</th>
|
||
<th style="width: 100px;">序号</th>
|
||
<th style="width: 150px;">备注</th>
|
||
<th style="width: 120px;">操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr
|
||
v-for="(item, index) in tableData"
|
||
:key="index"
|
||
:class="{ 'editing-row': item.editing, 'child-row': item.row.includes('.') }"
|
||
>
|
||
<td>{{ item.row }}</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="text" placeholder="请输入编码" v-model="item.code">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.code }}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="text" placeholder="请输入名称" v-model="item.name">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.name }}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<select v-model="item.type" :class="{ 'placeholder-text': !item.type }">
|
||
<option value="">选择检查类型</option>
|
||
<option
|
||
v-for="dict in inspectionTypeDicts"
|
||
:key="dict.dictValue"
|
||
:value="dict.dictValue"
|
||
>
|
||
{{ dict.dictLabel }}
|
||
</option>
|
||
</select>
|
||
</template>
|
||
<template v-else>
|
||
<span v-if="item.type">{{ getInspectionTypeLabel(item.type) }}</span>
|
||
<span v-else class="placeholder-text">选择检查类型</span>
|
||
</template>
|
||
</td>
|
||
<td class="checkbox-container">
|
||
<input type="checkbox" v-model="item.selected" @click.stop>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<select v-model="item.department" :class="{ 'placeholder-text': !item.department }">
|
||
<option value="">选择执行科室</option>
|
||
<option
|
||
v-if="item.department"
|
||
:value="item.department"
|
||
>
|
||
{{ item.department }}
|
||
</option>
|
||
<option
|
||
v-for="dept in departments"
|
||
:key="dept.dictValue"
|
||
:value="dept.dictLabel"
|
||
>
|
||
{{ dept.dictLabel }}
|
||
</option>
|
||
</select>
|
||
</template>
|
||
<template v-else>
|
||
<span v-if="item.department">{{ item.department }}</span>
|
||
<span v-else class="placeholder-text">选择执行科室</span>
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="text" v-model="item.number">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.number }}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="text" placeholder="请输入备注" v-model="item.remark">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.remark || '' }}
|
||
</template>
|
||
</td>
|
||
<td class="actions">
|
||
<template v-if="item.editing">
|
||
<button class="btn btn-confirm" @click.stop="handleConfirm(index)" title="保存">
|
||
✓
|
||
</button>
|
||
<button class="btn btn-cancel" @click.stop="handleCancelEdit(index)" title="取消">
|
||
✕
|
||
</button>
|
||
<button
|
||
v-if="!item.row.includes('.')"
|
||
class="btn btn-add"
|
||
@click.stop="handleAdd(index)"
|
||
title="添加子项"
|
||
>
|
||
+
|
||
</button>
|
||
</template>
|
||
<template v-else>
|
||
<button class="btn btn-edit" @click.stop="handleEdit(index)" title="修改">
|
||
✏️
|
||
</button>
|
||
<button
|
||
v-if="!item.row.includes('.')"
|
||
class="btn btn-add"
|
||
@click.stop="handleAdd(index)"
|
||
title="添加子项"
|
||
>
|
||
+
|
||
</button>
|
||
<button class="btn btn-delete" @click.stop="handleDelete(index)" title="删除">
|
||
✕
|
||
</button>
|
||
</template>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- 检查方法的表格视图 -->
|
||
<template v-else-if="activeMenu === '检查方法'">
|
||
<div class="header">
|
||
<h1>{{ activeMenu }}管理</h1>
|
||
</div>
|
||
<div class="search-bar search-bar-method">
|
||
<div class="search-filters">
|
||
<div class="search-item">
|
||
<label>检查类型</label>
|
||
<el-select v-model="searchParamsMethod.checkType" placeholder="选择检查类型" style="width: 150px">
|
||
<el-option
|
||
v-for="dict in inspectionTypeDicts"
|
||
:key="dict.dictValue"
|
||
:label="dict.dictLabel"
|
||
:value="dict.dictValue"
|
||
>
|
||
</el-option>
|
||
</el-select>
|
||
</div>
|
||
<div class="search-item">
|
||
<label>名称</label>
|
||
<el-input placeholder="名称/编码" v-model="searchParamsMethod.name" />
|
||
</div>
|
||
<div class="search-item">
|
||
<label>费用套餐</label>
|
||
<el-select v-model="searchParamsMethod.packageName" placeholder="选择使用套餐" style="width: 150px">
|
||
<el-option
|
||
v-for="pkg in checkPackages"
|
||
:key="pkg.id"
|
||
:label="pkg.name"
|
||
:value="pkg.name"
|
||
>
|
||
</el-option>
|
||
</el-select>
|
||
</div>
|
||
</div>
|
||
<div class="search-actions">
|
||
<el-button type="primary" @mouseenter="hoverAddButton = true" @mouseleave="hoverAddButton = false" @click="handleAddNewRow">新增</el-button>
|
||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
||
<el-button type="primary" @click="handleReset">重置</el-button>
|
||
<el-button type="success" @click="handleExport">导出表格</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th style="width: 50px;">行</th>
|
||
<th style="width: 100px;">代码</th>
|
||
<th style="width: 150px;">名称</th>
|
||
<th style="width: 150px;">检查类型</th>
|
||
<th style="width: 150px;">套餐名称</th>
|
||
<th style="width: 100px;">曝光次数</th>
|
||
<th style="width: 100px;">序号</th>
|
||
<th style="width: 150px;">备注</th>
|
||
<th style="width: 120px;">操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr
|
||
v-for="(item, index) in checkMethodData"
|
||
:key="index"
|
||
:class="{ 'editing-row': item.editing }"
|
||
@click="handleEdit(index)"
|
||
>
|
||
<td>{{ item.row }}</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="text" placeholder="请输入编码" v-model="item.code">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.code }}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="text" placeholder="请输入方法名称" v-model="item.name">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.name }}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<select v-model="item.checkType">
|
||
<option value="">选择检查类型</option>
|
||
<option
|
||
v-for="dict in inspectionTypeDicts"
|
||
:key="dict.dictValue"
|
||
:value="dict.dictValue"
|
||
>
|
||
{{ dict.dictLabel }}
|
||
</option>
|
||
</select>
|
||
</template>
|
||
<template v-else>
|
||
{{ getInspectionTypeLabel(item.checkType) || '无' }}
|
||
</template>
|
||
</td>
|
||
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="text" placeholder="请输入套餐名称" v-model="item.packageName">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.packageName || '' }}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="text" v-model="item.exposureNum">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.exposureNum || 0}}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="text" v-model="item.orderNum">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.orderNum || '0' }}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="text" placeholder="请输入备注" v-model="item.remark">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.remark || '' }}
|
||
</template>
|
||
</td>
|
||
<td class="actions">
|
||
<template v-if="item.editing">
|
||
<button class="btn btn-confirm" @click.stop="handleConfirm(index)" title="保存">
|
||
✓
|
||
</button>
|
||
<button class="btn btn-cancel" @click.stop="handleCancelEdit(index)" title="取消">
|
||
✕
|
||
</button>
|
||
</template>
|
||
<template v-else>
|
||
<button class="btn btn-edit" @click.stop="handleEdit(index)" title="编辑">
|
||
✏️
|
||
</button>
|
||
<button class="btn btn-confirm" @click.stop="handleConfirm(index)" title="保存">
|
||
✓
|
||
</button>
|
||
<button class="btn btn-delete" @click.stop="handleDelete(index)" title="删除">
|
||
✕
|
||
</button>
|
||
</template>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- 检查部位的表格视图 -->
|
||
<template v-else-if="activeMenu === '检查部位'">
|
||
<div class="header">
|
||
<h1>{{ activeMenu }}管理</h1>
|
||
</div>
|
||
<div class="search-bar search-bar-part">
|
||
<div class="search-item">
|
||
<label>检查类型</label>
|
||
<el-select v-model="searchParamsPart.checkType" placeholder="选择检查类型" style="width: 150px">
|
||
<el-option
|
||
v-for="dict in inspectionTypeDicts"
|
||
:key="dict.dictValue"
|
||
:label="dict.dictLabel"
|
||
:value="dict.dictValue"
|
||
>
|
||
</el-option>
|
||
</el-select>
|
||
</div>
|
||
<div class="search-item">
|
||
<label>名称</label>
|
||
<el-input placeholder="名称/编码" v-model="searchParamsPart.name" />
|
||
</div>
|
||
<div class="search-item">
|
||
<label>费用套餐</label>
|
||
<el-input placeholder="费用套餐" v-model="searchParamsPart.packageName" />
|
||
</div>
|
||
|
||
<div class="search-actions">
|
||
<el-button type="primary" @click="handleAddNewRow">新增</el-button>
|
||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
||
<el-button type="primary" @click="handleReset">重置</el-button>
|
||
<el-button type="success" @click="handleExport">导出表格</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="table-container">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th style="width: 50px;">行</th>
|
||
<th style="width: 100px;">*编码</th>
|
||
<th style="width: 100px;">*名称</th>
|
||
<th style="width: 120px;">检查类型</th>
|
||
<th style="width: 80px;">曝光次数</th>
|
||
<th style="width: 120px;">费用套餐</th>
|
||
<th style="width: 80px;">金额</th>
|
||
<th style="width: 50px;">序号</th>
|
||
<th style="width: 120px;">服务范围</th>
|
||
<th style="width: 120px;">下级医技类型</th>
|
||
<th style="width: 150px;">备注</th>
|
||
<th style="width: 120px;">操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr
|
||
v-for="(item, index) in checkPartData"
|
||
:key="index"
|
||
:class="{ 'editing-row': item.editing }"
|
||
@click="handleEdit(index)"
|
||
>
|
||
<td>{{ item.row }}</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="text" placeholder="请输入编码" v-model="item.code">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.code }}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="text" placeholder="请输入名称" v-model="item.name">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.name }}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<select v-model="item.checkType">
|
||
<option value="">选择检查类型</option>
|
||
<option
|
||
v-for="dict in inspectionTypeDicts"
|
||
:key="dict.dictValue"
|
||
:value="dict.dictValue"
|
||
>
|
||
{{ dict.dictLabel }}
|
||
</option>
|
||
</select>
|
||
</template>
|
||
<template v-else>
|
||
{{ getInspectionTypeLabel(item.checkType) || '无' }}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="number" min="0" placeholder="请输入曝光次数" v-model="item.exposureNum">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.exposureNum || '0' }}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="text" placeholder="请输入费用套餐" v-model="item.packageName">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.packageName || '' }}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="number" step="0.01" min="0" placeholder="请输入金额" v-model="item.price">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.price || '0.00' }}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="number" min="0" placeholder="请输入序号" v-model="item.number">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.number || '999999' }}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<select v-model="item.serviceScope">
|
||
<option value="">选择服务范围</option>
|
||
<option
|
||
v-for="dict in serviceScopeDicts"
|
||
:key="dict.dictValue"
|
||
:value="dict.dictValue"
|
||
>
|
||
{{ dict.dictLabel }}
|
||
</option>
|
||
</select>
|
||
</template>
|
||
<template v-else>
|
||
{{ getServiceScopeLabel(item.serviceScope) || '' }}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="text" placeholder="请输入下级医技类型" v-model="item.subType">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.subType || '' }}
|
||
</template>
|
||
</td>
|
||
<td>
|
||
<template v-if="item.editing">
|
||
<input type="text" placeholder="请输入备注" v-model="item.remark">
|
||
</template>
|
||
<template v-else>
|
||
{{ item.remark || '' }}
|
||
</template>
|
||
</td>
|
||
<td class="actions">
|
||
<template v-if="item.editing">
|
||
<button class="btn btn-confirm" @click.stop="handleConfirm(index)" title="保存">
|
||
✓
|
||
</button>
|
||
<button class="btn btn-cancel" @click.stop="handleCancelEdit(index)" title="取消">
|
||
✕
|
||
</button>
|
||
</template>
|
||
<template v-else>
|
||
<button class="btn btn-edit" @click.stop="handleEdit(index)" title="编辑">
|
||
✏️
|
||
</button>
|
||
<button class="btn btn-confirm" @click.stop="handleConfirm(index)" title="保存">
|
||
✓
|
||
</button>
|
||
<button class="btn btn-delete" @click.stop="handleDelete(index)" title="删除">
|
||
✕
|
||
</button>
|
||
</template>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</template>
|
||
<!-- 分页区域 -->
|
||
<div class="pagination">
|
||
<button class="pagination-btn">‹</button>
|
||
<span>1</span>
|
||
<button class="pagination-btn">›</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import {computed, onMounted, reactive, ref} from 'vue';
|
||
import {ElMessage, ElMessageBox} from 'element-plus';
|
||
import {getDicts} from '@/api/system/dict/data';
|
||
import {
|
||
addCheckMethod,
|
||
addCheckPart,
|
||
addCheckType,
|
||
delCheckMethod,
|
||
delCheckPart,
|
||
delCheckType,
|
||
exportCheckMethod,
|
||
exportCheckPart,
|
||
listCheckMethod,
|
||
listCheckPackage,
|
||
listCheckPart,
|
||
listCheckType,
|
||
searchCheckMethod,
|
||
searchCheckPart,
|
||
updateCheckMethod,
|
||
updateCheckPart,
|
||
updateCheckType
|
||
} from '@/api/system/checkType';
|
||
import PackageSettings from './components/PackageSettings.vue';
|
||
import PackageManagement from './components/PackageManagement.vue';
|
||
|
||
// 菜单数据
|
||
const menus = ['检查类型', '检查方法', '检查部位', '套餐设置'];
|
||
const activeMenu = ref('检查类型');
|
||
|
||
// 套餐视图状态: management-套餐管理列表, settings-套餐设置
|
||
const packageView = ref('management')
|
||
// 套餐设置模式: add-新增, edit-编辑, view-查看
|
||
const packageMode = ref('add')
|
||
// 当前编辑的套餐数据
|
||
const currentPackageData = ref(null)
|
||
|
||
// 检查类型和科室选项
|
||
const checkTypes = ref([]);
|
||
// 完整的检查类型字典数据
|
||
const inspectionTypeDicts = ref([]);
|
||
// 完整的服务范围字典数据
|
||
const serviceScopeDicts = ref([]);
|
||
const checkMethods = ref([]);
|
||
|
||
// 根据字典值获取检查类型标签
|
||
const getInspectionTypeLabel = (value) => {
|
||
const dictItem = inspectionTypeDicts.value.find(item => item.dictValue === value);
|
||
return dictItem ? dictItem.dictLabel : value;
|
||
};
|
||
|
||
// 根据字典值获取服务范围标签
|
||
const getServiceScopeLabel = (value) => {
|
||
const dictItem = serviceScopeDicts.value.find(item => item.dictValue === value);
|
||
return dictItem ? dictItem.dictLabel : value;
|
||
};
|
||
const checkParts = ref([]);
|
||
const checkPackages = ref([]);
|
||
const departments = ref([]);
|
||
|
||
// 表格数据 - 为每个菜单创建独立的数据存储
|
||
const checkTypeData = reactive([]);
|
||
const checkMethodData = reactive([]);
|
||
const checkPartData = reactive([]);
|
||
const packageData = reactive([]);
|
||
|
||
// 当前显示的表格数据
|
||
const tableData = computed(() => {
|
||
switch(activeMenu.value) {
|
||
case '检查类型':
|
||
return checkTypeData;
|
||
case '检查方法':
|
||
return checkMethodData;
|
||
case '检查部位':
|
||
return checkPartData;
|
||
case '套餐设置':
|
||
return packageData;
|
||
default:
|
||
return [];
|
||
}
|
||
});
|
||
|
||
// 搜索条件 - 为每个菜单创建独立的搜索参数
|
||
const searchParamsType = reactive({});
|
||
const searchParamsMethod = reactive({
|
||
checkType: '',
|
||
name: '',
|
||
packageName: ''
|
||
});
|
||
const searchParamsPart = reactive({
|
||
checkType: '',
|
||
name: '',
|
||
packageName: ''
|
||
});
|
||
|
||
// 获取当前菜单对应的搜索参数
|
||
const currentSearchParams = computed(() => {
|
||
switch(activeMenu.value) {
|
||
case '检查类型':
|
||
return searchParamsType;
|
||
case '检查方法':
|
||
return searchParamsMethod;
|
||
case '检查部位':
|
||
return searchParamsPart;
|
||
case '套餐设置':
|
||
return searchParamsMethod; // 套餐设置可能共享检查方法的搜索参数
|
||
default:
|
||
return {};
|
||
}
|
||
});
|
||
|
||
// 按钮悬停状态
|
||
const hoverAddButton = ref(false);
|
||
|
||
// 从数据库获取所有检查相关数据
|
||
onMounted(async () => {
|
||
try {
|
||
// 获取科室字典数据
|
||
const deptResponse = await getDicts('dept');
|
||
if (deptResponse && deptResponse.data) {
|
||
// 保存完整的科室字典数据,包含编码和名称
|
||
departments.value = deptResponse.data;
|
||
}
|
||
|
||
// 获取检查类型数据(从数据字典获取)
|
||
const typeResponse = await getDicts('inspection_type');
|
||
if (typeResponse && typeResponse.data) {
|
||
// 保存完整的字典数据
|
||
inspectionTypeDicts.value = typeResponse.data;
|
||
// 从数据字典获取检查类型值
|
||
checkTypes.value = typeResponse.data.map(item => item.dictValue);
|
||
} else {
|
||
checkTypes.value = [];
|
||
inspectionTypeDicts.value = [];
|
||
}
|
||
|
||
// 获取服务范围数据(从数据字典获取)
|
||
const scopeResponse = await getDicts('scope_of_services');
|
||
if (scopeResponse && scopeResponse.data) {
|
||
// 保存完整的服务范围字典数据
|
||
serviceScopeDicts.value = scopeResponse.data;
|
||
} else {
|
||
serviceScopeDicts.value = [];
|
||
}
|
||
|
||
// 获取检查类型表格数据(仍然从API获取)
|
||
const typeTableResponse = await listCheckType();
|
||
if (typeTableResponse && typeTableResponse.data) {
|
||
// 构建检查类型表格数据
|
||
checkTypeData.splice(0, checkTypeData.length);
|
||
typeTableResponse.data.forEach((item, index) => {
|
||
checkTypeData.push({
|
||
id: item.id, // 保存id字段,用于判断是新增还是修改
|
||
row: (index + 1).toString(),
|
||
code: item.code,
|
||
name: item.name,
|
||
type: item.type,
|
||
selected: true,
|
||
department: item.department || '',
|
||
number: item.number || '999999',
|
||
remark: item.remark || '',
|
||
actions: true
|
||
});
|
||
});
|
||
}
|
||
|
||
// 获取检查方法数据
|
||
const methodResponse = await listCheckMethod();
|
||
if (methodResponse && methodResponse.data) {
|
||
// 确保data是数组类型
|
||
checkMethods.value = Array.isArray(methodResponse.data) ? methodResponse.data : [];
|
||
} else {
|
||
checkMethods.value = [];
|
||
}
|
||
|
||
// 获取检查部位数据
|
||
const partResponse = await listCheckPart();
|
||
if (partResponse && partResponse.data) {
|
||
// 确保data是数组类型
|
||
checkParts.value = Array.isArray(partResponse.data) ? partResponse.data : [];
|
||
} else {
|
||
checkParts.value = [];
|
||
}
|
||
|
||
// 获取检查套餐数据
|
||
const packageResponse = await listCheckPackage();
|
||
if (packageResponse && packageResponse.data) {
|
||
// 确保data是数组类型
|
||
checkPackages.value = Array.isArray(packageResponse.data) ? packageResponse.data : [];
|
||
} else {
|
||
checkPackages.value = [];
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('获取数据失败:', error);
|
||
// 如果API调用失败,显示友好提示
|
||
alert('获取检查类型数据失败,请检查网络或服务状态');
|
||
}
|
||
});
|
||
|
||
// 处理菜单点击
|
||
function handleMenuClick(menu) {
|
||
console.log('点击菜单:', menu);
|
||
console.log('当前activeMenu:', activeMenu.value);
|
||
|
||
activeMenu.value = menu;
|
||
|
||
console.log('更新后activeMenu:', activeMenu.value);
|
||
|
||
// 更新菜单激活状态
|
||
const menuItems = document.querySelectorAll('.menu-item');
|
||
menuItems.forEach(item => {
|
||
item.classList.remove('active');
|
||
if (item.textContent.trim() === menu) {
|
||
item.classList.add('active');
|
||
}
|
||
});
|
||
|
||
// 如果点击套餐设置,默认显示套餐设置界面
|
||
if (menu === '套餐设置') {
|
||
packageView.value = 'settings'
|
||
packageMode.value = 'add'
|
||
currentPackageData.value = null
|
||
console.log('显示套餐设置界面')
|
||
} else {
|
||
loadMenuData(menu);
|
||
}
|
||
}
|
||
|
||
// 从套餐设置切换到套餐管理界面
|
||
function handleSwitchToManagement() {
|
||
console.log('切换到套餐管理界面')
|
||
packageView.value = 'management'
|
||
}
|
||
|
||
// 从套餐管理切换到套餐设置界面(新增/编辑/查看)
|
||
function handleSwitchToSettings(params) {
|
||
console.log('切换到套餐设置界面:', params)
|
||
packageView.value = 'settings'
|
||
packageMode.value = params.mode
|
||
currentPackageData.value = params.data
|
||
}
|
||
|
||
// 保存成功后保持在套餐设置界面
|
||
function handleSaveSuccess() {
|
||
console.log('保存成功')
|
||
// 保存成功后保持在套餐设置界面,可以继续编辑或返回管理界面
|
||
ElMessage.success('保存成功')
|
||
}
|
||
|
||
// 根据菜单加载对应数据
|
||
async function loadMenuData(menu) {
|
||
try {
|
||
switch(menu) {
|
||
case '检查类型':
|
||
// 清空检查类型数据
|
||
checkTypeData.splice(0, checkTypeData.length);
|
||
|
||
const typeResponse = await listCheckType();
|
||
if (typeResponse && typeResponse.data) {
|
||
// 确保data是数组类型
|
||
const typeData = Array.isArray(typeResponse.data) ? typeResponse.data : [];
|
||
|
||
// 获取所有不重复的检查类型值
|
||
checkTypes.value = [...new Set(typeData.map(item => item.type))];
|
||
|
||
typeData.forEach((item, index) => {
|
||
// 直接使用数据库中的department值,不进行转换
|
||
checkTypeData.push({
|
||
id: item.id, // 保存id字段,用于判断是新增还是修改
|
||
row: (index + 1).toString(),
|
||
code: item.code,
|
||
name: item.name,
|
||
type: item.type,
|
||
selected: true,
|
||
department: item.department || '',
|
||
number: item.number || '999999',
|
||
remark: item.remark || '',
|
||
actions: true
|
||
});
|
||
});
|
||
}
|
||
break;
|
||
|
||
case '检查方法':
|
||
// 清空检查方法数据
|
||
checkMethodData.splice(0, checkMethodData.length);
|
||
|
||
// 构建检查方法的搜索参数
|
||
const methodParams = {
|
||
pageNo: 1,
|
||
pageSize: 100, // 默认获取100条数据,可以根据需要调整
|
||
checkType: searchParamsMethod.checkType,
|
||
name: searchParamsMethod.name,
|
||
packageName: searchParamsMethod.packageName
|
||
};
|
||
try {
|
||
const methodResponse = await searchCheckMethod(methodParams);
|
||
|
||
// 确保data是数组,适配不同的后端返回格式
|
||
let methodData = [];
|
||
if (methodResponse) {
|
||
if (Array.isArray(methodResponse)) {
|
||
methodData = methodResponse;
|
||
} else if (methodResponse.data && Array.isArray(methodResponse.data)) {
|
||
methodData = methodResponse.data;
|
||
} else if (methodResponse.data && methodResponse.data.data && Array.isArray(methodResponse.data.data)) {
|
||
methodData = methodResponse.data.data;
|
||
} else if (methodResponse.data && methodResponse.data.records) {
|
||
methodData = methodResponse.data.records;
|
||
}
|
||
}
|
||
|
||
// 处理数组数据
|
||
if (methodData.length > 0) {
|
||
methodData.forEach((item, index) => {
|
||
checkMethodData.push({
|
||
id: item.id, // 保存id字段,用于判断是新增还是修改
|
||
row: (index + 1).toString(),
|
||
code: item.code,
|
||
name: item.name,
|
||
checkType: item.checkType || '',
|
||
packageName: item.packageName || '',
|
||
exposureNum: item.exposureNum || 0,
|
||
orderNum: item.orderNum || 0,
|
||
remark: item.remark || '',
|
||
actions: true
|
||
});
|
||
});
|
||
} else {
|
||
ElMessage.warning('未获取到检查方法数据');
|
||
}
|
||
} catch (error) {
|
||
ElMessage.error(`加载检查方法数据失败: ${error.message || '未知错误'}`);
|
||
}
|
||
break;
|
||
|
||
case '检查部位':
|
||
// 清空检查部位数据
|
||
checkPartData.splice(0, checkPartData.length);
|
||
|
||
// 构建检查部位的搜索参数
|
||
const partParams = {
|
||
pageNo: 1,
|
||
pageSize: 100, // 默认获取100条数据,可以根据需要调整
|
||
checkType: searchParamsPart.checkType,
|
||
name: searchParamsPart.name,
|
||
packageName: searchParamsPart.packageName
|
||
};
|
||
try {
|
||
const partResponse = await searchCheckPart(partParams);
|
||
|
||
// 确保data是数组,适配不同的后端返回格式
|
||
let partData = [];
|
||
if (partResponse) {
|
||
if (Array.isArray(partResponse)) {
|
||
partData = partResponse;
|
||
} else if (partResponse.data && Array.isArray(partResponse.data)) {
|
||
partData = partResponse.data;
|
||
} else if (partResponse.data && partResponse.data.data && Array.isArray(partResponse.data.data)) {
|
||
partData = partResponse.data.data;
|
||
} else if (partResponse.data && partResponse.data.records) {
|
||
partData = partResponse.data.records;
|
||
}
|
||
}
|
||
|
||
// 处理数组数据
|
||
if (partData.length > 0) {
|
||
partData.forEach((item, index) => {
|
||
checkPartData.push({
|
||
id: item.id, // 保存id字段,用于判断是新增还是修改
|
||
row: (index + 1).toString(),
|
||
code: item.code,
|
||
name: item.name,
|
||
checkType: item.checkType || '',
|
||
exposureNum: item.exposureNum || 0,
|
||
packageName: item.packageName || '',
|
||
price: item.price || 0,
|
||
number: item.number || '999999',
|
||
serviceScope: item.serviceScope || '',
|
||
subType: item.subType || '',
|
||
remark: item.remark || '',
|
||
actions: true
|
||
});
|
||
});
|
||
} else {
|
||
ElMessage.warning('未获取到检查部位数据');
|
||
}
|
||
} catch (error) {
|
||
ElMessage.error(`加载检查部位数据失败: ${error.message || '未知错误'}`);
|
||
}
|
||
break;
|
||
|
||
case '套餐设置':
|
||
const packageResponse = await listCheckPackage();
|
||
if (packageResponse && packageResponse.data) {
|
||
}
|
||
break;
|
||
}
|
||
} catch (error) {
|
||
console.error('加载菜单数据失败:', error);
|
||
ElMessage.error(`加载${menu}数据失败,请检查网络或服务状态`);
|
||
}
|
||
}
|
||
|
||
// 处理编辑按钮点击
|
||
function handleEdit(index) {
|
||
const item = tableData.value[index];
|
||
item.editing = true;
|
||
}
|
||
|
||
// 处理取消编辑按钮点击
|
||
function handleCancelEdit(index) {
|
||
const item = tableData.value[index];
|
||
item.editing = false;
|
||
}
|
||
|
||
// 处理确认按钮点击
|
||
async function handleConfirm(index) {
|
||
const item = tableData.value[index];
|
||
try {
|
||
// 根据当前激活的菜单调用不同的API
|
||
if (activeMenu.value === '检查方法') {
|
||
// 检查方法的保存逻辑
|
||
if (item.id) {
|
||
// 修改操作:只传递必要字段
|
||
const updateData = {
|
||
id: item.id,
|
||
code: item.code,
|
||
name: item.name,
|
||
checkType: item.checkType,
|
||
packageName: item.packageName,
|
||
exposureNum: item.exposureNum,
|
||
orderNum: item.orderNum,
|
||
remark: item.remark
|
||
};
|
||
await updateCheckMethod(updateData);
|
||
} else {
|
||
// 新增操作:只传递必要字段
|
||
const addData = {
|
||
code: item.code,
|
||
name: item.name,
|
||
checkType: item.checkType,
|
||
packageName: item.packageName,
|
||
exposureNum: item.exposureNum,
|
||
orderNum: item.orderNum,
|
||
remark: item.remark
|
||
};
|
||
console.log('准备新增检查方法:', addData);
|
||
const newItem = await addCheckMethod(addData);
|
||
console.log('新增检查方法返回结果:', newItem);
|
||
// 将新增的id赋值给本地数据
|
||
item.id = newItem.id;
|
||
}
|
||
} else if (activeMenu.value === '检查部位') {
|
||
// 检查部位的保存逻辑
|
||
if (item.id) {
|
||
// 修改操作:只传递必要字段
|
||
const updateData = {
|
||
id: item.id,
|
||
code: item.code,
|
||
name: item.name,
|
||
checkType: item.checkType,
|
||
exposureNum: item.exposureNum,
|
||
packageName: item.packageName,
|
||
price: item.price,
|
||
number: item.number,
|
||
serviceScope: item.serviceScope,
|
||
subType: item.subType,
|
||
remark: item.remark
|
||
};
|
||
await updateCheckPart(updateData);
|
||
} else {
|
||
// 新增操作:只传递必要字段
|
||
const addData = {
|
||
code: item.code,
|
||
name: item.name,
|
||
checkType: item.checkType,
|
||
exposureNum: item.exposureNum,
|
||
packageName: item.packageName,
|
||
price: item.price,
|
||
number: item.number,
|
||
serviceScope: item.serviceScope,
|
||
subType: item.subType,
|
||
remark: item.remark
|
||
};
|
||
console.log('准备新增检查部位:', addData);
|
||
const newItem = await addCheckPart(addData);
|
||
console.log('新增检查部位返回结果:', newItem);
|
||
// 将新增的id赋值给本地数据
|
||
item.id = newItem.id;
|
||
}
|
||
} else {
|
||
// 检查类型的保存逻辑
|
||
if (item.id) {
|
||
// 修改操作:只传递必要字段
|
||
const updateData = {
|
||
id: item.id,
|
||
code: item.code,
|
||
name: item.name,
|
||
type: item.type,
|
||
selected: item.selected,
|
||
department: item.department,
|
||
number: item.number,
|
||
remark: item.remark
|
||
};
|
||
await updateCheckType(updateData);
|
||
} else {
|
||
// 新增操作:只传递必要字段
|
||
const addData = {
|
||
code: item.code,
|
||
name: item.name,
|
||
type: item.type,
|
||
selected: item.selected,
|
||
department: item.department,
|
||
number: item.number,
|
||
remark: item.remark
|
||
};
|
||
console.log('准备新增检查类型:', addData);
|
||
const newItem = await addCheckType(addData);
|
||
console.log('新增检查类型返回结果:', newItem);
|
||
// 将新增的id赋值给本地数据
|
||
item.id = newItem.id;
|
||
}
|
||
}
|
||
// 退出编辑状态
|
||
tableData.value[index].editing = false;
|
||
// 显示保存成功提示
|
||
ElMessage.success(`第 ${item.row} 行数据已保存`);
|
||
} catch (error) {
|
||
console.error('保存失败,错误信息:', error);
|
||
console.error('保存失败,错误详情:', error.response ? error.response.data : error);
|
||
ElMessage.error('保存失败,请稍后重试');
|
||
}
|
||
}
|
||
|
||
// 处理删除按钮点击
|
||
async function handleDelete(index) {
|
||
ElMessageBox.confirm('确定要删除这一行吗?', '系统提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(async () => {
|
||
const item = tableData.value[index];
|
||
try {
|
||
// 如果有id,调用API删除数据库中的数据
|
||
if (item.id) {
|
||
if (activeMenu.value === '检查方法') {
|
||
await delCheckMethod(item.id);
|
||
} else if (activeMenu.value === '检查部位') {
|
||
await delCheckPart(item.id);
|
||
} else {
|
||
await delCheckType(item.id);
|
||
}
|
||
}
|
||
// 从数组中删除该行数据
|
||
tableData.value.splice(index, 1);
|
||
ElMessage.success('删除成功!');
|
||
} catch (error) {
|
||
ElMessage.error('删除失败,请稍后重试');
|
||
}
|
||
}).catch(() => {
|
||
// 用户取消删除操作
|
||
});
|
||
}
|
||
|
||
// 处理添加新行按钮点击
|
||
function handleAddNewRow() {
|
||
// 获取当前最大行号,为新建行生成行号
|
||
const maxRowNum = Math.max(
|
||
0,
|
||
...tableData.value.map(item => {
|
||
// 处理子行编号,如"1.1"只取主行号"1"
|
||
const rowParts = item.row.split('.');
|
||
return parseInt(rowParts[0]) || 0;
|
||
})
|
||
);
|
||
|
||
let newRow;
|
||
|
||
// 根据当前激活的菜单生成不同的初始数据结构
|
||
if (activeMenu.value === '检查类型') {
|
||
newRow = {
|
||
row: String(maxRowNum + 1),
|
||
code: '',
|
||
name: '',
|
||
type: '',
|
||
selected: true,
|
||
department: '',
|
||
number: '999999',
|
||
remark: '',
|
||
editing: true, // 新行默认进入编辑状态
|
||
isNew: true, // 标记为新增行
|
||
actions: true
|
||
};
|
||
} else if (activeMenu.value === '检查方法') {
|
||
newRow = {
|
||
row: String(maxRowNum + 1),
|
||
code: '',
|
||
name: '',
|
||
checkType: '',
|
||
packageName: '',
|
||
exposureNum: 0,
|
||
orderNum: 0,
|
||
remark: '',
|
||
editing: true, // 新行默认进入编辑状态
|
||
isNew: true, // 标记为新增行
|
||
actions: true
|
||
};
|
||
} else if (activeMenu.value === '检查部位') {
|
||
newRow = {
|
||
row: String(maxRowNum + 1),
|
||
code: '',
|
||
name: '',
|
||
checkType: '',
|
||
exposureNum: 0,
|
||
packageName: '',
|
||
price: 0,
|
||
number: '999999',
|
||
serviceScope: '',
|
||
subType: '',
|
||
remark: '',
|
||
editing: true, // 新行默认进入编辑状态
|
||
isNew: true, // 标记为新增行
|
||
actions: true
|
||
};
|
||
} else {
|
||
// 默认数据结构
|
||
newRow = {
|
||
row: String(maxRowNum + 1),
|
||
code: '',
|
||
name: '',
|
||
type: '',
|
||
selected: true,
|
||
department: '',
|
||
number: '999999',
|
||
remark: '',
|
||
editing: true, // 新行默认进入编辑状态
|
||
isNew: true, // 标记为新增行
|
||
actions: true
|
||
};
|
||
}
|
||
|
||
tableData.value.push(newRow);
|
||
}
|
||
|
||
// 处理添加按钮点击
|
||
function handleAdd(index) {
|
||
const parentRow = tableData.value[index];
|
||
|
||
// 创建子行数据,继承父行的编码
|
||
const childRow = {
|
||
row: parentRow.row + '.1', // 子行编号
|
||
code: parentRow.code, // 继承父行编码
|
||
name: '',
|
||
type: '',
|
||
selected: false,
|
||
department: '',
|
||
number: '',
|
||
remark: '',
|
||
editing: true,
|
||
actions: false
|
||
};
|
||
|
||
// 在父行后插入子行
|
||
tableData.value.splice(index + 1, 0, childRow);
|
||
}
|
||
|
||
// 处理搜索功能
|
||
async function handleSearch() {
|
||
try {
|
||
console.log('搜索条件:', currentSearchParams.value);
|
||
// ElMessage.info(`正在搜索${activeMenu.value}数据...`);
|
||
|
||
switch(activeMenu.value) {
|
||
case '检查方法':
|
||
// 清空检查方法数据
|
||
checkMethodData.splice(0, checkMethodData.length);
|
||
|
||
// 构建检查方法的搜索参数
|
||
const methodParams = {
|
||
pageNo: 1,
|
||
pageSize: 100, // 默认获取100条数据,可以根据需要调整
|
||
checkType: searchParamsMethod.checkType,
|
||
name: searchParamsMethod.name,
|
||
packageName: searchParamsMethod.packageName
|
||
};
|
||
|
||
const methodResponse = await searchCheckMethod(methodParams);
|
||
|
||
// 确保data是数组,适配不同的后端返回格式
|
||
let methodData = [];
|
||
if (methodResponse) {
|
||
if (Array.isArray(methodResponse)) {
|
||
methodData = methodResponse;
|
||
} else if (methodResponse.data && Array.isArray(methodResponse.data)) {
|
||
methodData = methodResponse.data;
|
||
} else if (methodResponse.data && methodResponse.data.data && Array.isArray(methodResponse.data.data)) {
|
||
methodData = methodResponse.data.data;
|
||
} else if (methodResponse.data && methodResponse.data.records) {
|
||
methodData = methodResponse.data.records;
|
||
}
|
||
}
|
||
|
||
// 处理数组数据
|
||
if (methodData.length > 0) {
|
||
methodData.forEach((item, index) => {
|
||
checkMethodData.push({
|
||
id: item.id, // 保存id字段,用于判断是新增还是修改
|
||
row: (index + 1).toString(),
|
||
code: item.code,
|
||
name: item.name,
|
||
checkType: item.checkType || '',
|
||
packageName: item.packageName || '',
|
||
exposureNum: item.exposureNum || 0,
|
||
orderNum: item.orderNum || 0,
|
||
remark: item.remark || '',
|
||
actions: true
|
||
});
|
||
});
|
||
ElMessage.success(`搜索到${methodData.length}条检查方法数据`);
|
||
} else {
|
||
ElMessage.warning('未搜索到检查方法数据');
|
||
}
|
||
break;
|
||
|
||
case '检查部位':
|
||
// 清空检查部位数据
|
||
checkPartData.splice(0, checkPartData.length);
|
||
|
||
// 构建检查部位的搜索参数
|
||
const partParams = {
|
||
pageNo: 1,
|
||
pageSize: 100, // 默认获取100条数据,可以根据需要调整
|
||
checkType: searchParamsPart.checkType,
|
||
name: searchParamsPart.name,
|
||
packageName: searchParamsPart.packageName
|
||
};
|
||
|
||
const partResponse = await searchCheckPart(partParams);
|
||
|
||
// 确保data是数组,适配不同的后端返回格式
|
||
let partData = [];
|
||
if (partResponse) {
|
||
if (Array.isArray(partResponse)) {
|
||
partData = partResponse;
|
||
} else if (partResponse.data && Array.isArray(partResponse.data)) {
|
||
partData = partResponse.data;
|
||
} else if (partResponse.data && partResponse.data.data && Array.isArray(partResponse.data.data)) {
|
||
partData = partResponse.data.data;
|
||
} else if (partResponse.data && partResponse.data.records) {
|
||
partData = partResponse.data.records;
|
||
}
|
||
}
|
||
|
||
// 处理数组数据
|
||
if (partData.length > 0) {
|
||
partData.forEach((item, index) => {
|
||
checkPartData.push({
|
||
id: item.id, // 保存id字段,用于判断是新增还是修改
|
||
row: (index + 1).toString(),
|
||
code: item.code,
|
||
name: item.name,
|
||
checkType: item.checkType || '',
|
||
exposureNum: item.exposureNum || 0,
|
||
packageName: item.packageName || '',
|
||
price: item.price || 0,
|
||
number: item.number || '999999',
|
||
serviceScope: item.serviceScope || '',
|
||
subType: item.subType || '',
|
||
remark: item.remark || '',
|
||
actions: true
|
||
});
|
||
});
|
||
ElMessage.success(`搜索到${partData.length}条检查部位数据`);
|
||
} else {
|
||
ElMessage.warning('未搜索到检查部位数据');
|
||
}
|
||
break;
|
||
|
||
default:
|
||
// 其他菜单使用原有的加载逻辑
|
||
await loadMenuData(activeMenu.value);
|
||
break;
|
||
}
|
||
} catch (error) {
|
||
console.error('搜索失败:', error);
|
||
ElMessage.error(`搜索${activeMenu.value}数据失败: ${error.message || '未知错误'}`);
|
||
}
|
||
}
|
||
|
||
// 处理重置功能
|
||
function handleReset() {
|
||
// 根据当前活动菜单重置对应的搜索条件
|
||
switch(activeMenu.value) {
|
||
case '检查类型':
|
||
for (const key in searchParamsType) {
|
||
searchParamsType[key] = '';
|
||
}
|
||
break;
|
||
|
||
case '检查方法':
|
||
searchParamsMethod.checkType = '';
|
||
searchParamsMethod.name = '';
|
||
searchParamsMethod.packageName = '';
|
||
break;
|
||
|
||
case '检查部位':
|
||
searchParamsPart.checkType = '';
|
||
searchParamsPart.name = '';
|
||
searchParamsPart.packageName = '';
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
ElMessage.info('搜索条件已重置');
|
||
}
|
||
|
||
// 处理导出表格功能
|
||
function handleExport() {
|
||
console.log('导出表格:', activeMenu.value);
|
||
|
||
if (activeMenu.value === '检查方法') {
|
||
// 调用检查方法导出API
|
||
exportCheckMethod(searchParamsMethod).then(blobData => {
|
||
// 直接使用blobData创建下载链接,因为response拦截器已经返回了res.data
|
||
const blob = new Blob([blobData], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
||
const url = window.URL.createObjectURL(blob);
|
||
const link = document.createElement('a');
|
||
link.href = url;
|
||
// 设置文件名
|
||
link.setAttribute('download', `检查方法数据_${new Date().toISOString().slice(0, 10)}.xlsx`);
|
||
document.body.appendChild(link);
|
||
link.click();
|
||
// 清理
|
||
document.body.removeChild(link);
|
||
window.URL.revokeObjectURL(url);
|
||
ElMessage.success('检查方法数据导出成功');
|
||
}).catch(error => {
|
||
console.error('导出检查方法数据失败:', error);
|
||
ElMessage.error('导出检查方法数据失败');
|
||
});
|
||
} else if (activeMenu.value === '检查部位') {
|
||
// 调用检查部位导出API
|
||
exportCheckPart(searchParamsPart).then(blobData => {
|
||
// 直接使用blobData创建下载链接,因为response拦截器已经返回了res.data
|
||
const blob = new Blob([blobData], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
||
const url = window.URL.createObjectURL(blob);
|
||
const link = document.createElement('a');
|
||
link.href = url;
|
||
// 设置文件名
|
||
link.setAttribute('download', `检查部位数据_${new Date().toISOString().slice(0, 10)}.xlsx`);
|
||
document.body.appendChild(link);
|
||
link.click();
|
||
// 清理
|
||
document.body.removeChild(link);
|
||
window.URL.revokeObjectURL(url);
|
||
ElMessage.success('检查部位数据导出成功');
|
||
}).catch(error => {
|
||
console.error('导出检查部位数据失败:', error);
|
||
ElMessage.error('导出检查部位数据失败');
|
||
});
|
||
} else {
|
||
// 其他菜单的导出逻辑可以在这里扩展
|
||
ElMessage.warning('该功能尚未实现');
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
select {
|
||
appearance: none;
|
||
-webkit-appearance: none;
|
||
-moz-appearance: none;
|
||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
|
||
background-repeat: no-repeat;
|
||
background-position: right 8px center;
|
||
background-size: 14px;
|
||
padding-right: 28px;
|
||
}
|
||
|
||
.check-project-settings {
|
||
display: flex;
|
||
min-height: 100vh;
|
||
background-color: #f5f7fa;
|
||
color: #000000;
|
||
}
|
||
|
||
/* 左侧导航栏样式 */
|
||
.sidebar {
|
||
width: 200px;
|
||
background: linear-gradient(180deg, #f8f9fa 0%, #ffffff 100%);
|
||
height: 100%;
|
||
position: relative;
|
||
padding: 24px 0;
|
||
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.08);
|
||
overflow-y: auto;
|
||
flex-shrink: 0;
|
||
border-right: 1px solid #e8e8e8;
|
||
}
|
||
|
||
.sidebar-header {
|
||
padding: 0 20px 20px 20px;
|
||
margin-bottom: 12px;
|
||
border-bottom: 2px solid #1890FF;
|
||
}
|
||
|
||
.sidebar-header h3 {
|
||
margin: 0;
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
color: #1890FF;
|
||
letter-spacing: 0.5px;
|
||
}
|
||
|
||
.sidebar-menu {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
padding: 0 12px;
|
||
}
|
||
|
||
.menu-item {
|
||
display: flex;
|
||
align-items: center;
|
||
width: 100%;
|
||
padding: 14px 16px;
|
||
margin-bottom: 0;
|
||
background-color: transparent;
|
||
color: #333333;
|
||
border-radius: 8px;
|
||
text-decoration: none;
|
||
font-size: 15px;
|
||
font-weight: 500;
|
||
line-height: 1;
|
||
border: 1px solid transparent;
|
||
cursor: pointer;
|
||
text-align: left;
|
||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
position: relative;
|
||
}
|
||
|
||
.menu-item::before {
|
||
content: '';
|
||
position: absolute;
|
||
left: 0;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
width: 4px;
|
||
height: 0;
|
||
background: linear-gradient(180deg, #1890FF 0%, #40a9ff 100%);
|
||
border-radius: 0 4px 4px 0;
|
||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
}
|
||
|
||
.menu-item:hover {
|
||
background-color: rgba(24, 144, 255, 0.08);
|
||
border-color: rgba(24, 144, 255, 0.2);
|
||
transform: translateX(4px);
|
||
}
|
||
|
||
.menu-item:hover::before {
|
||
height: 20px;
|
||
}
|
||
|
||
.menu-item.active {
|
||
background: linear-gradient(135deg, #1890FF 0%, #40a9ff 100%);
|
||
color: #FFFFFF;
|
||
border-color: #1890FF;
|
||
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.3);
|
||
}
|
||
|
||
.menu-item.active::before {
|
||
height: 24px;
|
||
}
|
||
|
||
.menu-icon {
|
||
font-size: 18px;
|
||
margin-right: 12px;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 24px;
|
||
height: 24px;
|
||
transition: transform 0.3s ease;
|
||
}
|
||
|
||
.menu-item:hover .menu-icon {
|
||
transform: scale(1.1);
|
||
}
|
||
|
||
.menu-text {
|
||
flex: 1;
|
||
letter-spacing: 0.3px;
|
||
}
|
||
|
||
/* 主内容区样式 */
|
||
.content {
|
||
flex: 1;
|
||
padding: 32px 32px 32px 32px;
|
||
min-width: 0;
|
||
overflow-x: auto;
|
||
overflow-y: auto;
|
||
background-color: #f8f9fa;
|
||
}
|
||
|
||
.header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 24px;
|
||
padding: 20px 24px;
|
||
background: #ffffff;
|
||
border-radius: 12px;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
|
||
border: 1px solid #e8e8e8;
|
||
}
|
||
|
||
.header h1 {
|
||
font-size: 22px;
|
||
font-weight: 600;
|
||
color: #1890FF;
|
||
margin: 0;
|
||
letter-spacing: 0.5px;
|
||
}
|
||
|
||
/* 搜索栏样式 */
|
||
.search-bar {
|
||
background-color: #FFFFFF;
|
||
padding: 20px 24px;
|
||
border-radius: 12px;
|
||
margin-bottom: 20px;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
|
||
border: 1px solid #e8e8e8;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16px;
|
||
}
|
||
|
||
/* 检查方法搜索栏特定样式 */
|
||
.search-bar-method {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16px;
|
||
}
|
||
|
||
.search-bar-method .search-filters {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16px;
|
||
width: 100%;
|
||
}
|
||
|
||
.search-bar-method .search-actions {
|
||
margin-left: auto;
|
||
display: flex;
|
||
gap: 8px;
|
||
}
|
||
|
||
.search-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.search-item label {
|
||
font-size: 14px;
|
||
color: #000000;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.search-item select,
|
||
.search-item input {
|
||
width: 150px;
|
||
height: 32px;
|
||
padding: 0 8px;
|
||
border: 1px solid #D9D9D9;
|
||
border-radius: 4px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.search-actions {
|
||
margin-left: auto;
|
||
display: flex;
|
||
gap: 8px;
|
||
}
|
||
|
||
.search-actions .btn {
|
||
width: auto;
|
||
height: 32px;
|
||
padding: 0 16px;
|
||
border-radius: 4px;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
border: none;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.btn-purple {
|
||
background-color: #722ED1;
|
||
color: white;
|
||
}
|
||
|
||
.btn-blue {
|
||
background-color: #1890FF;
|
||
color: white;
|
||
}
|
||
|
||
.btn-default {
|
||
background-color: #FFFFFF;
|
||
color: #000000;
|
||
border: 1px solid #D9D9D9;
|
||
}
|
||
|
||
.btn-green {
|
||
background-color: #52C41A;
|
||
color: white;
|
||
}
|
||
|
||
.search-actions .btn:hover {
|
||
opacity: 0.85;
|
||
}
|
||
|
||
.header-actions {
|
||
display: flex;
|
||
gap: 10px;
|
||
}
|
||
|
||
.btn-add-new {
|
||
background-color: #409eff;
|
||
color: white;
|
||
border: none;
|
||
padding: 8px 16px;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
transition: background-color 0.3s;
|
||
}
|
||
|
||
.btn-add-new:hover {
|
||
background-color: #66b1ff;
|
||
}
|
||
|
||
/* 表格样式 */
|
||
.table-container {
|
||
width: 100%;
|
||
overflow-x: auto;
|
||
background: #FFFFFF;
|
||
border-radius: 12px;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
|
||
border: 1px solid #e8e8e8;
|
||
}
|
||
|
||
table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
border-spacing: 0;
|
||
table-layout: fixed;
|
||
min-width: 1200px;
|
||
}
|
||
|
||
th {
|
||
background: linear-gradient(180deg, #f8f9fa 0%, #fafbfc 100%);
|
||
height: 48px;
|
||
padding: 12px 16px;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
line-height: 24px;
|
||
text-align: center;
|
||
border-bottom: 2px solid #e8e8e8;
|
||
color: #1890FF;
|
||
letter-spacing: 0.3px;
|
||
}
|
||
|
||
td {
|
||
padding: 8px 16px;
|
||
height: 40px;
|
||
font-size: 14px;
|
||
font-weight: 400;
|
||
line-height: 24px;
|
||
border-bottom: 1px solid #e8e8e8;
|
||
text-align: center;
|
||
}
|
||
|
||
/* 操作按钮样式 */
|
||
.actions {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
position: relative;
|
||
z-index: 10;
|
||
}
|
||
|
||
.btn {
|
||
width: 30px;
|
||
height: 30px;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
border: none;
|
||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
position: relative;
|
||
z-index: 10;
|
||
color: white;
|
||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
|
||
}
|
||
|
||
.btn:hover {
|
||
transform: translateY(-2px) scale(1.1);
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
|
||
}
|
||
|
||
.btn:active {
|
||
transform: translateY(0) scale(0.95);
|
||
}
|
||
|
||
.btn-confirm {
|
||
background: linear-gradient(135deg, #52C41A 0%, #73d13d 100%);
|
||
}
|
||
|
||
.btn-confirm:hover {
|
||
background: linear-gradient(135deg, #389E0D 0%, #52C41A 100%);
|
||
}
|
||
|
||
.btn-edit {
|
||
background: linear-gradient(135deg, #1890FF 0%, #40a9ff 100%);
|
||
}
|
||
|
||
.btn-edit:hover {
|
||
background: linear-gradient(135deg, #096DD9 0%, #1890FF 100%);
|
||
}
|
||
|
||
.btn-add {
|
||
background: linear-gradient(135deg, #1890FF 0%, #40a9ff 100%);
|
||
}
|
||
|
||
.btn-add:hover {
|
||
background: linear-gradient(135deg, #096DD9 0%, #1890FF 100%);
|
||
}
|
||
|
||
.btn-cancel {
|
||
background: linear-gradient(135deg, #FA8C16 0%, #ffa940 100%);
|
||
}
|
||
|
||
.btn-cancel:hover {
|
||
background: linear-gradient(135deg, #D46B08 0%, #FA8C16 100%);
|
||
}
|
||
|
||
.btn-delete {
|
||
background: linear-gradient(135deg, #FF4D4F 0%, #ff7875 100%);
|
||
z-index: 20;
|
||
pointer-events: auto;
|
||
}
|
||
|
||
.btn-delete:hover {
|
||
background: linear-gradient(135deg, #CF1322 0%, #FF4D4F 100%);
|
||
}
|
||
|
||
/* 特殊状态样式 */
|
||
.editing-row {
|
||
background-color: #E6F7FF;
|
||
cursor: text;
|
||
}
|
||
|
||
tr:not(.editing-row):hover {
|
||
background-color: rgba(24, 144, 255, 0.05);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.child-row {
|
||
background-color: #f9f9f9;
|
||
}
|
||
|
||
.child-row td:first-child {
|
||
padding-left: 32px;
|
||
}
|
||
|
||
.checkbox-container {
|
||
display: flex;
|
||
justify-content: center;
|
||
}
|
||
|
||
input[type="checkbox"] {
|
||
width: 16px;
|
||
height: 16px;
|
||
}
|
||
|
||
input[type="text"], select {
|
||
height: 30px;
|
||
padding: 0 8px;
|
||
width: 100%;
|
||
border: 1px solid #D9D9D9;
|
||
border-radius: 4px;
|
||
font-size: 14px;
|
||
background-color: white;
|
||
color: #333;
|
||
}
|
||
|
||
input[type="text"]::placeholder {
|
||
color: #C0C4CC;
|
||
}
|
||
|
||
/* 分页样式 */
|
||
.pagination {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
align-items: center;
|
||
padding: 16px 0;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.pagination span {
|
||
font-size: 14px;
|
||
margin: 0 16px;
|
||
}
|
||
|
||
.pagination-btn {
|
||
background: none;
|
||
border: 1px solid #D9D9D9;
|
||
border-radius: 4px;
|
||
width: 32px;
|
||
height: 32px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.pagination-btn:hover {
|
||
border-color: #1890FF;
|
||
color: #1890FF;
|
||
}
|
||
|
||
/* 禁用状态样式 */
|
||
.placeholder-text {
|
||
color: #C0C4CC;
|
||
}
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 768px) {
|
||
.sidebar {
|
||
width: 70px;
|
||
padding: 16px 8px;
|
||
}
|
||
|
||
.sidebar-header {
|
||
padding: 0 8px 16px 8px;
|
||
}
|
||
|
||
.sidebar-header h3 {
|
||
font-size: 14px;
|
||
text-align: center;
|
||
}
|
||
|
||
.menu-text {
|
||
display: none;
|
||
}
|
||
|
||
.menu-icon {
|
||
margin-right: 0;
|
||
}
|
||
|
||
.menu-item {
|
||
justify-content: center;
|
||
padding: 12px;
|
||
}
|
||
|
||
.content {
|
||
padding: 20px 16px;
|
||
}
|
||
}
|
||
|
||
/* 平板适配 */
|
||
@media (min-width: 769px) and (max-width: 1024px) {
|
||
.sidebar {
|
||
width: 160px;
|
||
}
|
||
|
||
.content {
|
||
padding: 24px 20px;
|
||
}
|
||
}
|
||
</style> |