提交
This commit is contained in:
1 parent
e6072457fd
commit
be4fab78e1
578 files changed
+174415
-214
No files matched your search
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">细胞样本类型列表</h2>
|
||||
<h2>细胞样本类型列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
@@ -34,12 +34,11 @@
|
||||
<div class="list-toolbar-selected">
|
||||
已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
|
||||
</div>
|
||||
<el-button v-if="hasAuth('add')" class="btn-main" type="primary" @click="handleAdd">
|
||||
<el-button class="btn-main" type="primary" @click="handleAdd">
|
||||
<el-icon><Plus /></el-icon>
|
||||
新增类型
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="hasAuth('delete')"
|
||||
class="btn-ghost"
|
||||
type="danger"
|
||||
:disabled="selectedRows.length === 0"
|
||||
@@ -117,8 +116,8 @@
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-button class="btn-op-item" @click="handleView(row)"><el-icon><View /></el-icon>查看</el-button>
|
||||
<el-button v-if="hasAuth('edit')" class="btn-op-item primary" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button v-if="hasAuth('delete')" class="btn-op-item" @click="handleDelete(row)">删除</el-button>
|
||||
<el-button class="btn-op-item primary" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button class="btn-op-item" @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -219,8 +218,6 @@
|
||||
fetchDeleteCellSampleType
|
||||
} from '@/api/admin'
|
||||
import SystemViewDialog from '@/components/business/system-view-dialog/index.vue'
|
||||
import { useAuth } from '@/hooks/core/useAuth'
|
||||
const { hasAuth } = useAuth()
|
||||
|
||||
defineOptions({ name: 'BizCellSampleType' })
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">采集协议号列表</h2>
|
||||
<h2>采集协议号列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
@@ -34,11 +34,11 @@
|
||||
<div class="list-toolbar-selected">
|
||||
已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
|
||||
</div>
|
||||
<el-button v-if="hasAuth('add')" class="btn-main" type="primary" @click="handleAdd">
|
||||
<el-button class="btn-main" type="primary" @click="handleAdd">
|
||||
<el-icon><Plus /></el-icon>
|
||||
新增协议号
|
||||
</el-button>
|
||||
<el-button v-if="hasAuth('add')" class="btn-ghost" @click="openBatchGenerate">
|
||||
<el-button class="btn-ghost" @click="openBatchGenerate">
|
||||
批量生成
|
||||
</el-button>
|
||||
<el-button
|
||||
@@ -56,7 +56,6 @@
|
||||
批量收回
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="hasAuth('delete')"
|
||||
class="btn-ghost"
|
||||
type="danger"
|
||||
:disabled="selectedRows.length === 0"
|
||||
@@ -138,8 +137,8 @@
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-button class="btn-op-item" @click="handleView(row)"><el-icon><View /></el-icon>查看</el-button>
|
||||
<el-button v-if="hasAuth('edit')" class="btn-op-item primary" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button v-if="hasAuth('delete')" class="btn-op-item" @click="handleDelete(row)">删除</el-button>
|
||||
<el-button class="btn-op-item primary" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button class="btn-op-item" @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -377,8 +376,6 @@
|
||||
fetchBatchIssueProtocolNos,
|
||||
fetchBatchRevokeProtocolNos
|
||||
} from '@/api/admin'
|
||||
import { useAuth } from '@/hooks/core/useAuth'
|
||||
const { hasAuth } = useAuth()
|
||||
|
||||
defineOptions({ name: 'BizCollectionProtocolNo' })
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">采集地区列表</h2>
|
||||
<h2>采集地区列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
@@ -34,12 +34,11 @@
|
||||
<div class="list-toolbar-selected">
|
||||
已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
|
||||
</div>
|
||||
<el-button v-if="hasAuth('add')" class="btn-main" type="primary" @click="handleAdd">
|
||||
<el-button class="btn-main" type="primary" @click="handleAdd">
|
||||
<el-icon><Plus /></el-icon>
|
||||
新增地区
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="hasAuth('delete')"
|
||||
class="btn-ghost"
|
||||
type="danger"
|
||||
:disabled="selectedRows.length === 0"
|
||||
@@ -114,8 +113,8 @@
|
||||
<el-button class="btn-op-item primary" @click="openHospitalDialog(row)"
|
||||
>地区医院配置</el-button
|
||||
>
|
||||
<el-button v-if="hasAuth('edit')" class="btn-op-item" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button v-if="hasAuth('delete')" class="btn-op-item" @click="handleDelete(row)">删除</el-button>
|
||||
<el-button class="btn-op-item" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button class="btn-op-item" @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -346,8 +345,6 @@
|
||||
fetchUpdateHospital,
|
||||
fetchDeleteHospital
|
||||
} from '@/api/admin'
|
||||
import { useAuth } from '@/hooks/core/useAuth'
|
||||
const { hasAuth } = useAuth()
|
||||
|
||||
defineOptions({ name: 'BizCollectionRegion' })
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">客户列表</h2>
|
||||
<h2>客户列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
@@ -38,12 +38,11 @@
|
||||
<div class="list-toolbar-selected">
|
||||
已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
|
||||
</div>
|
||||
<el-button v-if="hasAuth('add')" class="btn-main" type="primary" @click="handleAdd">
|
||||
<el-button class="btn-main" type="primary" @click="handleAdd">
|
||||
<el-icon><Plus /></el-icon>
|
||||
新增客户
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="hasAuth('delete')"
|
||||
class="btn-ghost"
|
||||
type="danger"
|
||||
:disabled="selectedRows.length === 0"
|
||||
@@ -126,8 +125,8 @@
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-button class="btn-op-item" @click="handleView(row)"><el-icon><View /></el-icon>查看</el-button>
|
||||
<el-button v-if="hasAuth('edit')" class="btn-op-item primary" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button v-if="hasAuth('delete')" class="btn-op-item" @click="handleDelete(row)">删除</el-button>
|
||||
<el-button class="btn-op-item primary" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button class="btn-op-item" @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -236,9 +235,7 @@
|
||||
fetchDeleteCustomer
|
||||
} from '@/api/admin'
|
||||
import SystemViewDialog from '@/components/business/system-view-dialog/index.vue'
|
||||
import { useAuth } from '@/hooks/core/useAuth'
|
||||
import { sexLabel } from '@/utils/status-tag-registry'
|
||||
const { hasAuth } = useAuth()
|
||||
|
||||
defineOptions({ name: 'BizCustomer' })
|
||||
|
||||
|
||||
@@ -0,0 +1,735 @@
|
||||
<!-- 保险公司 — 项目价格配置 -->
|
||||
<!-- eslint-disable vue/no-v-model-argument -->
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<header class="page-head">
|
||||
<h1>保险公司及项目价格</h1>
|
||||
<p class="page-desc">维护保险公司基础信息、开票信息及项目价格管理。</p>
|
||||
</header>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2>保险公司列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
<el-form :model="searchForm" class="filter-form" @submit.prevent>
|
||||
<div class="filter-grid">
|
||||
<el-form-item label="关键词">
|
||||
<el-input v-model="searchForm.keyword" placeholder="公司名称/联系人" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="searchForm.tag" placeholder="全部" clearable style="width: 100%">
|
||||
<el-option label="正常" value="1" />
|
||||
<el-option label="停用" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset">
|
||||
<el-icon><RefreshLeft /></el-icon>重置
|
||||
</el-button>
|
||||
<el-button class="btn-main" type="primary" @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>搜索
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="list-toolbar">
|
||||
<div class="list-toolbar-row">
|
||||
<div class="list-toolbar-selected">
|
||||
已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
|
||||
</div>
|
||||
<el-button class="btn-main" type="primary" @click="handleAdd">
|
||||
<el-icon><Plus /></el-icon>新增保险公司
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-body list-wrap">
|
||||
<el-table
|
||||
class="list-table"
|
||||
:data="tableData"
|
||||
v-loading="loading"
|
||||
stripe
|
||||
row-key="id"
|
||||
@selection-change="handleSelectionChange"
|
||||
@row-dblclick="handleView"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" header-align="center" />
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
width="68"
|
||||
align="center"
|
||||
header-align="center"
|
||||
:index="(i) => (pagination.page - 1) * pagination.pageSize + i + 1"
|
||||
/>
|
||||
<el-table-column prop="companyName" label="保险公司名称" min-width="160" align="center" header-align="center" />
|
||||
<el-table-column prop="companyAddress" label="地址" min-width="180" align="center" header-align="center" />
|
||||
<el-table-column prop="contactName" label="联系人" min-width="100" align="center" header-align="center" />
|
||||
<el-table-column prop="contactPhone" label="联系电话" min-width="120" align="center" header-align="center" />
|
||||
<el-table-column prop="tag" label="状态" width="90" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status == '1' ? 'success' : 'info'" size="small">{{ row.status == '1' ? '正常' : '停用' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="400" fixed="right" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button class="btn-op-item" @click="handleView(row)"><el-icon><View /></el-icon>查看</el-button>
|
||||
<el-button class="btn-op-item primary" @click="openItemDialog(row)"><el-icon><Setting /></el-icon>项目价格配置</el-button>
|
||||
<el-button class="btn-op-item" @click="handleEdit(row)"><el-icon><Edit /></el-icon>编辑</el-button>
|
||||
<el-button class="btn-op-item" @click="handleDelete(row)"><el-icon><Delete /></el-icon>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination list-pager-bar">
|
||||
<el-pagination
|
||||
:current-page="pagination.page"
|
||||
:page-size="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
@size-change="(v) => ((pagination.page = 1), (pagination.pageSize = v), loadData())"
|
||||
@current-change="(v) => ((pagination.page = v), loadData())"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑保险公司弹窗 -->
|
||||
<el-dialog
|
||||
v-model="companyDialogVisible"
|
||||
:title="companyDialogTitle"
|
||||
width="720px"
|
||||
class="dialog-form-layout"
|
||||
align-center
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form ref="companyFormRef" :model="companyForm" :rules="companyFormRules" label-position="top" class="biz-dialog-form">
|
||||
<div class="form-grid-2">
|
||||
<el-form-item label="保险公司名称" prop="companyName">
|
||||
<el-input v-model="companyForm.companyName" placeholder="请输入保险公司名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="公司地址">
|
||||
<el-input v-model="companyForm.companyAddress" placeholder="请输入公司地址" />
|
||||
</el-form-item>
|
||||
<el-form-item label="联系人">
|
||||
<el-input v-model="companyForm.contactName" placeholder="请输入联系人" />
|
||||
</el-form-item>
|
||||
<el-form-item label="联系电话">
|
||||
<el-input v-model="companyForm.contactPhone" placeholder="请输入联系电话" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="tag">
|
||||
<el-radio-group v-model="companyForm.tag">
|
||||
<el-radio :value="1">正常</el-radio>
|
||||
<el-radio :value="0">停用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" class="form-col-span-2">
|
||||
<el-input v-model="companyForm.remark" type="textarea" :rows="2" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="form-section">
|
||||
<div class="section-title">开票信息</div>
|
||||
<div class="form-grid-2">
|
||||
<el-form-item label="发票抬头">
|
||||
<el-input v-model="companyForm.invoiceTitle" placeholder="与营业执照一致" />
|
||||
</el-form-item>
|
||||
<el-form-item label="纳税人识别号">
|
||||
<el-input v-model="companyForm.taxNo" placeholder="统一社会信用代码" />
|
||||
</el-form-item>
|
||||
<el-form-item label="开户银行">
|
||||
<el-input v-model="companyForm.bankName" placeholder="收款银行全称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="银行账号">
|
||||
<el-input v-model="companyForm.bankAccount" placeholder="收款账号" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button class="btn-ghost" @click="companyDialogVisible = false">
|
||||
<el-icon><Close /></el-icon>取消
|
||||
</el-button>
|
||||
<el-button class="btn-main" type="primary" :loading="companySubmitLoading" @click="submitCompany">
|
||||
<el-icon><Check /></el-icon>确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 项目价格配置弹窗 -->
|
||||
<el-dialog
|
||||
v-model="itemDialogVisible"
|
||||
:title="itemDialogTitle"
|
||||
width="960px"
|
||||
class="dialog-form-layout insurance-item-config-dialog"
|
||||
align-center
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
@closed="onItemDialogClosed"
|
||||
>
|
||||
<div class="item-dialog-head">
|
||||
<span class="muted">当前公司:{{ currentCompanyName }}</span>
|
||||
</div>
|
||||
|
||||
<div class="list-toolbar item-toolbar">
|
||||
<div class="list-toolbar-row">
|
||||
<div class="list-toolbar-selected">
|
||||
已选 <span class="sel-num">{{ itemSelected.length }}</span> 项
|
||||
</div>
|
||||
<el-button class="btn-main" type="primary" @click="handleAddItem">
|
||||
<el-icon><Plus /></el-icon>新增项目
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-body list-wrap item-table-wrap">
|
||||
<el-table
|
||||
class="list-table"
|
||||
:data="itemTable"
|
||||
v-loading="itemLoading"
|
||||
stripe
|
||||
row-key="id"
|
||||
max-height="460"
|
||||
@selection-change="onItemSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" header-align="center" />
|
||||
<el-table-column type="index" label="序号" width="68" align="center" header-align="center" />
|
||||
<el-table-column prop="projectName" label="项目名称" min-width="160" align="center" header-align="center" />
|
||||
<el-table-column prop="projectFee" label="项目费用(元)" width="120" align="center" header-align="center">
|
||||
<template #default="{ row }">{{ row.projectFee != null ? `¥${row.projectFee}` : '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="90" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status == '1' ? 'success' : 'info'" size="small">{{ row.status == '1' ? '正常' : '停用' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="140" align="center" header-align="center" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="260" fixed="right" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button class="btn-op-item primary" @click="handleEditItem(row)"><el-icon><Edit /></el-icon>编辑</el-button>
|
||||
<el-button class="btn-op-item" @click="handleDeleteItem(row)"><el-icon><Delete /></el-icon>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination list-pager-bar">
|
||||
<el-pagination
|
||||
:current-page="itemPagination.page"
|
||||
:page-size="itemPagination.pageSize"
|
||||
:total="itemPagination.total"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
@size-change="(v) => ((itemPagination.page = 1), (itemPagination.pageSize = v), loadItems())"
|
||||
@current-change="(v) => ((itemPagination.page = v), loadItems())"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑项目嵌套弹窗 -->
|
||||
<el-dialog
|
||||
v-model="itemFormVisible"
|
||||
:title="itemFormTitle"
|
||||
width="640px"
|
||||
class="dialog-form-layout"
|
||||
align-center
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form ref="itemFormRef" :model="itemForm" :rules="itemFormRules" label-position="top" class="biz-dialog-form">
|
||||
<div class="form-grid-2">
|
||||
<el-form-item label="项目名称" prop="projectName">
|
||||
<el-input v-model="itemForm.projectName" />
|
||||
</el-form-item>
|
||||
<el-form-item label="项目费用(元)" prop="projectFee">
|
||||
<el-input-number v-model="itemForm.projectFee" :min="0" :precision="2" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="itemForm.status">
|
||||
<el-radio value="1">正常</el-radio>
|
||||
<el-radio value="0">停用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" class="form-col-span-2">
|
||||
<el-input v-model="itemForm.remark" type="textarea" :rows="2" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button class="btn-ghost" @click="itemFormVisible = false">
|
||||
<el-icon><Close /></el-icon>取消
|
||||
</el-button>
|
||||
<el-button class="btn-main" type="primary" :loading="itemSubmitLoading" @click="submitItem">
|
||||
<el-icon><Check /></el-icon>确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<template #footer>
|
||||
<el-button class="btn-ghost" @click="itemDialogVisible = false">
|
||||
<el-icon><Close /></el-icon>关闭
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 查看弹窗 -->
|
||||
<SystemViewDialog
|
||||
v-model:visible="viewVisible"
|
||||
title="查看保险公司"
|
||||
:icon="OfficeBuilding"
|
||||
:meta="viewCompanyName"
|
||||
:sections="viewSections"
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Plus, Close, Check, Search, RefreshLeft, View, Setting, Edit, Delete, OfficeBuilding } from '@element-plus/icons-vue'
|
||||
import SystemViewDialog from '@/components/business/system-view-dialog/index.vue'
|
||||
import type { ViewSection } from '@/components/business/system-view-dialog/index.vue'
|
||||
import {
|
||||
fetchInsuranceCompanyList,
|
||||
fetchCreateInsuranceCompany,
|
||||
fetchUpdateInsuranceCompany,
|
||||
fetchDeleteInsuranceCompany,
|
||||
fetchInsuranceCompanyInvoices,
|
||||
fetchCreateInsuranceCompanyInvoice,
|
||||
fetchUpdateInsuranceCompanyInvoice,
|
||||
fetchDeleteInsuranceCompanyInvoice,
|
||||
fetchInsuranceProjectPrices,
|
||||
fetchCreateInsuranceProjectPrice,
|
||||
fetchUpdateInsuranceProjectPrice,
|
||||
fetchDeleteInsuranceProjectPrice
|
||||
} from '@/api/admin'
|
||||
import { withFullscreenLoading, fullscreenLoadingText } from '@/utils/fullscreen-loading'
|
||||
|
||||
defineOptions({ name: 'BasicInfoInsuranceCompany' })
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 搜索 & 主表
|
||||
// ---------------------------------------------------------------------------
|
||||
const searchForm = reactive({ keyword: '', tag: '' })
|
||||
const tableData = ref<any[]>([])
|
||||
const selectedRows = ref<any[]>([])
|
||||
const loading = ref(false)
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 保险公司弹窗
|
||||
// ---------------------------------------------------------------------------
|
||||
const companyDialogVisible = ref(false)
|
||||
const companyDialogTitle = ref('新增保险公司')
|
||||
const companyIsEdit = ref(false)
|
||||
const companySubmitLoading = ref(false)
|
||||
const companyFormRef = ref()
|
||||
const editingId = ref<string | null>(null)
|
||||
const companyForm = reactive({
|
||||
companyName: '',
|
||||
companyAddress: '',
|
||||
contactName: '',
|
||||
contactPhone: '',
|
||||
invoiceTitle: '',
|
||||
taxNo: '',
|
||||
bankName: '',
|
||||
bankAccount: '',
|
||||
tag: 1 as number,
|
||||
remark: ''
|
||||
})
|
||||
const companyFormRules = {
|
||||
companyName: [{ required: true, message: '请输入保险公司名称', trigger: 'blur' }],
|
||||
tag: [{ required: true, message: '请选择状态', trigger: 'change' }]
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 项目价格配置弹窗
|
||||
// ---------------------------------------------------------------------------
|
||||
const itemDialogVisible = ref(false)
|
||||
const itemDialogTitle = ref('项目价格配置')
|
||||
const currentCompanyId = ref('')
|
||||
const currentCompanyName = ref('')
|
||||
const itemTable = ref<any[]>([])
|
||||
const itemSelected = ref<any[]>([])
|
||||
const itemLoading = ref(false)
|
||||
const itemPagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
|
||||
const itemFormVisible = ref(false)
|
||||
const itemFormTitle = ref('新增项目')
|
||||
const itemIsEdit = ref(false)
|
||||
const itemSubmitLoading = ref(false)
|
||||
const itemFormRef = ref()
|
||||
const editingItemId = ref<string | null>(null)
|
||||
const itemForm = reactive({
|
||||
projectName: '',
|
||||
projectFee: 0 as number | null,
|
||||
status: '1',
|
||||
remark: ''
|
||||
})
|
||||
const itemFormRules = {
|
||||
projectName: [{ required: true, message: '请输入项目名称', trigger: 'blur' }],
|
||||
status: [{ required: true, message: '请选择状态', trigger: 'change' }]
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 查看弹窗
|
||||
// ---------------------------------------------------------------------------
|
||||
const viewVisible = ref(false)
|
||||
const viewCompanyName = ref('')
|
||||
const viewSections = ref<ViewSection[]>([])
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 主表数据加载
|
||||
// ---------------------------------------------------------------------------
|
||||
async function loadData() {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await fetchInsuranceCompanyList({
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
})
|
||||
tableData.value = (res as any)?.list || []
|
||||
pagination.total = (res as any)?.total ?? 0
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
searchForm.tag = ''
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
function handleSelectionChange(rows: any[]) {
|
||||
selectedRows.value = rows
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 保险公司弹窗操作
|
||||
// ---------------------------------------------------------------------------
|
||||
function resetCompanyForm() {
|
||||
companyForm.companyName = ''
|
||||
companyForm.companyAddress = ''
|
||||
companyForm.contactName = ''
|
||||
companyForm.contactPhone = ''
|
||||
companyForm.invoiceTitle = ''
|
||||
companyForm.taxNo = ''
|
||||
companyForm.bankName = ''
|
||||
companyForm.bankAccount = ''
|
||||
companyForm.tag = 1
|
||||
companyForm.remark = ''
|
||||
editingId.value = null
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
companyIsEdit.value = false
|
||||
companyDialogTitle.value = '新增保险公司'
|
||||
resetCompanyForm()
|
||||
companyDialogVisible.value = true
|
||||
}
|
||||
|
||||
async function handleEdit(row: any) {
|
||||
companyIsEdit.value = true
|
||||
companyDialogTitle.value = '编辑保险公司'
|
||||
editingId.value = row.id
|
||||
companyForm.companyName = row.companyName || ''
|
||||
companyForm.companyAddress = row.companyAddress || ''
|
||||
companyForm.contactName = row.contactName || ''
|
||||
companyForm.contactPhone = row.contactPhone || ''
|
||||
companyForm.tag = row.status != null ? Number(row.status) : 1
|
||||
companyForm.remark = row.remark || ''
|
||||
// 加载开票信息
|
||||
try {
|
||||
const invRes = await fetchInsuranceCompanyInvoices(row.id)
|
||||
const invoices = (invRes as any)?.list || (invRes as any) || []
|
||||
if (invoices.length > 0) {
|
||||
const inv = invoices[0]
|
||||
companyForm.invoiceTitle = inv.invoiceTitle || inv.companyName || ''
|
||||
companyForm.taxNo = inv.taxNo || ''
|
||||
companyForm.bankName = inv.bankName || ''
|
||||
companyForm.bankAccount = inv.bankAccount || ''
|
||||
} else {
|
||||
companyForm.invoiceTitle = ''
|
||||
companyForm.taxNo = ''
|
||||
companyForm.bankName = ''
|
||||
companyForm.bankAccount = ''
|
||||
}
|
||||
} catch {
|
||||
companyForm.invoiceTitle = ''
|
||||
companyForm.taxNo = ''
|
||||
companyForm.bankName = ''
|
||||
companyForm.bankAccount = ''
|
||||
}
|
||||
companyDialogVisible.value = true
|
||||
}
|
||||
|
||||
async function submitCompany() {
|
||||
const valid = await companyFormRef.value?.validate?.().catch(() => false)
|
||||
if (!valid) return
|
||||
companySubmitLoading.value = true
|
||||
try {
|
||||
const payload = {
|
||||
companyName: companyForm.companyName.trim(),
|
||||
companyAddress: companyForm.companyAddress?.trim() || undefined,
|
||||
contactName: companyForm.contactName?.trim() || undefined,
|
||||
contactPhone: companyForm.contactPhone?.trim() || undefined,
|
||||
status: String(companyForm.tag),
|
||||
remark: companyForm.remark?.trim() || undefined
|
||||
}
|
||||
if (companyIsEdit.value && editingId.value) {
|
||||
await fetchUpdateInsuranceCompany(editingId.value, payload)
|
||||
// 同步开票信息
|
||||
const invRes = await fetchInsuranceCompanyInvoices(editingId.value)
|
||||
const invoices = (invRes as any)?.list || (invRes as any) || []
|
||||
const invoicePayload = {
|
||||
companyName: companyForm.invoiceTitle?.trim() || undefined,
|
||||
invoiceTitle: companyForm.invoiceTitle?.trim() || undefined,
|
||||
taxNo: companyForm.taxNo?.trim() || undefined,
|
||||
bankName: companyForm.bankName?.trim() || undefined,
|
||||
bankAccount: companyForm.bankAccount?.trim() || undefined
|
||||
}
|
||||
if (invoices.length > 0) {
|
||||
await fetchUpdateInsuranceCompanyInvoice(invoices[0].id, invoicePayload)
|
||||
} else if (companyForm.invoiceTitle) {
|
||||
await fetchCreateInsuranceCompanyInvoice(editingId.value, invoicePayload)
|
||||
}
|
||||
ElMessage.success('已保存')
|
||||
} else {
|
||||
const newInst = await fetchCreateInsuranceCompany(payload)
|
||||
// 新增时同步创建开票信息
|
||||
if ((newInst as any)?.id && companyForm.invoiceTitle?.trim()) {
|
||||
const invoicePayload = {
|
||||
companyName: companyForm.invoiceTitle?.trim() || undefined,
|
||||
invoiceTitle: companyForm.invoiceTitle?.trim() || undefined,
|
||||
taxNo: companyForm.taxNo?.trim() || undefined,
|
||||
bankName: companyForm.bankName?.trim() || undefined,
|
||||
bankAccount: companyForm.bankAccount?.trim() || undefined,
|
||||
}
|
||||
await fetchCreateInsuranceCompanyInvoice((newInst as any).id, invoicePayload)
|
||||
}
|
||||
ElMessage.success('已新增')
|
||||
}
|
||||
companyDialogVisible.value = false
|
||||
loadData()
|
||||
} finally {
|
||||
companySubmitLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDelete(row: any) {
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定删除「${row.companyName}」?其下属项目价格将一并删除。`, '提示', {
|
||||
type: 'warning'
|
||||
})
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
await withFullscreenLoading(async () => {
|
||||
await fetchDeleteInsuranceCompany(row.id)
|
||||
ElMessage.success('已删除')
|
||||
await loadData()
|
||||
}, fullscreenLoadingText.delete)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 查看弹窗
|
||||
// ---------------------------------------------------------------------------
|
||||
async function handleView(row: any) {
|
||||
viewCompanyName.value = row.companyName || ''
|
||||
const sections: ViewSection[] = [
|
||||
{
|
||||
title: '基本信息',
|
||||
fields: [
|
||||
{ label: '保险公司名称', value: row.companyName },
|
||||
{ label: '公司地址', value: row.companyAddress, span: true },
|
||||
{ label: '联系人', value: row.contactName },
|
||||
{ label: '联系电话', value: row.contactPhone },
|
||||
{ label: '状态', value: row.status == '1' ? '正常' : '停用', tagType: row.status == '1' ? 'success' : 'info' },
|
||||
{ label: '备注', value: row.remark, span: true }
|
||||
]
|
||||
}
|
||||
]
|
||||
// 加载开票信息
|
||||
try {
|
||||
const invRes = await fetchInsuranceCompanyInvoices(row.id)
|
||||
const invoices = (invRes as any)?.list || (invRes as any) || []
|
||||
if (invoices.length > 0) {
|
||||
const inv = invoices[0]
|
||||
sections.push({
|
||||
title: '开票信息',
|
||||
fields: [
|
||||
{ label: '发票抬头', value: inv.invoiceTitle || inv.companyName },
|
||||
{ label: '纳税人识别号', value: inv.taxNo },
|
||||
{ label: '开户银行', value: inv.bankName },
|
||||
{ label: '银行账号', value: inv.bankAccount }
|
||||
]
|
||||
})
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
viewSections.value = sections
|
||||
viewVisible.value = true
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 项目价格配置弹窗
|
||||
// ---------------------------------------------------------------------------
|
||||
function openItemDialog(row: any) {
|
||||
currentCompanyId.value = row.id
|
||||
currentCompanyName.value = row.companyName || ''
|
||||
itemPagination.page = 1
|
||||
itemSelected.value = []
|
||||
itemDialogTitle.value = `项目价格配置 — ${row.companyName}`
|
||||
itemDialogVisible.value = true
|
||||
loadItems()
|
||||
}
|
||||
|
||||
async function loadItems() {
|
||||
if (!currentCompanyId.value) return
|
||||
itemLoading.value = true
|
||||
try {
|
||||
const res = await fetchInsuranceProjectPrices(currentCompanyId.value)
|
||||
const list = Array.isArray(res) ? res : (res as any)?.list || []
|
||||
itemTable.value = list
|
||||
itemPagination.total = Array.isArray(res) ? list.length : ((res as any)?.total ?? list.length)
|
||||
} finally {
|
||||
itemLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function onItemDialogClosed() {
|
||||
currentCompanyId.value = ''
|
||||
currentCompanyName.value = ''
|
||||
itemTable.value = []
|
||||
}
|
||||
|
||||
function onItemSelectionChange(rows: any[]) {
|
||||
itemSelected.value = rows
|
||||
}
|
||||
|
||||
function resetItemForm() {
|
||||
itemForm.projectName = ''
|
||||
itemForm.projectFee = 0
|
||||
itemForm.status = '1'
|
||||
itemForm.remark = ''
|
||||
editingItemId.value = null
|
||||
}
|
||||
|
||||
function handleAddItem() {
|
||||
itemIsEdit.value = false
|
||||
itemFormTitle.value = '新增项目'
|
||||
resetItemForm()
|
||||
itemFormVisible.value = true
|
||||
}
|
||||
|
||||
function handleEditItem(row: any) {
|
||||
itemIsEdit.value = true
|
||||
itemFormTitle.value = '编辑项目'
|
||||
editingItemId.value = row.id
|
||||
itemForm.projectName = row.projectName || ''
|
||||
itemForm.projectFee = row.projectFee ?? 0
|
||||
itemForm.status = row.status != null ? String(row.status) : '1'
|
||||
itemForm.remark = row.remark || ''
|
||||
itemFormVisible.value = true
|
||||
}
|
||||
|
||||
async function submitItem() {
|
||||
const valid = await itemFormRef.value?.validate?.().catch(() => false)
|
||||
if (!valid) return
|
||||
itemSubmitLoading.value = true
|
||||
try {
|
||||
const payload = {
|
||||
projectName: itemForm.projectName.trim(),
|
||||
projectFee: itemForm.projectFee,
|
||||
status: itemForm.status,
|
||||
remark: itemForm.remark?.trim() || undefined
|
||||
}
|
||||
if (itemIsEdit.value && editingItemId.value) {
|
||||
await fetchUpdateInsuranceProjectPrice(editingItemId.value, payload)
|
||||
ElMessage.success('已保存')
|
||||
} else {
|
||||
await fetchCreateInsuranceProjectPrice(currentCompanyId.value, payload)
|
||||
ElMessage.success('已新增')
|
||||
}
|
||||
itemFormVisible.value = false
|
||||
loadItems()
|
||||
} finally {
|
||||
itemSubmitLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDeleteItem(row: any) {
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定删除「${row.projectName}」?`, '提示', { type: 'warning' })
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
await withFullscreenLoading(async () => {
|
||||
await fetchDeleteInsuranceProjectPrice(row.id)
|
||||
ElMessage.success('已删除')
|
||||
await loadItems()
|
||||
}, fullscreenLoadingText.delete)
|
||||
}
|
||||
|
||||
onMounted(() => loadData())
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.biz-dialog-form {
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.item-dialog-head {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.item-dialog-head .muted {
|
||||
font-size: 13px;
|
||||
color: var(--mint-text-muted);
|
||||
}
|
||||
|
||||
.item-toolbar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.item-table-wrap {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
background: #fafafa;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.form-section .section-title {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 12px;
|
||||
padding-left: 10px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
border-left: 3px solid #10b981;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- 弹窗 teleport 到 body,高度类名需非 scoped -->
|
||||
<style lang="scss">
|
||||
.el-dialog.insurance-item-config-dialog.dialog-form-layout {
|
||||
min-height: min(640px, calc(100vh - 80px));
|
||||
}
|
||||
</style>
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">样本编码列表</h2>
|
||||
<h2>样本编码列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
@@ -34,11 +34,11 @@
|
||||
<div class="list-toolbar-selected">
|
||||
已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
|
||||
</div>
|
||||
<el-button v-if="hasAuth('add')" class="btn-main" type="primary" @click="handleAdd">
|
||||
<el-button class="btn-main" type="primary" @click="handleAdd">
|
||||
<el-icon><Plus /></el-icon>
|
||||
新增样本编码
|
||||
</el-button>
|
||||
<el-button v-if="hasAuth('add')" class="btn-ghost" @click="openBatchGenerate">
|
||||
<el-button class="btn-ghost" @click="openBatchGenerate">
|
||||
批量生成
|
||||
</el-button>
|
||||
<el-button
|
||||
@@ -56,7 +56,6 @@
|
||||
批量收回
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="hasAuth('delete')"
|
||||
class="btn-ghost"
|
||||
type="danger"
|
||||
:disabled="selectedRows.length === 0"
|
||||
@@ -147,8 +146,8 @@
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-button class="btn-op-item" @click="handleView(row)"><el-icon><View /></el-icon>查看</el-button>
|
||||
<el-button v-if="hasAuth('edit')" class="btn-op-item primary" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button v-if="hasAuth('delete')" class="btn-op-item" @click="handleDelete(row)">删除</el-button>
|
||||
<el-button class="btn-op-item primary" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button class="btn-op-item" @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -392,9 +391,7 @@
|
||||
fetchBatchIssueSampleCodes,
|
||||
fetchBatchRevokeSampleCodes
|
||||
} from '@/api/admin'
|
||||
import { useAuth } from '@/hooks/core/useAuth'
|
||||
import { sampleCodeTypeLabel } from '@/utils/status-tag-registry'
|
||||
const { hasAuth } = useAuth()
|
||||
|
||||
defineOptions({ name: 'BizSampleCode' })
|
||||
|
||||
|
||||
@@ -0,0 +1,400 @@
|
||||
<!-- 满月待办 — 保险办理管理 -->
|
||||
<!-- eslint-disable vue/no-v-model-argument -->
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<header class="page-head">
|
||||
<h1>满月待办管理</h1>
|
||||
<p class="page-desc">集中管理满月待办保险办理情况,支持筛选与批量办理。</p>
|
||||
</header>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">待办列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
<el-form :model="searchForm" class="filter-form" @submit.prevent>
|
||||
<div class="filter-grid">
|
||||
<el-form-item label="关键词">
|
||||
<el-input
|
||||
v-model="searchForm.keyword"
|
||||
placeholder="协议号/姓名"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="待办状态">
|
||||
<el-select v-model="searchForm.todoStatus" placeholder="全部" clearable style="width: 100%">
|
||||
<el-option label="全部" value="" />
|
||||
<el-option label="未办保险" value="0" />
|
||||
<el-option label="已办报销" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset">
|
||||
<el-icon><RefreshLeft /></el-icon>重置
|
||||
</el-button>
|
||||
<el-button class="btn-main" type="primary" @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>搜索
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="list-body list-wrap">
|
||||
<el-table
|
||||
class="list-table"
|
||||
:data="tableData"
|
||||
v-loading="loading"
|
||||
stripe
|
||||
row-key="id"
|
||||
>
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
width="68"
|
||||
align="center"
|
||||
header-align="center"
|
||||
:index="(i) => (pagination.page - 1) * pagination.pageSize + i + 1"
|
||||
/>
|
||||
<el-table-column prop="protocolNo" label="采集协议号" width="160" align="center" header-align="center" />
|
||||
<el-table-column prop="motherName" label="母亲姓名" width="100" align="center" header-align="center" />
|
||||
<el-table-column prop="newbornDeliveryTime" label="新生儿分娩时间" width="140" align="center" header-align="center" />
|
||||
<el-table-column prop="fullmoonDate" label="满月日期" width="120" align="center" header-align="center" />
|
||||
<el-table-column prop="todoStatus" label="待办状态" width="100" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.todoStatus == 1 ? 'success' : 'warning'" size="small">
|
||||
{{ row.todoStatus == 1 ? '已办报销' : '未办保险' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="insuranceSubscribed" label="是否已订购保险" width="120" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.insuranceSubscribed == 1 ? 'success' : 'info'" size="small">
|
||||
{{ row.insuranceSubscribed == 1 ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="insuranceCompanyName" label="保险公司" width="140" align="center" header-align="center" />
|
||||
<el-table-column prop="insuranceType" label="保险险种" width="120" align="center" header-align="center" />
|
||||
<el-table-column label="操作" width="160" fixed="right" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button class="btn-op-item primary" @click="handleEdit(row)">办理保险</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination list-pager-bar">
|
||||
<el-pagination
|
||||
:current-page="pagination.page"
|
||||
:page-size="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
@size-change="(v) => ((pagination.page = 1), (pagination.pageSize = v), loadData())"
|
||||
@current-change="(v) => ((pagination.page = v), loadData())"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 办理保险弹窗 -->
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
title="办理保险"
|
||||
width="720px"
|
||||
class="dialog-form-layout"
|
||||
align-center
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-position="top"
|
||||
class="biz-dialog-form"
|
||||
scroll-to-error
|
||||
:scroll-into-view-options="{ behavior: 'smooth', block: 'center' }"
|
||||
>
|
||||
<div class="form-grid-2">
|
||||
<el-form-item label="保险公司" prop="insuranceCompanyId">
|
||||
<el-select
|
||||
v-model="formData.insuranceCompanyId"
|
||||
placeholder="请选择保险公司"
|
||||
filterable
|
||||
style="width: 100%"
|
||||
@change="handleInsuranceCompanyChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="c in insuranceCompanyOptions"
|
||||
:key="c.id"
|
||||
:label="c.companyName"
|
||||
:value="c.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="保险险种" prop="insuranceType">
|
||||
<el-input v-model="formData.insuranceType" placeholder="请输入保险险种" />
|
||||
</el-form-item>
|
||||
<el-form-item label="保险单号">
|
||||
<el-input v-model="formData.insurancePolicyNo" placeholder="请输入保险单号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="保单费用(元)">
|
||||
<el-input-number
|
||||
v-model="formData.insuranceFee"
|
||||
:precision="2"
|
||||
:min="0"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="保险单生效时间">
|
||||
<el-date-picker
|
||||
v-model="formData.policyEffectiveDate"
|
||||
type="date"
|
||||
placeholder="请选择生效时间"
|
||||
format="YYYYMMDD"
|
||||
value-format="YYYYMMDD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="保险单失效时间">
|
||||
<el-date-picker
|
||||
v-model="formData.policyExpiryDate"
|
||||
type="date"
|
||||
placeholder="请选择失效时间"
|
||||
format="YYYYMMDD"
|
||||
value-format="YYYYMMDD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否已订购保险">
|
||||
<el-radio-group v-model="formData.insuranceSubscribed">
|
||||
<el-radio :value="1">是</el-radio>
|
||||
<el-radio :value="0">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="办理日期">
|
||||
<el-date-picker
|
||||
v-model="formData.processDate"
|
||||
type="date"
|
||||
placeholder="请选择办理日期"
|
||||
format="YYYYMMDD"
|
||||
value-format="YYYYMMDD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="待办状态">
|
||||
<el-radio-group v-model="formData.todoStatus">
|
||||
<el-radio :value="0">未办保险</el-radio>
|
||||
<el-radio :value="1">已办报销</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="保险单附件" class="form-col-span-2">
|
||||
<el-upload
|
||||
v-model:file-list="formData.attachments"
|
||||
action=""
|
||||
:auto-upload="false"
|
||||
:limit="10"
|
||||
multiple
|
||||
>
|
||||
<el-button type="primary" plain>选择文件</el-button>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">支持上传多个附件,单个文件不超过 20MB</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="办理备注" class="form-col-span-2">
|
||||
<el-input v-model="formData.remark" type="textarea" :rows="3" placeholder="请输入办理备注" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button class="btn-ghost" @click="dialogVisible = false">
|
||||
<el-icon><Close /></el-icon>取消
|
||||
</el-button>
|
||||
<el-button class="btn-main" type="primary" :loading="submitLoading" @click="handleSubmit">
|
||||
<el-icon><Check /></el-icon>确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Close, Check, Search, RefreshLeft } from '@element-plus/icons-vue'
|
||||
import {
|
||||
fetchFullmoonTodoList,
|
||||
fetchUpdateFullmoonTodoInsurance,
|
||||
fetchInsuranceCompanyList
|
||||
} from '@/api/admin'
|
||||
|
||||
defineOptions({ name: 'CellStorageFullmoonTodo' })
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 搜索 & 主表
|
||||
// ---------------------------------------------------------------------------
|
||||
const searchForm = reactive({ keyword: '', todoStatus: '' })
|
||||
const tableData = ref<any[]>([])
|
||||
const loading = ref(false)
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 保险公司下拉
|
||||
// ---------------------------------------------------------------------------
|
||||
const insuranceCompanyOptions = ref<any[]>([])
|
||||
|
||||
async function loadInsuranceCompanies() {
|
||||
try {
|
||||
const res = await fetchInsuranceCompanyList({ page: 1, pageSize: 100 })
|
||||
insuranceCompanyOptions.value = (res as any)?.list || []
|
||||
} catch {
|
||||
insuranceCompanyOptions.value = []
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 主表数据加载
|
||||
// ---------------------------------------------------------------------------
|
||||
async function loadData() {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await fetchFullmoonTodoList({
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
todoStatus: searchForm.todoStatus || undefined
|
||||
})
|
||||
tableData.value = (res as any)?.list || []
|
||||
pagination.total = (res as any)?.total ?? 0
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
searchForm.todoStatus = ''
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 办理保险弹窗
|
||||
// ---------------------------------------------------------------------------
|
||||
const dialogVisible = ref(false)
|
||||
const submitLoading = ref(false)
|
||||
const formRef = ref()
|
||||
const editingRow = ref<any>(null)
|
||||
|
||||
const formData = reactive({
|
||||
insuranceCompanyId: '' as string,
|
||||
insuranceCompanyName: '' as string,
|
||||
insuranceType: '' as string,
|
||||
insurancePolicyNo: '' as string,
|
||||
policyEffectiveDate: '' as string,
|
||||
policyExpiryDate: '' as string,
|
||||
insuranceSubscribed: 0 as number,
|
||||
insuranceFee: 0 as number,
|
||||
processDate: '' as string,
|
||||
remark: '' as string,
|
||||
todoStatus: 0 as number,
|
||||
attachments: [] as any[]
|
||||
})
|
||||
|
||||
const formRules = {
|
||||
insuranceCompanyId: [{ required: true, message: '请选择保险公司', trigger: 'change' }],
|
||||
insuranceType: [{ required: true, message: '请输入保险险种', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
formData.insuranceCompanyId = ''
|
||||
formData.insuranceCompanyName = ''
|
||||
formData.insuranceType = ''
|
||||
formData.insurancePolicyNo = ''
|
||||
formData.policyEffectiveDate = ''
|
||||
formData.policyExpiryDate = ''
|
||||
formData.insuranceSubscribed = 0
|
||||
formData.insuranceFee = 0
|
||||
formData.processDate = ''
|
||||
formData.remark = ''
|
||||
formData.todoStatus = 0
|
||||
formData.attachments = []
|
||||
editingRow.value = null
|
||||
}
|
||||
|
||||
function handleEdit(row: any) {
|
||||
editingRow.value = row
|
||||
resetForm()
|
||||
// 回填已有数据
|
||||
formData.insuranceCompanyId = row.insuranceCompanyId || ''
|
||||
formData.insuranceCompanyName = row.insuranceCompanyName || ''
|
||||
formData.insuranceType = row.insuranceType || ''
|
||||
formData.insurancePolicyNo = row.insurancePolicyNo || ''
|
||||
formData.policyEffectiveDate = row.policyEffectiveDate || ''
|
||||
formData.policyExpiryDate = row.policyExpiryDate || ''
|
||||
formData.insuranceSubscribed = row.insuranceSubscribed ?? 0
|
||||
formData.insuranceFee = row.insuranceFee ?? 0
|
||||
formData.processDate = row.processDate || ''
|
||||
formData.remark = row.remark || ''
|
||||
formData.todoStatus = row.todoStatus ?? 0
|
||||
dialogVisible.value = true
|
||||
formRef.value?.clearValidate?.()
|
||||
}
|
||||
|
||||
function handleInsuranceCompanyChange(val: string) {
|
||||
const found = insuranceCompanyOptions.value.find((c) => c.id === val)
|
||||
formData.insuranceCompanyName = found ? found.companyName : ''
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
await formRef.value?.validate?.()
|
||||
if (!editingRow.value?.protocolId) return
|
||||
submitLoading.value = true
|
||||
try {
|
||||
const payload = {
|
||||
insuranceCompanyId: formData.insuranceCompanyId || undefined,
|
||||
insuranceCompanyName: formData.insuranceCompanyName || undefined,
|
||||
insuranceType: formData.insuranceType?.trim() || undefined,
|
||||
insurancePolicyNo: formData.insurancePolicyNo?.trim() || undefined,
|
||||
policyEffectiveDate: formData.policyEffectiveDate || undefined,
|
||||
policyExpiryDate: formData.policyExpiryDate || undefined,
|
||||
insuranceSubscribed: formData.insuranceSubscribed,
|
||||
insuranceFee: formData.insuranceFee || undefined,
|
||||
processDate: formData.processDate || undefined,
|
||||
remark: formData.remark?.trim() || undefined,
|
||||
todoStatus: formData.todoStatus
|
||||
}
|
||||
await fetchUpdateFullmoonTodoInsurance(editingRow.value.protocolId, payload)
|
||||
ElMessage.success('保存成功')
|
||||
dialogVisible.value = false
|
||||
await loadData()
|
||||
} catch {
|
||||
/* 校验或接口错误已由全局处理 */
|
||||
} finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
loadInsuranceCompanies()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.biz-dialog-form {
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,193 @@
|
||||
<!-- 物料变动记录 -->
|
||||
<!-- eslint-disable vue/no-v-model-argument -->
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<header class="page-head">
|
||||
<h1>物料变动记录</h1>
|
||||
<p class="page-desc">查看物料的入库、出库历史变动记录</p>
|
||||
</header>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2>变动记录列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
<el-form :model="searchForm" class="filter-form" @submit.prevent>
|
||||
<div class="filter-grid">
|
||||
<el-form-item label="物料名称/编码">
|
||||
<el-input v-model="searchForm.keyword" placeholder="物料名称或编码" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="变动类型">
|
||||
<el-select v-model="searchForm.changeType" placeholder="全部" clearable>
|
||||
<el-option label="入库" value="rk" />
|
||||
<el-option label="出库" value="ck" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="日期范围">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">按物料名称/编码查询,可按变动类型和日期范围筛选。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset">重置</el-button>
|
||||
<el-button class="btn-main" type="primary" @click="handleSearch">搜索</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="list-body list-wrap">
|
||||
<el-table
|
||||
class="list-table"
|
||||
:data="tableData"
|
||||
v-loading="loading"
|
||||
stripe
|
||||
row-key="id"
|
||||
>
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
width="68"
|
||||
align="center"
|
||||
header-align="center"
|
||||
:index="(index) => (pagination.page - 1) * pagination.pageSize + index + 1"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="materialCode"
|
||||
label="物料编码"
|
||||
min-width="130"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="materialName"
|
||||
label="物料名称"
|
||||
min-width="150"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column label="变动类型" min-width="100" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.changeType === 'rk' ? 'success' : 'warning'" size="small">
|
||||
{{ row.changeType === 'rk' ? '入库' : '出库' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="变动数量" min-width="100" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.changeType === 'rk' ? '+' : '' }}{{ row.changeQty }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="stockBefore"
|
||||
label="变动前库存"
|
||||
min-width="110"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="stockAfter"
|
||||
label="变动后库存"
|
||||
min-width="110"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column label="领用人" min-width="100" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.changeType === 'ck' ? (row.receiver || '-') : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用途" min-width="120" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.changeType === 'ck' ? (row.purpose || '-') : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="createBy"
|
||||
label="操作人"
|
||||
min-width="100"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="createTime"
|
||||
label="操作时间"
|
||||
min-width="180"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
</el-table>
|
||||
<div class="pagination list-pager-bar">
|
||||
<el-pagination
|
||||
:current-page="pagination.page"
|
||||
:page-size="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
@size-change="(val) => ((pagination.page = 1), (pagination.pageSize = val), loadData())"
|
||||
@current-change="(val) => ((pagination.page = val), loadData())"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { fetchMaterialStockLogList } from '@/api/material'
|
||||
import type { MaterialStockLog } from '@/api/material'
|
||||
|
||||
defineOptions({ name: 'CellStorageMaterialStockLog' })
|
||||
|
||||
const searchForm = reactive({ keyword: '', changeType: '' })
|
||||
const dateRange = ref<[string, string] | null>(null)
|
||||
const tableData = ref<MaterialStockLog[]>([])
|
||||
const loading = ref(false)
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
|
||||
async function loadData() {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await fetchMaterialStockLogList({
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
changeType: searchForm.changeType || undefined,
|
||||
startTime: dateRange.value?.[0] || undefined,
|
||||
endTime: dateRange.value?.[1] || undefined
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total ?? 0
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
searchForm.changeType = ''
|
||||
dateRange.value = null
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,669 @@
|
||||
<!-- 市场物料库 -->
|
||||
<!-- eslint-disable vue/no-v-model-argument -->
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<header class="page-head">
|
||||
<h1>物料库</h1>
|
||||
<p class="page-desc">管理市场部门的物料信息,支持入库、出库操作</p>
|
||||
</header>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2>物料列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
<el-form :model="searchForm" class="filter-form" @submit.prevent>
|
||||
<div class="filter-grid">
|
||||
<el-form-item label="关键词">
|
||||
<el-input v-model="searchForm.keyword" placeholder="物料编码/名称" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="物料分类">
|
||||
<el-select v-model="searchForm.category" placeholder="全部" clearable>
|
||||
<el-option
|
||||
v-for="opt in categoryOptions"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="searchForm.status" placeholder="全部" clearable>
|
||||
<el-option label="正常" value="1" />
|
||||
<el-option label="停用" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">按编码、名称模糊查询,可按分类、状态筛选。</span>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset">重置</el-button>
|
||||
<el-button class="btn-main" type="primary" @click="handleSearch">搜索</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="list-toolbar">
|
||||
<div class="list-toolbar-row">
|
||||
<div class="list-toolbar-selected">
|
||||
已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
|
||||
</div>
|
||||
<el-button class="btn-main" type="primary" @click="handleAdd">
|
||||
<el-icon><Plus /></el-icon>
|
||||
新增物料
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-body list-wrap">
|
||||
<el-table
|
||||
class="list-table"
|
||||
:data="tableData"
|
||||
v-loading="loading"
|
||||
stripe
|
||||
row-key="id"
|
||||
@selection-change="handleSelectionChange"
|
||||
@row-dblclick="handleView"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" header-align="center" />
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
width="68"
|
||||
align="center"
|
||||
header-align="center"
|
||||
:index="(index) => (pagination.page - 1) * pagination.pageSize + index + 1"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="materialCode"
|
||||
label="物料编码"
|
||||
min-width="130"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="materialName"
|
||||
label="物料名称"
|
||||
min-width="150"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column label="物料分类" min-width="120" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getCategoryTagType(row.category)" size="small">
|
||||
{{ getCategoryLabel(row.category) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="specModel"
|
||||
label="规格型号"
|
||||
min-width="120"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="unit"
|
||||
label="单位"
|
||||
min-width="80"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="stockQty"
|
||||
label="当前库存"
|
||||
min-width="100"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column label="状态" min-width="90" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status === '1' ? 'success' : 'info'" size="small">
|
||||
{{ row.status === '1' ? '正常' : '停用' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" min-width="260" fixed="right" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button class="btn-op-item" @click="handleStockIn(row)">入库</el-button>
|
||||
<el-button class="btn-op-item" @click="handleStockOut(row)">出库</el-button>
|
||||
<el-button class="btn-op-item" @click="handleView(row)"
|
||||
><el-icon><View /></el-icon>查看</el-button
|
||||
>
|
||||
<el-button class="btn-op-item primary" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button class="btn-op-item" @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination list-pager-bar">
|
||||
<el-pagination
|
||||
:current-page="pagination.page"
|
||||
:page-size="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
@size-change="(val) => ((pagination.page = 1), (pagination.pageSize = val), loadData())"
|
||||
@current-change="(val) => ((pagination.page = val), loadData())"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑弹窗 -->
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogTitle"
|
||||
width="560px"
|
||||
class="dialog-form-layout"
|
||||
align-center
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-position="top"
|
||||
class="material-dialog-form"
|
||||
scroll-to-error
|
||||
:scroll-into-view-options="{ behavior: 'smooth', block: 'center' }"
|
||||
>
|
||||
<div class="form-grid-2">
|
||||
<el-form-item label="物料编码" prop="materialCode">
|
||||
<el-input v-model="formData.materialCode" placeholder="请输入物料编码" />
|
||||
</el-form-item>
|
||||
<el-form-item label="物料名称" prop="materialName">
|
||||
<el-input v-model="formData.materialName" placeholder="请输入物料名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="物料分类" prop="category">
|
||||
<el-select v-model="formData.category" placeholder="请选择物料分类" clearable>
|
||||
<el-option
|
||||
v-for="opt in categoryOptions"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="规格型号" prop="specModel">
|
||||
<el-input v-model="formData.specModel" placeholder="请输入规格型号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="单位" prop="unit">
|
||||
<el-input v-model="formData.unit" placeholder="请输入单位" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio value="1">正常</el-radio>
|
||||
<el-radio value="0">停用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" class="form-col-span-2">
|
||||
<el-input
|
||||
v-model="formData.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="可选"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button class="btn-ghost" @click="dialogVisible = false">
|
||||
<el-icon><Close /></el-icon>
|
||||
取消
|
||||
</el-button>
|
||||
<el-button class="btn-main" type="primary" @click="handleSubmit" :loading="submitLoading">
|
||||
<el-icon><Check /></el-icon>
|
||||
确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 入库弹窗 -->
|
||||
<el-dialog
|
||||
v-model="stockInVisible"
|
||||
title="物料入库"
|
||||
width="480px"
|
||||
class="dialog-form-layout"
|
||||
align-center
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form
|
||||
ref="stockInFormRef"
|
||||
:model="stockInForm"
|
||||
:rules="stockInRules"
|
||||
label-position="top"
|
||||
scroll-to-error
|
||||
:scroll-into-view-options="{ behavior: 'smooth', block: 'center' }"
|
||||
>
|
||||
<el-form-item label="入库数量" prop="qty">
|
||||
<el-input-number
|
||||
v-model="stockInForm.qty"
|
||||
:min="0.01"
|
||||
:precision="2"
|
||||
:step="1"
|
||||
placeholder="请输入入库数量"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input
|
||||
v-model="stockInForm.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="可选"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button class="btn-ghost" @click="stockInVisible = false">
|
||||
<el-icon><Close /></el-icon>
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
class="btn-main"
|
||||
type="primary"
|
||||
@click="handleStockInSubmit"
|
||||
:loading="stockInLoading"
|
||||
>
|
||||
<el-icon><Check /></el-icon>
|
||||
确认入库
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 出库弹窗 -->
|
||||
<el-dialog
|
||||
v-model="stockOutVisible"
|
||||
title="物料出库"
|
||||
width="480px"
|
||||
class="dialog-form-layout"
|
||||
align-center
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form
|
||||
ref="stockOutFormRef"
|
||||
:model="stockOutForm"
|
||||
:rules="stockOutRules"
|
||||
label-position="top"
|
||||
scroll-to-error
|
||||
:scroll-into-view-options="{ behavior: 'smooth', block: 'center' }"
|
||||
>
|
||||
<el-form-item label="出库数量" prop="qty">
|
||||
<el-input-number
|
||||
v-model="stockOutForm.qty"
|
||||
:min="0.01"
|
||||
:precision="2"
|
||||
:step="1"
|
||||
placeholder="请输入出库数量"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="领用人" prop="receiver">
|
||||
<el-input v-model="stockOutForm.receiver" placeholder="请输入领用人" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用途">
|
||||
<el-input
|
||||
v-model="stockOutForm.purpose"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="可选"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input
|
||||
v-model="stockOutForm.remark"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="可选"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button class="btn-ghost" @click="stockOutVisible = false">
|
||||
<el-icon><Close /></el-icon>
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
class="btn-main"
|
||||
type="primary"
|
||||
@click="handleStockOutSubmit"
|
||||
:loading="stockOutLoading"
|
||||
>
|
||||
<el-icon><Check /></el-icon>
|
||||
确认出库
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 查看弹窗 -->
|
||||
<SystemViewDialog
|
||||
v-model:visible="viewVisible"
|
||||
:title="viewRow?.materialName || '物料详情'"
|
||||
:icon="Box"
|
||||
:meta="viewRow?.createTime || ''"
|
||||
:sections="viewSections"
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus, Close, Check, View, Box } from '@element-plus/icons-vue'
|
||||
import SystemViewDialog from '@/components/business/system-view-dialog/index.vue'
|
||||
import { fetchDictDataOptions } from '@/api/admin'
|
||||
import {
|
||||
fetchMaterialList,
|
||||
fetchCreateMaterial,
|
||||
fetchUpdateMaterial,
|
||||
fetchDeleteMaterial,
|
||||
fetchStockInMaterial,
|
||||
fetchStockOutMaterial
|
||||
} from '@/api/material'
|
||||
import type { Material } from '@/api/material'
|
||||
|
||||
defineOptions({ name: 'CellStorageMaterial' })
|
||||
|
||||
const searchForm = reactive({ keyword: '', category: '', status: '' })
|
||||
const tableData = ref<Material[]>([])
|
||||
const selectedRows = ref<Material[]>([])
|
||||
const loading = ref(false)
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
|
||||
// 字典选项
|
||||
const categoryOptions = ref<{ label: string; value: string }[]>([])
|
||||
|
||||
// 新增/编辑
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = ref('新增物料')
|
||||
const isEdit = ref(false)
|
||||
const submitLoading = ref(false)
|
||||
const formRef = ref()
|
||||
const editingId = ref<string | null>(null)
|
||||
|
||||
const formData = reactive({
|
||||
materialCode: '',
|
||||
materialName: '',
|
||||
category: '',
|
||||
specModel: '',
|
||||
unit: '',
|
||||
status: '1',
|
||||
remark: ''
|
||||
})
|
||||
|
||||
const formRules = {
|
||||
materialCode: [{ required: true, message: '请输入物料编码', trigger: 'blur' }],
|
||||
materialName: [{ required: true, message: '请输入物料名称', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
// 入库
|
||||
const stockInVisible = ref(false)
|
||||
const stockInLoading = ref(false)
|
||||
const stockInFormRef = ref()
|
||||
const stockInMaterialId = ref<string | null>(null)
|
||||
const stockInForm = reactive({ qty: 1, remark: '' })
|
||||
|
||||
const stockInRules = {
|
||||
qty: [{ required: true, message: '请输入入库数量', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
// 出库
|
||||
const stockOutVisible = ref(false)
|
||||
const stockOutLoading = ref(false)
|
||||
const stockOutFormRef = ref()
|
||||
const stockOutMaterialId = ref<string | null>(null)
|
||||
const stockOutStockQty = ref(0)
|
||||
const stockOutForm = reactive({ qty: 1, receiver: '', purpose: '', remark: '' })
|
||||
|
||||
const stockOutRules = {
|
||||
qty: [{ required: true, message: '请输入出库数量', trigger: 'blur' }],
|
||||
receiver: [{ required: true, message: '请输入领用人', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
// 查看
|
||||
const viewVisible = ref(false)
|
||||
const viewRow = ref<Material | null>(null)
|
||||
|
||||
const getCategoryLabel = (code: string) => {
|
||||
if (!code) return '-'
|
||||
const opt = categoryOptions.value.find((o) => o.value === code)
|
||||
return opt ? opt.label : code
|
||||
}
|
||||
|
||||
const getCategoryTagType = (code: string) => {
|
||||
if (code === 'xccyw') return 'primary'
|
||||
if (code === 'ccyw') return 'success'
|
||||
return 'info'
|
||||
}
|
||||
|
||||
const handleSelectionChange = (rows: Material[]) => {
|
||||
selectedRows.value = rows
|
||||
}
|
||||
|
||||
const viewSections = computed(() => {
|
||||
if (!viewRow.value) return []
|
||||
const row = viewRow.value
|
||||
return [
|
||||
{
|
||||
title: '基本信息',
|
||||
fields: [
|
||||
{ label: '物料编码', value: row.materialCode },
|
||||
{ label: '物料名称', value: row.materialName },
|
||||
{
|
||||
label: '物料分类',
|
||||
value: getCategoryLabel(row.category),
|
||||
tagType: getCategoryTagType(row.category) as 'success' | 'warning' | 'danger' | 'info' | '' | 'primary'
|
||||
},
|
||||
{ label: '规格型号', value: row.specModel },
|
||||
{ label: '单位', value: row.unit },
|
||||
{
|
||||
label: '状态',
|
||||
value: row.status === '1' ? '正常' : '停用',
|
||||
tagType: (row.status === '1' ? 'success' : 'info') as 'success' | 'info'
|
||||
},
|
||||
{ label: '当前库存', value: String(row.stockQty ?? 0) }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '其他信息',
|
||||
fields: [
|
||||
{ label: '备注', value: row.remark, span: true },
|
||||
{ label: '创建时间', value: row.createTime },
|
||||
{ label: '更新时间', value: row.updateTime }
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
async function loadDictOptions() {
|
||||
try {
|
||||
const res = await fetchDictDataOptions('wllb')
|
||||
categoryOptions.value = res || []
|
||||
} catch {
|
||||
categoryOptions.value = []
|
||||
}
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await fetchMaterialList({
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
category: searchForm.category || undefined,
|
||||
status: searchForm.status || undefined
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total ?? 0
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
searchForm.category = ''
|
||||
searchForm.status = ''
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
formData.materialCode = ''
|
||||
formData.materialName = ''
|
||||
formData.category = ''
|
||||
formData.specModel = ''
|
||||
formData.unit = ''
|
||||
formData.status = '1'
|
||||
formData.remark = ''
|
||||
editingId.value = null
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
isEdit.value = false
|
||||
dialogTitle.value = '新增物料'
|
||||
resetForm()
|
||||
dialogVisible.value = true
|
||||
formRef.value?.clearValidate?.()
|
||||
}
|
||||
|
||||
function handleEdit(row: Material) {
|
||||
isEdit.value = true
|
||||
dialogTitle.value = '编辑物料'
|
||||
editingId.value = row.id
|
||||
formData.materialCode = row.materialCode || ''
|
||||
formData.materialName = row.materialName || ''
|
||||
formData.category = row.category || ''
|
||||
formData.specModel = row.specModel || ''
|
||||
formData.unit = row.unit || ''
|
||||
formData.status = row.status || '1'
|
||||
formData.remark = row.remark || ''
|
||||
dialogVisible.value = true
|
||||
formRef.value?.clearValidate?.()
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
await formRef.value?.validate?.()
|
||||
submitLoading.value = true
|
||||
try {
|
||||
const payload = {
|
||||
materialCode: formData.materialCode.trim(),
|
||||
materialName: formData.materialName.trim(),
|
||||
category: formData.category || undefined,
|
||||
specModel: formData.specModel?.trim() || undefined,
|
||||
unit: formData.unit?.trim() || undefined,
|
||||
status: formData.status,
|
||||
remark: formData.remark?.trim() || undefined
|
||||
}
|
||||
if (isEdit.value && editingId.value) {
|
||||
await fetchUpdateMaterial(editingId.value, payload)
|
||||
} else {
|
||||
await fetchCreateMaterial(payload)
|
||||
}
|
||||
ElMessage.success(isEdit.value ? '更新成功' : '创建成功')
|
||||
dialogVisible.value = false
|
||||
await loadData()
|
||||
} catch {
|
||||
/* 校验或接口错误已由全局处理 */
|
||||
} finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleView(row: Material) {
|
||||
viewRow.value = row
|
||||
viewVisible.value = true
|
||||
}
|
||||
|
||||
async function handleDelete(row: Material) {
|
||||
await ElMessageBox.confirm('确定要删除该物料吗?', '提示', { type: 'warning' })
|
||||
await fetchDeleteMaterial(row.id)
|
||||
ElMessage.success('删除成功')
|
||||
await loadData()
|
||||
}
|
||||
|
||||
function handleStockIn(row: Material) {
|
||||
stockInMaterialId.value = row.id
|
||||
stockInForm.qty = 1
|
||||
stockInForm.remark = ''
|
||||
stockInVisible.value = true
|
||||
stockInFormRef.value?.clearValidate?.()
|
||||
}
|
||||
|
||||
async function handleStockInSubmit() {
|
||||
await stockInFormRef.value?.validate?.()
|
||||
stockInLoading.value = true
|
||||
try {
|
||||
await fetchStockInMaterial(stockInMaterialId.value!, {
|
||||
qty: stockInForm.qty,
|
||||
remark: stockInForm.remark?.trim() || undefined
|
||||
})
|
||||
ElMessage.success('入库成功')
|
||||
stockInVisible.value = false
|
||||
await loadData()
|
||||
} catch {
|
||||
/* 校验或接口错误已由全局处理 */
|
||||
} finally {
|
||||
stockInLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleStockOut(row: Material) {
|
||||
stockOutMaterialId.value = row.id
|
||||
stockOutStockQty.value = row.stockQty ?? 0
|
||||
stockOutForm.qty = 1
|
||||
stockOutForm.receiver = ''
|
||||
stockOutForm.purpose = ''
|
||||
stockOutForm.remark = ''
|
||||
stockOutVisible.value = true
|
||||
stockOutFormRef.value?.clearValidate?.()
|
||||
}
|
||||
|
||||
async function handleStockOutSubmit() {
|
||||
await stockOutFormRef.value?.validate?.()
|
||||
if (stockOutForm.qty > stockOutStockQty.value) {
|
||||
ElMessage.warning(`出库数量不能超过当前库存 (${stockOutStockQty.value})`)
|
||||
return
|
||||
}
|
||||
stockOutLoading.value = true
|
||||
try {
|
||||
await fetchStockOutMaterial(stockOutMaterialId.value!, {
|
||||
qty: stockOutForm.qty,
|
||||
receiver: stockOutForm.receiver?.trim() || undefined,
|
||||
purpose: stockOutForm.purpose?.trim() || undefined,
|
||||
remark: stockOutForm.remark?.trim() || undefined
|
||||
})
|
||||
ElMessage.success('出库成功')
|
||||
stockOutVisible.value = false
|
||||
await loadData()
|
||||
} catch {
|
||||
/* 校验或接口错误已由全局处理 */
|
||||
} finally {
|
||||
stockOutLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadDictOptions()
|
||||
loadData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.material-dialog-form {
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">缴费确认列表</h2>
|
||||
<h2>缴费确认列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="list-body list-wrap payment-confirm-table-wrap">
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">缴费信息列表</h2>
|
||||
<h2>缴费信息列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">协议单列表</h2>
|
||||
<h2>协议单列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">协议单列表</h2>
|
||||
<h2>协议单列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">退费确认列表</h2>
|
||||
<h2>退费确认列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="list-body list-wrap refund-confirm-table-wrap">
|
||||
|
||||
@@ -0,0 +1,460 @@
|
||||
<!-- 储存证管理 -->
|
||||
<!-- eslint-disable vue/no-v-model-argument -->
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<header class="page-head">
|
||||
<h1>储存证管理</h1>
|
||||
<p class="page-desc">管理细胞储存协议的储存证制作与查看。</p>
|
||||
</header>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">储存证列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
<el-form :model="searchForm" class="filter-form" @submit.prevent>
|
||||
<div class="filter-grid">
|
||||
<el-form-item label="关键词">
|
||||
<el-input v-model="searchForm.keyword" placeholder="协议号/姓名" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="制作状态">
|
||||
<el-select v-model="searchForm.makeStatus" placeholder="全部" clearable style="width: 100%">
|
||||
<el-option label="未制作" value="0" />
|
||||
<el-option label="已制作" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset">
|
||||
<el-icon><RefreshLeft /></el-icon>重置
|
||||
</el-button>
|
||||
<el-button class="btn-main" type="primary" @click="handleSearch">
|
||||
<el-icon><Search /></el-icon>搜索
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="list-body list-wrap">
|
||||
<el-table
|
||||
class="list-table"
|
||||
:data="tableData"
|
||||
v-loading="loading"
|
||||
stripe
|
||||
row-key="id"
|
||||
>
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
width="68"
|
||||
align="center"
|
||||
header-align="center"
|
||||
:index="(i) => (pagination.page - 1) * pagination.pageSize + i + 1"
|
||||
/>
|
||||
<el-table-column prop="protocolNo" label="采集协议号" width="160" align="center" header-align="center" />
|
||||
<el-table-column prop="motherName" label="母亲姓名" width="100" align="center" header-align="center" />
|
||||
<el-table-column prop="newbornDeliveryTime" label="新生儿分娩时间" width="140" align="center" header-align="center" />
|
||||
<el-table-column prop="sampleInfo" label="样本信息" min-width="180" align="center" header-align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="storageInDate" label="入库日期" width="120" align="center" header-align="center" />
|
||||
<el-table-column prop="makeStatus" label="制作状态" width="100" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.makeStatus == '1' ? 'success' : 'warning'" size="small">
|
||||
{{ row.makeStatus == '1' ? '已制作' : '未制作' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="makeDate" label="制作日期" width="120" align="center" header-align="center" />
|
||||
<el-table-column label="操作" width="200" fixed="right" align="center" header-align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button class="btn-op-item primary" @click="handleUpload(row)">
|
||||
<el-icon><Upload /></el-icon>上传储存证
|
||||
</el-button>
|
||||
<el-button class="btn-op-item" @click="handleView(row)">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination list-pager-bar">
|
||||
<el-pagination
|
||||
:current-page="pagination.page"
|
||||
:page-size="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
@size-change="(val) => ((pagination.page = 1), (pagination.pageSize = val), loadData())"
|
||||
@current-change="(val) => ((pagination.page = val), loadData())"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 上传储存证弹窗 -->
|
||||
<el-dialog
|
||||
v-model="uploadDialogVisible"
|
||||
title="上传储存证"
|
||||
width="640px"
|
||||
class="dialog-form-layout"
|
||||
align-center
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form
|
||||
ref="uploadFormRef"
|
||||
:model="uploadForm"
|
||||
:rules="uploadFormRules"
|
||||
label-position="top"
|
||||
class="storage-cert-dialog-form"
|
||||
scroll-to-error
|
||||
:scroll-into-view-options="{ behavior: 'smooth', block: 'center' }"
|
||||
>
|
||||
<div class="form-grid-2">
|
||||
<el-form-item label="采集协议号">
|
||||
<el-input :model-value="uploadRow?.protocolNo" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="母亲姓名">
|
||||
<el-input :model-value="uploadRow?.motherName" disabled />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label="储存证图片" prop="certImageUrls">
|
||||
<el-upload
|
||||
v-model:file-list="uploadFileList"
|
||||
action=""
|
||||
:auto-upload="false"
|
||||
list-type="picture-card"
|
||||
accept="image/*"
|
||||
:limit="9"
|
||||
:on-exceed="() => ElMessage.warning('最多上传 9 张图片')"
|
||||
>
|
||||
<el-icon><Plus /></el-icon>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<div class="form-grid-2">
|
||||
<el-form-item label="制作日期" prop="makeDate">
|
||||
<el-date-picker
|
||||
v-model="uploadForm.makeDate"
|
||||
type="date"
|
||||
format="YYYYMMDD"
|
||||
value-format="YYYYMMDD"
|
||||
placeholder="选择日期"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="uploadForm.remark" type="textarea" :rows="2" placeholder="可选" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button class="btn-ghost" @click="uploadDialogVisible = false">
|
||||
<el-icon><Close /></el-icon>取消
|
||||
</el-button>
|
||||
<el-button class="btn-main" type="primary" :loading="submitLoading" @click="handleSubmitUpload">
|
||||
<el-icon><Check /></el-icon>确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 查看弹窗 -->
|
||||
<el-dialog
|
||||
v-model="viewDialogVisible"
|
||||
title="查看储存证"
|
||||
width="720px"
|
||||
class="dialog-form-layout"
|
||||
align-center
|
||||
destroy-on-close
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<div class="view-info-grid">
|
||||
<div class="view-info-item">
|
||||
<span class="view-label">采集协议号</span>
|
||||
<span class="view-value">{{ viewRow?.protocolNo || '—' }}</span>
|
||||
</div>
|
||||
<div class="view-info-item">
|
||||
<span class="view-label">母亲姓名</span>
|
||||
<span class="view-value">{{ viewRow?.motherName || '—' }}</span>
|
||||
</div>
|
||||
<div class="view-info-item">
|
||||
<span class="view-label">新生儿分娩时间</span>
|
||||
<span class="view-value">{{ viewRow?.newbornDeliveryTime || '—' }}</span>
|
||||
</div>
|
||||
<div class="view-info-item">
|
||||
<span class="view-label">样本信息</span>
|
||||
<span class="view-value">{{ viewRow?.sampleInfo || '—' }}</span>
|
||||
</div>
|
||||
<div class="view-info-item">
|
||||
<span class="view-label">入库日期</span>
|
||||
<span class="view-value">{{ viewRow?.storageInDate || '—' }}</span>
|
||||
</div>
|
||||
<div class="view-info-item">
|
||||
<span class="view-label">制作状态</span>
|
||||
<span class="view-value">
|
||||
<el-tag :type="viewRow?.makeStatus == '1' ? 'success' : 'warning'" size="small">
|
||||
{{ viewRow?.makeStatus == '1' ? '已制作' : '未制作' }}
|
||||
</el-tag>
|
||||
</span>
|
||||
</div>
|
||||
<div class="view-info-item">
|
||||
<span class="view-label">制作日期</span>
|
||||
<span class="view-value">{{ viewRow?.makeDate || '—' }}</span>
|
||||
</div>
|
||||
<div class="view-info-item">
|
||||
<span class="view-label">备注</span>
|
||||
<span class="view-value">{{ viewRow?.remark || '—' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="viewCertImages.length" class="view-cert-images">
|
||||
<div class="view-cert-label">储存证图片</div>
|
||||
<div class="view-cert-grid">
|
||||
<el-image
|
||||
v-for="(url, idx) in viewCertImages"
|
||||
:key="idx"
|
||||
:src="url"
|
||||
:preview-src-list="viewCertImages"
|
||||
:initial-index="idx"
|
||||
fit="cover"
|
||||
class="view-cert-img"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button class="btn-ghost" @click="viewDialogVisible = false">
|
||||
<el-icon><Close /></el-icon>关闭
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import type { UploadUserFile } from 'element-plus'
|
||||
import {
|
||||
Plus,
|
||||
Close,
|
||||
Check,
|
||||
Search,
|
||||
RefreshLeft,
|
||||
View,
|
||||
Upload
|
||||
} from '@element-plus/icons-vue'
|
||||
import { fetchStorageCertList } from '@/api/admin'
|
||||
import { fetchUpdateCollectionProtocol } from '@/api/collection-protocol'
|
||||
import { fetchUploadAttachment } from '@/api/business'
|
||||
|
||||
defineOptions({ name: 'CellStorageStorageCert' })
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 搜索 & 主表
|
||||
// ---------------------------------------------------------------------------
|
||||
const searchForm = reactive({ keyword: '', makeStatus: '' })
|
||||
const tableData = ref<any[]>([])
|
||||
const loading = ref(false)
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 上传弹窗
|
||||
// ---------------------------------------------------------------------------
|
||||
const uploadDialogVisible = ref(false)
|
||||
const uploadRow = ref<any>(null)
|
||||
const uploadFormRef = ref()
|
||||
const uploadFileList = ref<UploadUserFile[]>([])
|
||||
const submitLoading = ref(false)
|
||||
const uploadForm = reactive({
|
||||
makeDate: '',
|
||||
remark: ''
|
||||
})
|
||||
const uploadFormRules = {
|
||||
certImageUrls: [{ required: true, message: '请上传储存证图片', trigger: 'change' }],
|
||||
makeDate: [{ required: true, message: '请选择制作日期', trigger: 'change' }]
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 查看弹窗
|
||||
// ---------------------------------------------------------------------------
|
||||
const viewDialogVisible = ref(false)
|
||||
const viewRow = ref<any>(null)
|
||||
const viewCertImages = computed(() => {
|
||||
if (!viewRow.value?.certImageUrls) return []
|
||||
return viewRow.value.certImageUrls
|
||||
.split(',')
|
||||
.map((u: string) => u.trim())
|
||||
.filter(Boolean)
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 数据加载
|
||||
// ---------------------------------------------------------------------------
|
||||
async function loadData() {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await fetchStorageCertList({
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
makeStatus: searchForm.makeStatus || undefined
|
||||
})
|
||||
tableData.value = (res as any)?.list || []
|
||||
pagination.total = (res as any)?.total ?? 0
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
searchForm.keyword = ''
|
||||
searchForm.makeStatus = ''
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 上传储存证
|
||||
// ---------------------------------------------------------------------------
|
||||
function handleUpload(row: any) {
|
||||
uploadRow.value = row
|
||||
uploadFileList.value = []
|
||||
uploadForm.makeDate = getTodayStr()
|
||||
uploadForm.remark = ''
|
||||
uploadDialogVisible.value = true
|
||||
}
|
||||
|
||||
async function handleSubmitUpload() {
|
||||
// 手动校验图片
|
||||
if (uploadFileList.value.length === 0) {
|
||||
ElMessage.warning('请上传储存证图片')
|
||||
return
|
||||
}
|
||||
const valid = await uploadFormRef.value?.validate?.().catch(() => false)
|
||||
if (!valid) return
|
||||
|
||||
submitLoading.value = true
|
||||
try {
|
||||
// 1. 逐个上传图片文件
|
||||
const uploadedUrls: string[] = []
|
||||
for (const f of uploadFileList.value) {
|
||||
const file = f.raw
|
||||
if (!file) continue
|
||||
const fd = new FormData()
|
||||
fd.append('business_type', 'storage_cert')
|
||||
fd.append('business_id', uploadRow.value?.protocolId || 'temp')
|
||||
fd.append('file', file)
|
||||
const res: any = await fetchUploadAttachment(fd)
|
||||
if (res?.fileUrl) {
|
||||
uploadedUrls.push(res.fileUrl)
|
||||
}
|
||||
}
|
||||
const existingUrls = uploadRow.value?.certImageUrls || ''
|
||||
const finalUrls = [existingUrls, ...uploadedUrls].filter(Boolean).join(',')
|
||||
|
||||
// 2. 调用协议更新接口保存储存证数据
|
||||
await fetchUpdateCollectionProtocol(uploadRow.value.protocolId, {
|
||||
storageCert: {
|
||||
makeStatus: '1',
|
||||
certImageUrls: finalUrls,
|
||||
makeDate: uploadForm.makeDate,
|
||||
remark: uploadForm.remark?.trim() || undefined
|
||||
}
|
||||
})
|
||||
|
||||
ElMessage.success('上传成功')
|
||||
uploadDialogVisible.value = false
|
||||
await loadData()
|
||||
} catch {
|
||||
/* 全局已处理 */
|
||||
} finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 查看储存证
|
||||
// ---------------------------------------------------------------------------
|
||||
function handleView(row: any) {
|
||||
viewRow.value = row
|
||||
viewDialogVisible.value = true
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 工具函数
|
||||
// ---------------------------------------------------------------------------
|
||||
function getTodayStr(): string {
|
||||
const d = new Date()
|
||||
const yyyy = d.getFullYear()
|
||||
const mm = String(d.getMonth() + 1).padStart(2, '0')
|
||||
const dd = String(d.getDate()).padStart(2, '0')
|
||||
return `${yyyy}${mm}${dd}`
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.storage-cert-dialog-form {
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.view-info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px 24px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.view-info-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.view-label {
|
||||
font-size: 12px;
|
||||
color: var(--mint-text-muted, #909399);
|
||||
}
|
||||
|
||||
.view-value {
|
||||
font-size: 14px;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.view-cert-images {
|
||||
border-top: 1px solid var(--el-border-color-lighter, #ebeef5);
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.view-cert-label {
|
||||
font-size: 13px;
|
||||
color: var(--mint-text-muted, #909399);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.view-cert-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.view-cert-img {
|
||||
width: 120px;
|
||||
height: 96px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--el-border-color-lighter, #ebeef5);
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">快速入口</h2>
|
||||
<h2>快速入口</h2>
|
||||
</div>
|
||||
<div class="console-lite__body">
|
||||
<p class="console-lite__hint">详见仓库根目录 `.cursorrules` 中「页面级 UI 模板(固定五页)」。</p>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">洁净室列表</h2>
|
||||
<h2>洁净室列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">选择项</h2>
|
||||
<h2>选择项</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">预约列表</h2>
|
||||
<h2>预约列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<!-- 左侧:库位树 -->
|
||||
<div class="w-[280px] shrink-0 border-r border-[var(--mint-border)] pr-4">
|
||||
<div class="panel-top storage-aside__head">
|
||||
<h2 class="title-bar-heading">库位树</h2>
|
||||
<h2>库位树</h2>
|
||||
<el-button type="primary" size="small" @click="handleAddRoot">
|
||||
<el-icon><Plus /></el-icon>
|
||||
新增
|
||||
@@ -62,7 +62,7 @@
|
||||
<template v-else-if="selectedNode.isLeaf !== 1">
|
||||
<div class="storage-content-header">
|
||||
<div>
|
||||
<h3 class="title-bar-heading">
|
||||
<h3>
|
||||
{{
|
||||
buildTreePathLabelFromFlat(selectedNode.id, flatList, { nameKey: 'nodeName' })
|
||||
}}
|
||||
@@ -76,7 +76,7 @@
|
||||
<template v-else>
|
||||
<div class="storage-content-header">
|
||||
<div>
|
||||
<h3 class="title-bar-heading">
|
||||
<h3>
|
||||
{{
|
||||
buildTreePathLabelFromFlat(selectedNode.id, flatList, { nameKey: 'nodeName' })
|
||||
}}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">价格列表</h2>
|
||||
<h2>价格列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">规格列表</h2>
|
||||
<h2>规格列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">类型列表</h2>
|
||||
<h2>类型列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">渠道列表</h2>
|
||||
<h2>渠道列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">机构列表</h2>
|
||||
<h2>机构列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">体系列表</h2>
|
||||
<h2>体系列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">产品列表</h2>
|
||||
<h2>产品列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">耗材包列表</h2>
|
||||
<h2>耗材包列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">耗材列表</h2>
|
||||
<h2>耗材列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">类型列表</h2>
|
||||
<h2>类型列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">分类列表</h2>
|
||||
<h2>分类列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">路线列表</h2>
|
||||
<h2>路线列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">工艺列表</h2>
|
||||
<h2>工艺列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<!-- ========== 列表视图 ========== -->
|
||||
<template v-if="currentView === 'list'">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">任务列表</h2>
|
||||
<h2>任务列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
@@ -95,7 +95,7 @@
|
||||
<div class="task-detail-header">
|
||||
<div class="task-detail-header-info">
|
||||
<div class="task-detail-title-row">
|
||||
<h2 class="title-bar-heading">任务执行</h2>
|
||||
<h2>任务执行</h2>
|
||||
<el-tag v-if="taskDetail" :type="taskStatusTag(taskDetail.taskStatus).type" size="large">
|
||||
{{ taskStatusTag(taskDetail.taskStatus).label }}
|
||||
</el-tag>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">工单列表</h2>
|
||||
<h2>工单列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">试剂列表</h2>
|
||||
<h2>试剂列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">SOP列表</h2>
|
||||
<h2>SOP列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">项目列表</h2>
|
||||
<h2>项目列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">工单列表</h2>
|
||||
<h2>工单列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">接收检查项列表</h2>
|
||||
<h2>接收检查项列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">样本接收列表</h2>
|
||||
<h2>样本接收列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">公司列表</h2>
|
||||
<h2>公司列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">捐赠协议单列表</h2>
|
||||
<h2>捐赠协议单列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">捐赠协议单列表</h2>
|
||||
<h2>捐赠协议单列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">分类列表</h2>
|
||||
<h2>分类列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">组织管理</h2>
|
||||
<h2>组织管理</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">字典类型</h2>
|
||||
<h2>字典类型</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">快递公司列表</h2>
|
||||
<h2>快递公司列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">请假列表</h2>
|
||||
<h2>请假列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">菜单列表</h2>
|
||||
<h2>菜单列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">订单列表</h2>
|
||||
<h2>订单列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">职位列表</h2>
|
||||
<h2>职位列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</header>
|
||||
<div class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">商品列表</h2>
|
||||
<h2>商品列表</h2>
|
||||
</div>
|
||||
<div class="filter-block">
|
||||
<el-form :model="searchForm" class="filter-form" @submit.prevent>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">角色列表</h2>
|
||||
<h2>角色列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">站点列表</h2>
|
||||
<h2>站点列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">租户列表</h2>
|
||||
<h2>租户列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">单位列表</h2>
|
||||
<h2>单位列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="w-[280px] shrink-0 border-r border-[var(--mint-border)] pr-4">
|
||||
<!-- 标题与搜索同处 panel-top:避免标题栏底边与独立输入框之间出现不可控的视觉断层 -->
|
||||
<div class="panel-top user-dept-aside__head">
|
||||
<h2 class="title-bar-heading">组织</h2>
|
||||
<h2>组织</h2>
|
||||
<el-input v-model="deptKeyword" placeholder="搜索组织" clearable />
|
||||
</div>
|
||||
<el-tree
|
||||
@@ -32,7 +32,7 @@
|
||||
<!-- 右侧:用户列表 -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">用户列表</h2>
|
||||
<h2>用户列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">申请列表</h2>
|
||||
<h2>申请列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">流程列表</h2>
|
||||
<h2>流程列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">已办列表</h2>
|
||||
<h2>已办列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">待办列表</h2>
|
||||
<h2>待办列表</h2>
|
||||
</div>
|
||||
|
||||
<div class="filter-block">
|
||||
|
||||
Reference in new issue
Block a user