代码整合

This commit is contained in:
wuyy 2026-03-09 18:04:16 +08:00
parent 0cdc3bdee2
commit 375f509bee
53 changed files with 10601 additions and 1564 deletions

126
src/api/checkCode/index.ts Normal file
View File

@ -0,0 +1,126 @@
//@ts-ignore js语法检查忽略
import request from '@/utils/request';
// 生成条码
export function addObj(query?: Object) {
return request({
url: 'zyreq/add',
method: 'get',
params: query,
});
}
// 查询申请单列表
export function fetchCodeList(query?: Object) {
return request({
url: '/zyreq/query',
method: 'get',
params: query,
});
}
// 查询项目
export function fetchCodeDetail(query?: Object) {
return request({
url: 'zyreq/detail',
method: 'get',
params: query,
});
}
// 执行条码
export function fetchCodeExec(query?: Object) {
return request({
url: '/zyreq/exec',
method: 'get',
params: query,
});
}
// 执行条码
export function printSendSample(query?: Object) {
return request({
url: '/zyreq/printSendSample',
method: 'post',
data: query,
});
}
// 获取申请单主表信息
export function fetchCodeReqmain(query?: Object) {
return request({
url: 'zyreq/reqmain',
method: 'get',
params: query,
});
}
// 查询报告单列表
export function reportList(query?: Object) {
return request({
url: '/report/ReportList',
method: 'post',
data: query,
});
}
// 查询报告Pdf预览
export function reportViewPdf(query?: Object) {
return request({
url: '/report/pdf',
method: 'get',
params: query,
});
}
// 查询报告Pdf打印
export function reportPrintPdf(query?: Object) {
return request({
url: '/report/print',
method: 'post',
data: query,
});
}
// 查询项目报告
export function reportResult(query?: Object) {
return request({
url: '/report/result',
method: 'post',
data: query,
});
}
// 查询微生物报告
export function reportMedList(query?: Object) {
return request({
url: '/report/MedList',
method: 'post',
data: query,
});
}
// 查询微生物报告
export function reportFsresult(query?: Object) {
return request({
url: '/report/fsresult',
method: 'post',
data: query,
});
}
// 打印机插件检查
export function printcheck(query?: Object) {
return request({
url: '/zyreq/printcheck',
method: 'get',
params: query,
});
}
// 打印机插件设置
export function printsetup(query?: Object) {
return request({
url: '/zyreq/printsetup',
method: 'get',
params: query,
});
}
// 取消采样
export function cancelExecSQD(query?: Object) {
return request({
url: '/zyreq/cancelExecSQD',
method: 'post',
data: query,
});
}

View File

@ -0,0 +1,46 @@
//参数设置字典
// @ts-ignore
import request from '@/utils/request'
// 查询字典列表
export function listconfigdict(params:any) {
return request({
url: '/configdict/list',
method: 'get',
params
})
}
// 查询字典详细
export function getconfigdict(id:number) {
return request({
url: `/configdict/${id}`,
method: 'get'
})
}
// 新增字典
export function addconfigdict(params:any) {
return request({
url: '/configdict',
method: 'post',
data:params
})
}
// 修改字典
export function updateconfigdict(params:any) {
return request({
url: '/configdict',
method: 'put',
data:params
})
}
// 删除字典
export function delconfigdict(id:any) {
return request({
url: `/configdict/${id}`,
method: 'delete'
})
}

View File

@ -20,6 +20,15 @@ export function login(username: string, password: string, code: string, uuid: st
})
}
// 单点登录
export function loginAnonymous(data: { username: string; yljg: string }): Promise<LoginInfoResult> {
return request({
url: '/loginAnonymous',
method: 'post',
data: data
})
}
// 注册方法
export function register(data: SysRegister): Promise<AjaxResult> {
return request({

58
src/api/mzcx/cydj.ts Normal file
View File

@ -0,0 +1,58 @@
import request from '@/utils/request'
// 查询采样登记列表
export function querySQD(query: Object) {
return request({
url: '/mzcx/querySQD',
method: 'get',
params: query
})
}
// 查询采样登记列表
export function printBarcode(query: Object) {
return request({
url: '/mzcx/printBarcode',
method: 'get',
params: query
})
}
export function printBarcodeall(data: Object) {
return request({
url: '/mzcx/printBarcode',
method: 'post',
data: data
})
}
// 查询病人列表
export function queryPatList() {
return request({
url: '/mzcx/queryPatList',
method: 'get'
})
}
// 打印回单
export function printBackpaper(data: Object) {
return request({
url: '/mzcx/printBackpaper',
method: 'post',
data: data
})
}
// 修改采样登记
export function updateReqmain(data: Object) {
return request({
url: '/system/reqmain',
method: 'put',
data: data
})
}
// 删除采样登记
export function delReqmain(sqh: string) {
return request({
url: '/system/reqmain/' + sqh,
method: 'delete'
})
}

155
src/api/mzcx/index.ts Normal file
View File

@ -0,0 +1,155 @@
//@ts-ignore js语法检查忽略
import request from '@/utils/request';
// 查询条码类别
export function feeitemclassList(query?: Object) {
return request({
url: 'feeitemclass/query',
method: 'get',
params: query,
});
}
// 报告领取规则
export function rptgetrules(query?: Object) {
return request({
url: '/rptgetrule/query',
method: 'get',
params: query,
});
}
// 新增条码类别
export function feeitemclassAdd(query?: Object) {
return request({
url: '/feeitemclass/add',
method: 'post',
data: query,
});
}
// 修改条码类别
export function feeitemclassUpdate(query?: Object) {
return request({
url: '/feeitemclass/update',
method: 'post',
data: query,
});
}
// 删除条码类别
export function feeitemclassDel(query?: Object) {
return request({
url: '/feeitemclass/del',
method: 'delete',
params: query,
});
}
// 收费项目维护列表
export function xmfeeList(query?: Object) {
return request({
url: 'xmfee/query',
method: 'get',
params: query,
});
}
// 收费项目新增
export function xmfeeadd(query?: Object) {
return request({
url: 'xmfee/addXmfee',
method: 'post',
data: query,
});
}
// 收费项目修改
export function xmfeeUpdate(query?: Object) {
return request({
url: 'xmfee/update',
method: 'post',
data: query,
});
}
// 收费项目删除
export function xmfeeDel(query?: Object) {
return request({
url: 'xmfee/del',
method: 'delete',
params: query,
});
}
// 报告领取规则维护列表
export function rptgetruleList(query?: Object) {
return request({
url: 'rptgetrule/query',
method: 'get',
params: query,
});
}
// 报告领取规则明细列表
export function rptgetruleDetail(query?: Object) {
return request({
url: 'rptgetrule/queryDetail',
method: 'get',
params: query,
});
}
// 报告领取规则新增
export function rptgetruleadd(query?: Object) {
return request({
url: 'rptgetrule/add',
method: 'post',
data: query,
});
}
// 报告领取规则修改
export function rptgetruleUpdate(query?: Object) {
return request({
url: 'rptgetrule/update',
method: 'post',
data: query,
});
}
// 报告领取规则删除
export function rptgetruleDel(query?: Object) {
return request({
url: 'rptgetrule/del',
method: 'delete',
params: query,
});
}
// 报告领取规则明细删除
export function rptgetruleDelDetail(query?: Object) {
return request({
url: 'rptgetrule/delDetail',
method: 'delete',
params: query,
});
}
// 查询条码类别与项目对照
export function feeitemvsList(query?: Object) {
return request({
url: '/feeitemvsclass/query',
method: 'get',
params: query,
});
}
// 保存对照的项目
export function feeitemvAdd(query?: Object) {
return request({
url: '/feeitemvsclass/add',
method: 'post',
data: query,
});
}
// 保存对照的项目
export function feeitemvDel(query?: Object) {
return request({
url: '/feeitemvsclass/del',
method: 'delete',
params: query,
});
}

View File

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询诊断列表
export function listdiagnosis(query) {
return request({
url: '/transitdict/diagnosis/list',
method: 'get',
params: query
})
}
// 查询诊断详细
export function getdiagnosis(diagnosisId) {
return request({
url: '/transitdict/diagnosis/' + diagnosisId,
method: 'get'
})
}
// 新增诊断
export function adddiagnosis(data) {
return request({
url: '/transitdict/diagnosis',
method: 'post',
data: data
})
}
// 修改诊断
export function updatediagnosis(data) {
return request({
url: '/transitdict/diagnosis',
method: 'put',
data: data
})
}
// 删除诊断
export function deldiagnosis(diagnosisId) {
return request({
url: '/transitdict/diagnosis/' + diagnosisId,
method: 'delete'
})
}

View File

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询医疗机构列表
export function listhospital(query) {
return request({
url: '/transitdict/hospital/list',
method: 'get',
params: query
})
}
// 查询医疗机构详细
export function gethospital(hospitalId) {
return request({
url: '/transitdict/hospital/' + hospitalId,
method: 'get'
})
}
// 新增医疗机构
export function addhospital(data) {
return request({
url: '/transitdict/hospital',
method: 'post',
data: data
})
}
// 修改医疗机构
export function updatehospital(data) {
return request({
url: '/transitdict/hospital',
method: 'put',
data: data
})
}
// 删除医疗机构
export function delhospital(hospitalId) {
return request({
url: '/transitdict/hospital/' + hospitalId,
method: 'delete'
})
}

View File

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询诊断列表
export function listitemclass(query) {
return request({
url: '/transitdict/itemclass/list',
method: 'get',
params: query
})
}
// 查询诊断详细
export function getitemclass(itemclassId) {
return request({
url: '/transitdict/itemclass/' + itemclassId,
method: 'get'
})
}
// 新增诊断
export function additemclass(data) {
return request({
url: '/transitdict/itemclass',
method: 'post',
data: data
})
}
// 修改诊断
export function updateitemclass(data) {
return request({
url: '/transitdict/itemclass',
method: 'put',
data: data
})
}
// 删除诊断
export function delitemclass(itemclassId) {
return request({
url: '/transitdict/itemclass/' + itemclassId,
method: 'delete'
})
}

View File

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询字典列表
export function listregdict(query) {
return request({
url: '/transitdict/regdict/list',
method: 'get',
params: query
})
}
// 查询字典详细
export function getregdict(regdictId) {
return request({
url: '/transitdict/regdict/' + regdictId,
method: 'get'
})
}
// 新增字典
export function addregdict(data) {
return request({
url: '/transitdict/regdict',
method: 'post',
data: data
})
}
// 修改字典
export function updateregdict(data) {
return request({
url: '/transitdict/regdict',
method: 'put',
data: data
})
}
// 删除字典
export function delregdict(regdictId) {
return request({
url: '/transitdict/regdict/' + regdictId,
method: 'delete'
})
}

59
src/api/regional/index.ts Normal file
View File

@ -0,0 +1,59 @@
// @ts-ignore
import request from '@/utils/request'
// 获取流转数据
export function querySample(query?: Object) {
return request({
url: '/transit/querySample',
method: 'get',
params: query
})
}
// 获取未签收的标本
export function querySampleSign(query?: Object) {
return request({
url: '/transit/querySampleSign',
method: 'get',
params: query
})
}
// 签收标本
export function sampleSign(query?: Object) {
return request({
url: '/transit/sampleSign',
method: 'post',
data: query
})
}
// 退回的标本
export function querySampleSignBack(query?: Object) {
return request({
url: '/transit/querySampleSignBack',
method: 'get',
params: query
})
}
// 标本报表
export function sampleTypeCount(query?: Object) {
return request({
url: '/transitReport/sampleTypeCount',
method: 'get',
params: query
})
}
// 标本报表费用
export function sampleitemCount(query?: Object) {
return request({
url: '/transitReport/itemCount',
method: 'get',
params: query
})
}
// 标本报表费用
export function getallcount(query?: Object) {
return request({
url: '/transitstat/getallcount',
method: 'get',
params: query
})
}

BIN
src/assets/images/xjt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
src/assets/images/yjt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -47,6 +47,12 @@ export const constantRoutes = [
component: () => import('@/views/register.vue'),
hidden: true
},
// 大屏
{
path: '/regional/statistics/overview',
component: () => import('@/views/regional/statistics/overview/index.vue'),
hidden: true
},
{
path: "/:pathMatch(.*)*",
component: () => import('@/views/error/404.vue'),

View File

@ -0,0 +1,36 @@
// 打印状态管理
import { defineStore } from 'pinia'
export const usePrintStore = defineStore('printStore', {
state: () => ({
isConnected: false, // 存储连接状态
clientInfo: null, // 存储客户端信息
printerList: [] as any[], // 存储打印机列表
defaultPrinter: '' as string, // 存储默认打印机名称
}),
actions: {
setConnected(status: boolean) {
this.isConnected = status
},
setClientInfo(info: any) {
this.clientInfo = info
},
setPrinterList(list: any[]) {
this.printerList = list
},
setDefaultPrinter(printerName: string) {
this.defaultPrinter = printerName
}
},
// 持久化配置
persist: {
// 指定要持久化的状态字段
pick: ['defaultPrinter',],
// 可选配置:自定义存储键名(默认是store的id)
// key: 'common_store',
// 可选配置:指定存储位置(默认是localStorage 也可以用sessionStorage)
storage: localStorage,
}
})

View File

@ -1,6 +1,6 @@
import router from '@/router'
import { ElMessageBox } from 'element-plus'
import { login, logout, getInfo } from '@/api/login'
import { login, logout, getInfo, loginAnonymous } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth'
import { isHttp, isEmpty } from "@/utils/validate"
import defAva from '@/assets/images/profile.jpg'
@ -28,6 +28,24 @@ const useUserStore = defineStore(
permissions: []
}),
actions: {
// 单点登录
loginAnonymous(data: { name: string; yljg: string }) {
return new Promise((resolve, reject) => {
loginAnonymous({
username: data.name,
yljg: data.yljg
}).then(res => {
if (res.code == 200) {
setToken(res.token)
this.token = res.token
resolve(true)
}
}).catch(error => {
reject(error)
})
})
},
// 登录
login(userInfo: { username: string; password: string; code: string; uuid: string }) {
const username = userInfo.username.trim()
@ -64,16 +82,16 @@ const useUserStore = defineStore(
this.nickName = user.nickName || ''
this.avatar = avatar
/* 初始密码提示 */
if(res.isDefaultModifyPwd) {
ElMessageBox.confirm('您的密码还是初始密码,请修改密码!', '安全提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => {
if (res.isDefaultModifyPwd) {
ElMessageBox.confirm('您的密码还是初始密码,请修改密码!', '安全提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => {
router.push({ name: 'Profile', params: { activeTab: 'resetPwd' } })
}).catch(() => {})
}).catch(() => { })
}
/* 过期密码提示 */
if(!res.isDefaultModifyPwd && res.isPasswordExpired) {
ElMessageBox.confirm('您的密码已过期,请尽快修改密码!', '安全提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => {
if (!res.isDefaultModifyPwd && res.isPasswordExpired) {
ElMessageBox.confirm('您的密码已过期,请尽快修改密码!', '安全提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => {
router.push({ name: 'Profile', params: { activeTab: 'resetPwd' } })
}).catch(() => {})
}).catch(() => { })
}
resolve(res)
}).catch(error => {

50
src/utils/printHelper.ts Normal file
View File

@ -0,0 +1,50 @@
/**
* @file printHelper.ts 检查打印服务连接状态
* @author: w
* @since: 2026-01-26
*/
import { ElMessageBox, ElMessage } from 'element-plus'
import { printcheck } from '@/api/checkCode/index'
// @ts-ignore
import Download from '@/plugins/download'
export const checkPrintService = async (): Promise<boolean> => { //连接成功返回true,失败返回false
try {
const res = await printcheck()
if (res.code == 0) {
return true
} else {
await showPrintServiceError(res.msg)
return false
}
} catch (error) {
console.error('打印服务检查失败:', error)
await showPrintServiceError('打印服务连接异常')
return false
}
}
export const showPrintServiceError = async (msg: string) => {
// 挂载downExe方法到window,供提示框内的onclick调用
if (!(window as any).downExe) {
(window as any).downExe = () => {
Download.name('lisprintsetup.exe', false)
}
}
await ElMessageBox.alert(
`${msg}!<br>请确保目标服务器已<a style="color: #1f79db" onclick="downExe()">下载安装</a> 并运行打印服务!`,
"客户端未连接",
{
dangerouslyUseHTMLString: true,
}
)
}
//触发打印服务安装包下载
export const downloadPrintSetup = () => {
Download.name('lisprintsetup.exe', false)
}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/**
* @file index.vue 科内开单
* @author: w
* @since: 2026-03-02
* @since: 2026-03-09
*/
<template>
@ -86,21 +86,8 @@
:scrollYConfig="{ enabled: true, rSize: 30, height: '100%', }" :row-style="rowStyle"
:cell-style="cellStyle" class="mytable-style" ref="tableRef" :enable-column-drag="true"
@column-drag-end="handleColumnDragEnd">
<template #brxb="{ row }">
{{ formatDict(row.brxb, 'SX') }}
</template>
<template #nldw="{ row }">
{{ formatDict(row.nldw, 'AU') }}
</template>
<template #yblx="{ row }">
{{ formatDict(row.yblx, 'BT') }}
</template>
<template #ksdh="{ row }">
{{ formatDict(row.ksdh, 'DP') }}
</template>
<template #brly="{ row }">
{{ formatDict(row.brly, 'PT') }}
<template #sqys="{ row }">
{{ row.sqys }}
</template>
<template #zt="{ row }">
{{ formatDictzt(row.zt) }}
@ -132,12 +119,17 @@ const searchKey = ref('')
const loading = ref(false)
const tableRef = useTemplateRef('tableRef')
const labPatList = ref([])
const searchForm = ref({})
const searchForm = ref({
brxm: '',
zt: '',
days: 0,
begdate: dayjs().format('YYYY-MM-DD'),
})
const tableColumns = ref([
{ field: 'brxm', title: '姓名', width: 40, align: 'center', resizable: true, },
{ field: 'zt', title: '状态', width: 40, align: 'center', slotName: 'zt', resizable: true, },
{ field: 'sqsj', title: '登记时间', width: 80, align: 'center', resizable: true },
{ field: 'sqr', title: '登记人', width: 80, align: 'center', resizable: true },
{ field: 'sqys', title: '登记人', width: 80, align: 'center', slotName: 'sqys', resizable: true },
{ field: 'jymd', title: '项目', align: 'center', resizable: true },
])
@ -150,7 +142,7 @@ const cellStyle = ({ row, column }) => {
const handleRowClick = (row) => {
queryPatDetail({ sqh: row.sqh }).then(res => {
labpat.value = res.data.labReqmain
labpat.value.zt = labpat.value.zt.trim()
labpat.value.zt = labpat.value.zt?.trim()
sqXmList.value = res.data.reqInputLisWorkVOList
checkboxs.value = res.data.reqInputLisWorkVOList.map(item => item.sfxmdh)
})
@ -304,7 +296,6 @@ const formatDictzt = (value) => {
}
onMounted(() => {
searchForm.value.begdate = dayjs().format('YYYY-MM-DD')
getXmList()
getDictData('PT', 'SX', 'AU', 'BT', 'DP', 'SRD', 'ZJLX')
})
@ -347,7 +338,6 @@ onMounted(() => {
}
.xmBoxs {
:deep(.el-checkbox__label) {}
height: 60%;
overflow-y: auto;

View File

@ -0,0 +1,441 @@
<template>
<div class="dynamic-input-container">
<!-- 1. 开关组件(替代原单选框 type=0:是/否 → 开启/关闭) -->
<el-switch
class="custom-switch"
v-if="type === '0'"
v-model="innerValue"
active-color="#13ce66"
inactive-color="#ff4949"
active-value="1"
inactive-value="0"
@change="handleSwitchChange"
/>
<!-- 2. 下拉框(1):直接绑定value -->
<el-select
v-else-if="type === '1'"
v-model="innerValue"
size="small"
clearable
@change="handleValueChange"
>
<el-option
v-for="item in dictOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<!-- 3. 字典单选(2):绑定zddh(value),显示zdmc(label) -->
<el-select
v-else-if="type === '2'"
v-model="innerValue"
size="small"
clearable
@change="handleValueChange"
v-loading="dictLoading"
>
<el-option
v-for="item in dictOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<!-- 4. 字典多选(3):数组↔逗号分隔字符串 → 修复核心:仅绑定multipleValue,移除冗余逻辑 -->
<el-select
v-else-if="type === '3'"
v-model="multipleValue"
size="small"
multiple
@change="handleMultipleChange"
v-loading="dictLoading"
clearable
>
<el-option
v-for="item in dictOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<!-- 5. 特殊(4) -->
<el-input
v-else-if="type === '4'"
v-model="innerValue"
size="small"
disabled
@change="handleValueChange"
/>
<!-- 6. 文本框(5) -->
<el-input
v-else-if="type === '5'"
v-model="innerValue"
size="small"
:placeholder="placeholder"
@change="handleValueChange"
/>
<!-- 7. 数字框(6):支持dictData定义小数位数,空值初始化 -->
<el-input-number
v-else-if="type === '6'"
v-model="innerValue"
size="small"
:min="minNum"
:precision="finalPrecision"
controls-position="right"
@change="handleValueChange"
:placeholder="placeholder || '请输入数字'"
/>
<!-- 8. 日期框(7):适配yyyy/mm/dd -->
<el-date-picker
v-else-if="type === '7'"
v-model="innerValue"
size="small"
type="date"
format="YYYY/MM/DD"
value-format="YYYY-MM-DD"
:placeholder="placeholder"
@change="handleValueChange"
/>
<!-- 9. 时间框(8):适配hh:mm(修复标签闭合问题) -->
<el-time-picker
v-else-if="type === '8'"
v-model="innerValue"
size="small"
format="HH:mm"
value-format="HH:mm:ss"
:placeholder="placeholder"
@change="handleValueChange"
:picker-options="{ selectableRange: '00:00:00 - 23:59:59' }"
/>
<!-- 兜底:默认文本框 -->
<el-input
v-else
v-model="innerValue"
size="small"
:placeholder="placeholder"
@change="handleValueChange"
/>
</div>
</template>
<script setup name="DynamicInput">
import { ref, watch, defineProps, defineEmits, onMounted, computed } from "vue";
import { ElMessage } from "element-plus";
import { getoptionselect } from "@/api/liswork/xtwh/localconfigApi.ts";
// 字典缓存:key=字典类型,value=映射后的{label,value}列表
const dictCache = ref({});
// Props定义
const props = defineProps({
modelValue: { // Vue3 规范:v-model 绑定 modelValue
type: [String, Number, Boolean, null, undefined], // 新增null/undefined支持空值
required: false, // 允许空值
default: ""
},
type: { type: String, required: true, default: "5" },
dictData: { type: [String, Number, Object, Array], default: "" }, // 支持Number类型(小数位数)
placeholder: { type: String, default: "请输入值" },
minNum: { type: Number, default: -Infinity }, // 数字框最小值改为无限制(空值场景)
precisionNum: { type: Number, default: 0 } // 默认整数
});
// Emits定义(统一触发 update:modelValue)
const emit = defineEmits(["update:modelValue", "change"]);
// 内部状态
const innerValue = ref(null); // 初始值改为null,适配空值
const multipleValue = ref([]); // 多选值(仅type=3用)→ 核心:初始化为空数组,杜绝默认0
const dictOptions = ref([]); // 下拉/字典选项列表
const dictLoading = ref(false); // 字典加载状态
// ========== 核心:数字框小数位数计算 ==========
const finalPrecision = computed(() => {
if (props.type !== "6") return props.precisionNum;
// dictData为小数保留位数(优先级最高)
if (props.dictData !== "" && props.dictData !== null && props.dictData !== undefined) {
const precision = Number(props.dictData);
return isNaN(precision) ? 0 : Math.max(0, precision); // 确保非负整数
}
// dictData为空,默认整数(precisionNum=0)
return 0;
});
// ========== 核心修复:值初始化 + 格式适配 → 重点优化多选逻辑 ==========
watch(() => props.modelValue, (newVal) => {
const val = newVal; // 移除兜底空值,保留原始值
switch (props.type) {
// 开关组件(替代原单选框):后端1/0 → 前端"1"/"0"
case "0":
innerValue.value = (val === 1 || val === "1" || val === true) ? "1" : "0";
break;
// 下拉框/字典单选:直接绑定value(zddh)
case "1":
case "2":
innerValue.value = val === null || val === undefined ? "" : String(val);
break;
// 字典多选:核心修复 → 严格过滤空值/无效值,杜绝默认0
case "3":
// 1. 空值/0/空字符串 → 空数组
if (val === null || val === undefined || val === "" || val === 0) {
multipleValue.value = [];
}
// 2. 有效字符串 → 分割为数组(过滤空项)
else if (typeof val === "string") {
multipleValue.value = val.split(",").filter(item => item.trim() !== "").map(item => String(item));
}
// 3. 数组类型(特殊场景)→ 直接赋值
else if (Array.isArray(val)) {
multipleValue.value = val.filter(item => item !== null && item !== undefined && item !== "").map(item => String(item));
}
// 4. 其他类型 → 空数组
else {
multipleValue.value = [];
}
// 移除innerValue同步(避免干扰多选)
break;
// 数字框:空值处理,支持小数位数
case "6":
// 空值/非数字 → 空(null),否则转为数字
if (val === null || val === undefined || val === "" || isNaN(Number(val))) {
innerValue.value = null;
} else {
innerValue.value = Number(val);
}
break;
// 日期框:后端 yyyy/mm/dd → 前端 yyyy-MM-dd
case "7":
innerValue.value = typeof val === "string" && val.includes("/")
? val.replace(/\//g, "-")
: val || null;
break;
// 时间框:后端 hh:mm → 前端 hh:mm:ss
case "8":
innerValue.value = typeof val === "string" && val.includes(":") && val.split(":").length === 2
? `${val}:00`
: val || null;
break;
// 其他类型:保留原始值(空值则为null)
default:
innerValue.value = val === null || val === undefined ? "" : val;
break;
}
}, { immediate: true, deep: true });
// ========== 修复:移除innerValue对多选的干扰 → 仅监听非多选类型 ==========
watch(innerValue, (newVal) => {
// 多选类型跳过innerValue监听
if (props.type === "3") return;
let finalVal = newVal;
// 数字框:空值提交空字符串,非空则保留数字类型
if (props.type === "6") {
finalVal = newVal === null || newVal === undefined ? "" : Number(newVal);
}
// 日期框:前端 yyyy-MM-dd → 后端 yyyy/mm/dd
else if (props.type === "7" && typeof newVal === "string" && newVal.includes("-")) {
finalVal = newVal.replace(/-/g, "/");
}
// 时间框:前端 hh:mm:ss → 后端 hh:mm
else if (props.type === "8" && typeof newVal === "string" && newVal.includes(":")) {
finalVal = newVal.split(":").slice(0, 2).join(":");
}
emit("update:modelValue", finalVal);
emit("change", finalVal);
}, { deep: true });
// ========== 字典加载逻辑 → 新增:字典加载后重新同步多选值 ==========
watch([() => props.type, () => props.dictData], async () => {
dictOptions.value = [];
// 数字框(type=6)不需要加载字典
if (props.type === "1") {
await parseJsonDict();
} else if (["2", "3"].includes(props.type)) {
await loadApiDict();
// 字典加载完成后,重新同步多选值(修复选不到值的问题)
if (props.type === "3") {
const val = props.modelValue;
if (val === null || val === undefined || val === "" || val === 0) {
multipleValue.value = [];
} else if (typeof val === "string") {
multipleValue.value = val.split(",").filter(item => item.trim() !== "").map(item => String(item));
}
}
}
}, { immediate: true, deep: true });
// 解析下拉框JSON数组(type=1)
async function parseJsonDict() {
if (!props.dictData) return;
try {
let jsonStr = typeof props.dictData === "string" ? props.dictData : JSON.stringify(props.dictData);
jsonStr = jsonStr.replace(/\s+/g, " ").replace(/[\n\t]/g, "");
let jsonData = JSON.parse(jsonStr);
if (!Array.isArray(jsonData)) jsonData = [jsonData];
dictOptions.value = jsonData.map(item => ({
label: item.label || item.zdmc || item.name || "",
value: item.value || item.zddh || item.code || ""
})).filter(item => item.label && item.value);
} catch (error) {
ElMessage.error(`下拉框数据解析失败:${error.message}`);
console.error("JSON解析失败:", { raw: props.dictData, error });
}
}
// 加载字典API(type=2/3):zddh→value,zdmc→label
async function loadApiDict() {
const dictType = props.dictData;
if (!dictType) return;
if (dictCache.value[dictType]) {
dictOptions.value = dictCache.value[dictType];
return;
}
try {
dictLoading.value = true;
const res = await getoptionselect({ zdlb: dictType });
if (res.code === 200 && Array.isArray(res.data)) {
dictOptions.value = res.data.map(item => ({
label: item.zdmc || item.label || "",
value: item.zddh || item.value || ""
})).filter(item => item.label && item.value);
dictCache.value[dictType] = dictOptions.value;
} else {
ElMessage.warning(`字典${dictType}无有效数据`);
}
} catch (error) {
ElMessage.error("字典请求失败");
console.error("字典API异常:", { dictType, error });
} finally {
dictLoading.value = false;
}
}
// ========== 开关组件专属变更处理(直接返回数字1/0) ==========
function handleSwitchChange(val) {
// val是字符串1/0,转为数字提交给后端
const finalVal = Number(val);
emit("update:modelValue", finalVal);
emit("change", finalVal);
}
// ========== 普通值变更处理(除开关/多选外) ==========
function handleValueChange(val) {
let finalVal = val;
emit("update:modelValue", finalVal);
emit("change", finalVal);
}
// ========== 核心修复:多选值变更处理 → 简化逻辑,杜绝值覆盖 ==========
function handleMultipleChange(val) {
// 1. 过滤空值,避免提交无效数据
const validVal = val.filter(item => item !== null && item !== undefined && item !== "");
// 2. 转为逗号分隔字符串(后端格式)
const strVal = validVal.join(",");
// 3. 更新多选值(确保同步)
multipleValue.value = validVal;
// 4. 触发父组件更新
emit("update:modelValue", strVal);
emit("change", strVal);
}
// ========== 初始化优化 → 移除多选冗余逻辑,杜绝默认0 ==========
onMounted(() => {
// 开关组件初始值兜底
if (props.type === "0" && innerValue.value === null) {
innerValue.value = "0"; // 默认关闭
emit("update:modelValue", 0); // 后端默认值:0
}
// 多选初始化:仅处理有效值,杜绝空值/0转为["0"]
if (props.type === "3") {
const val = props.modelValue;
if (val === null || val === undefined || val === "" || val === 0) {
multipleValue.value = [];
} else if (typeof val === "string") {
multipleValue.value = val.split(",").filter(item => item.trim() !== "").map(item => String(item));
}
}
});
</script>
<style scoped>
.dynamic-input-container {
width: 100%;
height: 100%; /* 关键:占满表格单元格高度 */
display: flex;
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
padding: 0 2px; /* 轻微内边距,避免贴边 */
}
/* 开关组件样式优化 */
:deep(.el-switch) {
margin: 0 auto; /* 开关水平居中 */
}
/* 深度选择器强制覆盖激活颜色 */
:deep(.custom-switch .el-switch__core) {
/* 开启状态背景色 */
--el-switch-on-color: #13ce66 !important;
/* 关闭状态背景色(可选) */
--el-switch-off-color: #C3C3C3 !important;
}
/* 兼容旧版Element Plus(可选) */
:deep(.custom-switch .el-switch__core.is-checked) {
background-color: #13ce66 !important;
border-color: #13ce66 !important;
}
:deep(.el-radio-group) {
display: flex;
gap: 10px;
align-items: center;
}
:deep(.el-select--small),
:deep(.el-input--small),
:deep(.el-input-number--small),
:deep(.el-date-picker--small),
:deep(.el-time-picker--small) {
width: 100%;
}
/* 数字输入框空值样式优化 */
:deep(.el-input-number--small) {
.el-input__inner {
text-align: center;
}
/* 空值时占位符样式 */
.el-input__placeholder {
color: #999;
font-size: 12px;
}
}
/* 多选下拉样式优化:避免高度溢出 */
:deep(.el-select--multiple .el-select__tags) {
flex-wrap: wrap;
min-height: 32px; /* 匹配small尺寸高度 */
}
</style>

View File

@ -0,0 +1,365 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item :label="menuname + '类别'" prop="configType">
<el-select v-model="queryParams.configType" :placeholder="`请选择${menuname}类别`" clearable style="width: 200px"
@change="handleQuery">
<el-option v-for="item in configTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="menuname + '编码'" prop="configCode">
<el-input v-model="queryParams.configCode" :placeholder="`请输入${menuname}编码`" clearable style="width: 200px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item :label="`${menuname}名称`" prop="configName">
<el-input v-model="queryParams.configName" :placeholder="`请输入${menuname}名称`" clearable style="width: 200px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="状态" clearable style="width: 200px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<div class="table-container">
<el-table v-loading="loading" :data="regdictList" @selection-change="handleSelectionChange" class="config-table"
height="100%">
<el-table-column type="selection" width="55" align="center" />
<el-table-column :label="`${menuname}编号`" align="center" prop="configId" v-if="false" />
<el-table-column :label="`${menuname}类别`" align="center" prop="configType" width="100" show-overflow-tooltip>
<template #default="scope">
<span class="config-type-cell" :style="{
backgroundColor: getConfigTypeColor(scope.row.configType),
color: '#fff' // 文字白色,保证对比
}">
{{configTypeOptions.find(item => item.value === scope.row.configType)?.label || scope.row.configType}}
</span>
</template>
</el-table-column>
<el-table-column :label="`${menuname}编码`" align="center" prop="configCode" width="150" show-overflow-tooltip />
<el-table-column :label="`${menuname}名称`" align="left" prop="configName" show-overflow-tooltip />
<el-table-column label="选项类型" align="center" prop="configOptiontype" width="100">
<template #default="scope">
<span class="config-type-cell" :style="{
backgroundColor: getconfigOptionTypeColor(scope.row.configOptiontype),
color: '#fff' // 文字白色,保证对比
}">
{{configOptiontypeOptions.find(item => item.value === scope.row.configOptiontype)?.label ||
scope.row.configOptiontype}}
</span>
</template>
</el-table-column>
<el-table-column label="默认值" align="center" prop="configDefvalue" width="200" show-overflow-tooltip>
<template #default="scope">
<DynamicInput :type="scope.row.configOptiontype" v-model="scope.row.configDefvalue"
:dict-data="scope.row.remark" :placeholder="`请输入${scope.row.configName}值`" class="edit-input" />
</template>
</el-table-column>
<el-table-column label="值域规则" align="left" prop="remark" show-overflow-tooltip />
<el-table-column label="排序" align="center" prop="configSort" width="80" />
<el-table-column label="状态" align="center" prop="status" width="80">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="150" show-overflow-tooltip>
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
<!-- 添加或修改字典对话框 -->
<el-dialog :title="title" v-model="open" width="500px">
<el-form ref="configdictRef" :model="form" :rules="rules" label-width="150px">
<el-form-item :label="`${menuname}类别`" prop="configType">
<el-select v-model="form.configType" :placeholder="`请选择${menuname}类别`" style="width: 100%">
<el-option v-for="item in configTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="`${menuname}编码`" prop="configCode">
<el-input v-model="form.configCode" :placeholder="`请输入${menuname}编码`" />
</el-form-item>
<el-form-item :label="`${menuname}名称`" prop="configName">
<el-input v-model="form.configName" :placeholder="`请输入${menuname}名称`" />
</el-form-item>
<el-form-item :label="`${menuname}选项类型`" prop="configOptiontype">
<el-select v-model="form.configOptiontype" :placeholder="`请选择${menuname}选项类型`" style="width: 100%">
<el-option v-for="item in configOptiontypeOptions" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="`${menuname}默认值`" prop="configDefvalue">
<el-input v-model="form.configDefvalue" :placeholder="`请输入${menuname}默认值`" />
</el-form-item>
<el-form-item label="顺序" prop="configSort">
<el-input-number v-model="form.configSort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label
}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="值域参数JSON" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="configdict">
import { listData, } from "@/api/system/dict/data";
import {
addconfigdict, delconfigdict,
getconfigdict,
listconfigdict,
updateconfigdict
} from "@/api/liswork/xtwh/configdictApi.ts";
import DynamicInput from "../components/DynamicInput.vue"
// 1. 定义类别下拉选项(根据实际业务调整)
// 2. 定义获取类别对应颜色的方法
function getConfigTypeColor(type) {
// 匹配对应类别的颜色,无匹配时用默认色
const item = configTypeOptions.value.find(item => item.value === type);
return item?.elTagClass || "#909399"; // 默认灰色
}
// 2. 定义参数类别下拉选项(根据实际业务调整)
const configOptiontypeOptions = ref([
{ label: "单选框", value: "0", color: "#56BBBD" },
{ label: "下拉框", value: "1", color: "#67C23A" },
{ label: "字典单选", value: "2", color: "#FF443F" },
{ label: "字典多选", value: "3", color: "#F08784" },
{ label: "特殊", value: "4", color: "#909399" },
{ label: "文本框", value: "5", color: "#3282F6" },
{ label: "数字框", value: "6", color: "#507F80" },
{ label: "日期框", value: "7", color: "#7E84F7" },
{ label: "时间框", value: "8", color: "#377D22" },
]);
function getconfigOptionTypeColor(type) {
// 匹配对应类别的颜色,无匹配时用默认色
const item = configOptiontypeOptions.value.find(item => item.value === type);
return item?.color || "#909399"; // 默认灰色
}
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const { lis_opt_type } = proxy.useDict("lis_opt_type"); //参数类别
const configTypeOptions = lis_opt_type
const regdictList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const menuname = ref("参数");
const data = reactive({
form: {},
queryParams: {
configCode: undefined,
configName: undefined,
configType: undefined,
status: undefined,
pageNum: 1,
pageSize: 30
},
rules: {
configType: [{ required: true, message: menuname.value + "类别不能为空", trigger: "blur" }],
configName: [{ required: true, message: menuname.value + "名称不能为空", trigger: "blur" }],
configCode: [{ required: true, message: menuname.value + "编码不能为空", trigger: "blur" }],
configSort: [{ required: true, message: menuname.value + "顺序不能为空", trigger: "blur" }],
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询字典列表 */
function getList() {
loading.value = true;
listconfigdict(queryParams.value).then(response => {
regdictList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
configId: undefined,
configCode: undefined,
configName: undefined,
configType: configTypeOptions.value[0]?.value || "",
configOptiontype: configOptiontypeOptions.value[0]?.value || "",
configDefvalue: undefined,
configSort: 0,
status: "0",
remark: undefined
};
proxy.resetForm("configdictRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.configId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加" + menuname.value;
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const configId = row.configId || ids.value;
getconfigdict(configId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改" + menuname.value;
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["configdictRef"].validate(valid => {
if (valid) {
if (form.value.configId != undefined) {
updateconfigdict(form.value).then(response => {
if (response.code == 200) {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
}
});
} else {
addconfigdict(form.value).then(response => {
if (response.code == 200) {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
}
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const configIds = row.configId || ids.value;
proxy.$modal.confirm('是否确认删除"' + menuname.value + '"编号为"' + configIds + '"的数据项?').then(function () {
return delconfigdict(configIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => { });
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("delconfigdict/export", {
...queryParams.value
}, `dict_${new Date().getTime()}.xlsx`);
}
getList();
</script>
<style scoped>
.mb8 {
height: 30px;
/* 固定高度 */
}
.table-container {
height: calc(100% - 150px);
}
/* 1. 减小表格行高(核心) */
:deep(.config-table .el-table__row) {
height: 30px !important;
/* 原默认行高约40px,按需调整(建议28-35px) */
line-height: 30px !important;
/* 行高与height一致,保证垂直居中 */
}
/* 2. 减小单元格内边距(配合行高优化) */
:deep(.config-table .el-table__cell) {
padding: 2px 4px !important;
height: 30px !important;
/* 单元格高度与行高一致 */
line-height: 1.2 !important;
/* 文字行高适配矮行 */
vertical-align: middle !important;
/* 强制垂直居中 */
}
/* 3. 类别单元格适配矮行高 */
.config-type-cell {
width: 100%;
height: 100%;
min-height: 26px;
/* 适配30px行高,略小一点 */
display: flex;
align-items: center;
justify-content: center;
padding: 0;
font-size: 12px;
}
/* 可选:优化操作列按钮大小,适配矮行 */
:deep(.config-table .el-button--link) {
padding: 0 4px !important;
font-size: 12px !important;
}
</style>

View File

@ -0,0 +1,231 @@
<template>
<div class="app-container">
<!-- 操作按钮栏:改为保存/取消/还原默认 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleSave">保存</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" @click="handleCancelEdit">取消修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Download" @click="handleRestoreDefault">还原默认</el-button>
</el-col>
</el-row>
<el-row :gutter="5" class="table-container">
<el-table v-loading="loading" :data="regdictList" @selection-change="handleSelectionChange" class="config-table"
height="100%">
<el-table-column label="序号" align="center" prop="configSort" />
<el-table-column :label="`${menuname}编码`" align="center" prop="configCode" show-overflow-tooltip />
<el-table-column :label="`${menuname}名称`" align="left" prop="configName" show-overflow-tooltip />
<!-- 核心:默认值列改为持久化可编辑输入框 -->
<el-table-column label="参数值" align="center" prop="configDefvalue" show-overflow-tooltip>
<template #default="scope">
<DynamicInput :type="scope.row.configOptiontype" v-model="scope.row.configDefvalue"
:dict-data="scope.row.remark" :placeholder="`请输入${scope.row.configName}值`" />
</template>
</el-table-column>
<el-table-column label="值码" align="center" prop="configDefvalue" show-overflow-tooltip />
</el-table>
</el-row>
</div>
</template>
<script setup name="localconfig">
// 导入核心依赖
import { ref, reactive, toRefs, getCurrentInstance } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import DynamicInput from "../components/DynamicInput.vue";
import { listlocalconfig, savelocalconfig, getLocalConfigDefault } from "@/api/liswork/xtwh/localconfigApi.ts";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
// 表格数据(原始数据缓存,用于取消修改)
const regdictList = ref([]);
const originRegdictList = ref([]); // 缓存原始数据,用于取消修改
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const menuname = ref("本地选项");
const data = reactive({
queryParams: {
configCode: undefined,
configName: undefined,
configType: undefined,
status: undefined
}
});
const { queryParams } = toRefs(data);
/** 查询字典列表(缓存原始数据) */
function getList() {
loading.value = true;
listlocalconfig(queryParams.value).then(response => {
// 存储表格展示数据
regdictList.value = response.data.map(item => ({ ...item }));
// 缓存原始数据(深拷贝,避免引用修改)
originRegdictList.value = JSON.parse(JSON.stringify(response.data));
total.value = response.data.length;
loading.value = false;
});
}
/** 搜索按钮操作 */
function handleQuery() {
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 表格行选中事件 */
function handleSelectionChange(val) {
ids.value = val.map(item => item.configId);
single.value = val.length === 1;
multiple.value = val.length > 1;
}
/** 核心:保存整个表格数据(批量提交) */
async function handleSave() {
// 空值校验:检查所有行的默认值是否为空
//const emptyRows = regdictList.value.filter(item => !item.configDefvalue?.trim());
//if (emptyRows.length > 0) {
// ElMessage.warning(`有${emptyRows.length}行默认值为空,请补充后再保存!`);
// return;
// }
try {
loading.value = true;
// 调用批量保存接口,传入整个列表
const res = await savelocalconfig(regdictList.value);
if (res.code === 200) {
ElMessage.success("批量保存成功!");
// 保存后更新原始数据缓存
originRegdictList.value = JSON.parse(JSON.stringify(regdictList.value));
} else {
ElMessage.error(res.msg || "批量保存失败,请重试!");
}
} catch (error) {
ElMessage.error("保存失败,网络异常!");
console.error("保存失败:", error);
} finally {
loading.value = false;
}
}
/** 取消修改:恢复原始数据 */
function handleCancelEdit() {
ElMessageBox.confirm(
"是否确认取消所有修改,恢复到原始数据?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}
).then(() => {
// 恢复原始数据
regdictList.value = JSON.parse(JSON.stringify(originRegdictList.value));
ElMessage.success("已取消所有修改,恢复原始数据!");
});
}
/** 还原默认值:调用接口获取默认值并刷新 */
async function handleRestoreDefault() {
ElMessageBox.confirm(
"是否确认还原所有默认值?此操作会覆盖当前修改!",
"警告",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "danger"
}
).then(async () => {
try {
loading.value = true;
// 调用还原默认接口
const res = await getLocalConfigDefault(queryParams.value);
if (res.code === 200) {
// 更新表格数据和原始缓存
regdictList.value = res.data.map(item => ({ ...item }));
originRegdictList.value = JSON.parse(JSON.stringify(res.data));
ElMessage.success("已成功还原默认值!");
} else {
ElMessage.error(res.msg || "还原默认值失败,请重试!");
}
} catch (error) {
ElMessage.error("还原失败,网络异常!");
console.error("还原默认值失败:", error);
} finally {
loading.value = false;
}
});
}
// 初始化加载数据
getList();
</script>
<style scoped>
.app-container {
display: flex;
flex-direction: column;
height: 90vh;
overflow: hidden;
}
.mb8 {
height: 30px;
margin-bottom: 8px;
}
.table-container {
width: 100%;
flex: 1;
overflow: hidden;
}
/* 表格样式优化 */
:deep(.config-table .el-table__row) {
height: 30px !important;
line-height: 30px !important;
}
:deep(.config-table .el-table__cell) {
padding: 2px 4px !important;
height: 30px !important;
line-height: 1.2 !important;
vertical-align: middle !important;
}
/* 编辑输入框样式适配 */
:deep(.config-table .edit-input) {
width: 100%;
}
:deep(.config-table .edit-input .el-input__inner) {
padding: 0 5px;
height: 24px;
line-height: 24px;
font-size: 12px;
border: 1px solid #dcdfe6;
}
:deep(.config-table .edit-input .el-input__inner:focus) {
border-color: #409eff;
outline: none;
}
</style>

View File

@ -0,0 +1,267 @@
<template>
<div class="app-container">
<div class="compact-form">
<el-form :model="queryParams" ref="queryRef" label-width="5rem" style="width: 100%;" :size="aotuSize">
<el-row :gutter="10">
<el-col :span="4">
<el-form-item label="委托机构:" prop="SrcHospName">
<SelectTable v-model:data="queryParams.SrcHospName" :fields="ksdhFields" :tableData="hosList"
label="label" :size="aotuSize" value="label" objKey="label" :border="true" placeholder="请选择委托机构" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="检测医院:" prop="DstHospName">
<SelectTable v-model:data="queryParams.DstHospName" :fields="ksdhFields" :tableData="hosList"
label="label" :size="aotuSize" value="label" objKey="label" :border="true" placeholder="请选择" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="条码号:" prop="Barcode">
<el-input v-model="queryParams.Barcode" placeholder="请输入条码号" clearable />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="姓名:" prop="PatName">
<el-input v-model="queryParams.PatName" placeholder="请输入姓名" clearable />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="申请项目:" prop="checkPUR">
<el-input v-model="queryParams.checkPUR" placeholder="请输入申请项目" clearable />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="标本状态:" prop="Status">
<el-select v-model="queryParams.Status" placeholder="请选择" clearable>
<el-option v-for="item in regdictList" :label="item.dictName" :value="item.dictCode" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="采样人:" prop="AffirmUserName">
<el-input v-model="queryParams.AffirmUserName" placeholder="请输入采样人" clearable />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="签收人:" prop="SignInUserName">
<el-input v-model="queryParams.SignInUserName" placeholder="请输入签收人" clearable />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="时间类型:" prop="DateType">
<el-select v-model="queryParams.DateType" placeholder="请选择">
<el-option label="登记时间" value="登记时间" />
<el-option label="采样时间" value="采样时间" />
<el-option label="送出时间" value="送出时间" />
<el-option label="签收时间" value="签收时间" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="日期:" prop="times">
<el-date-picker v-model="queryParams.times" type="daterange" range-separator="-" start-placeholder="开始时间"
end-placeholder="结束时间" format="YYYY-MM-DD" value-format="YYYY-MM-DD" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</el-col>
</el-row>
</el-form>
</div>
<div>
<CustomTable ref="tableRefs" :data="tableData" :columns="columns" :config="tableConfig" :pagination="pagination"
@size-change="sizeChange" @page-change="currentChange" @row-click="rowHandle">
<template #patAge="{ row }">
{{ row.patAge }}{{ row.ageUnit }}
</template>
<template #status="{ row }">
{{ formatDict(row.status, regdictList) }}
</template>
<template #patSex="{ row }">
{{ row.patSex == 1 ? '男' : '女' }}
</template>
</CustomTable>
</div>
<!-- 样本流程 -->
<div class="time-line-box">
<div v-for="(item, i) in timelineItems" :key="i" class="time-line-item">
<div v-if="i != 0" class="timeline-connector">
<img class="timg" src="@/assets/images/yjt.png" alt="">
</div>
<div :class="['timeline-content', i > lastTimeIndex ? 'no_active' : '']">
<div :class="['index', lastTimeIndex == i ? 'active' : '']">{{ i + 1 }}
</div>
<div class="timeline-title">{{ item.title }}</div>
<div class="timeline-time">{{ item.time }}</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import CustomTable from '@/components/elTable/index.vue'
import { querySample } from '@/api/regional/index'
import SelectTable from '@/components/SelectTable/index.vue';
import { classCom } from '@/utils/classCom';
const aotuSize = classCom.useAutoSize();
// @ts-ignore
import { listhospital } from "@/api/regional/dict/hospital.js";
// @ts-ignore
import { listregdict } from "@/api/regional/dict/regdict.js";
const queryParams: any = ref({
pageSize: 50,
pageNum: 1,
})
const tableData: any = ref([])
const columns: any = ref([
{ prop: 'barcode', label: '条码号', align: 'center', visible: true, width: 150 },
{ prop: 'srcHospName', label: '委托机构', align: 'center', visible: true, width: 200 },
{ prop: 'patName', label: '姓名', align: 'center', visible: true, width: 70 },
{ prop: 'patSex', label: '性别', align: 'center', visible: true, width: 60, slot: "patSex" },
{ prop: 'patAge', label: '年龄', align: 'center', visible: true, slot: "patAge", width: 60 },
{ prop: 'checkPUR', label: '申请项目', align: 'center', visible: true, width: 200 },
{ prop: 'sampleTypeName', label: '标本类型', align: 'center', visible: true, },
{ prop: 'tubeName', label: '采集容器', align: 'center', visible: true, },
{ prop: 'status', label: '标本状态', align: 'center', visible: true, slot: "status" },
// { prop: 'moveStateName', label: '流转状态', align: 'center', visible: true, },
{ prop: 'affirmUserName', label: '采样人', align: 'center', visible: true, },
{ prop: 'affirmTime', label: '采样时间', align: 'center', visible: true, width: 150 },
{ prop: 'signInUserName', label: '签收人', align: 'center', visible: true, },
{ prop: 'signInTime', label: '签收时间', align: 'center', visible: true, width: 150 },
{ prop: 'dstHospName', label: '检测机构名称', align: 'center', visible: true, width: 150 },
])
const tableConfig = ref({
border: true, // 边框
height: '65vh', // 高度
highlightCurrentRow: true, // 高亮当前行
// fit: true, // 列宽自适应
})
const pagination = ref({
show: true,
total: 0,
pageSize: 50,
currentPage: 1,
})
const ksdhFields = ref([
{ prop: 'label', label: '名称', width: 150, enablePinyinSearch: true },
{ prop: 'value', label: '代号', width: 120, enablePinyinSearch: true },
])
// 时间线数据
const timelineItems = ref(
[
{ title: '检验申请', time: '' },
{ title: '标本采集', time: '' },
{ title: '标本送检', time: '' },
{ title: '标本外送', time: '' },
{ title: '标本签收', time: '' },
{ title: '上机检测', time: '' },
{ title: '结果审核', time: '' },
{ title: '报告发布', time: '' },
]
);
// 计算最后一个有时间的节点索引
const lastTimeIndex = computed(() => {
const lastIndex = timelineItems.value.findLastIndex(item => item.time);
if (lastIndex === -1) {
return -1
} else {
return lastIndex;
}
});
const handleQuery = () => {
if (queryParams.value.times && queryParams.value.times.length > 0) {
queryParams.value.DateStart = queryParams.value.times[0]
queryParams.value.DateEnd = queryParams.value.times[1]
} else {
queryParams.value.DateStart = ''
queryParams.value.DateEnd = ''
}
getList()
}
const resetHandle = () => {
queryParams.value = {
pageSize: 50,
pageNum: 1,
}
handleQuery()
}
const currentChange = (page: { currentPage: number, pageSize: number }) => {
queryParams.value.pageNum = page.currentPage
handleQuery()
}
const sizeChange = (page: { currentPage: number, pageSize: number }) => {
queryParams.value.pageSize = page.pageSize
handleQuery()
}
const rowHandle = (row: any) => {
timelineItems.value =
[
{ title: '检验申请', time: row.orderTime },
{ title: '标本采集', time: row.affirmTime },
{ title: '标本送检', time: row.signInDate },
{ title: '标本外送', time: row.sendPackTime },
{ title: '标本签收', time: row.signInTime },
{ title: '上机检测', time: row.testDate },
{ title: '结果审核', time: row.auditTime },
{ title: '报告发布', time: row.reportTime },
]
}
const tableRefs = ref()
const getList = () => {
querySample(queryParams.value).then((res: any) => {
tableData.value = res.rows
pagination.value.total = res.total
tableRefs.value.setCurrentRow(res.rows[0])
rowHandle(res.rows[0])
})
}
const hosList = ref([])
const regdictList: any = ref([])
onMounted(() => {
getList()
listhospital().then((res: any) => {
hosList.value = res.rows.map((item: any) => {
return {
label: item.hospitalName,
value: item.hospitalCode
}
})
})
listregdict({ pageSize: 100, pageNum: 1, dictType: 'ZT' }).then((res: any) => {
regdictList.value = res.rows;
})
})
const formatDict = (v: string, arr: Array<any>) => {
return arr.find((item: any) => item.dictCode == v)?.dictName || v;
};
</script>
<style scoped lang="scss">
.compact-form {
height: 5rem;
.el-form-item {
margin-bottom: 5px;
}
}
</style>

View File

@ -0,0 +1,249 @@
<template>
<div class="app-container">
<div class="compact-form">
<el-form :model="queryParams" ref="queryRef" label-width="5rem" style="width: 100%;" :size="aotuSize">
<el-row :gutter="10">
<el-col :span="5">
<el-form-item label="委托机构:" prop="SrcHospName">
<SelectTable v-model:data="queryParams.SrcHospName" :fields="ksdhFields" :tableData="hosList"
label="label" :size="aotuSize" value="value" objKey="value" :border="true" placeholder="请选择委托机构" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="检测医院:" prop="DstHospName">
<SelectTable v-model:data="queryParams.DstHospName" :fields="ksdhFields" :tableData="hosList"
label="label" :size="aotuSize" value="label" objKey="label" :border="true" placeholder="请选择" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="条码号:" prop="Barcode">
<el-input v-model="queryParams.Barcode" placeholder="请输入条码号" clearable />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="姓名:" prop="PatName">
<el-input v-model="queryParams.PatName" placeholder="请输入姓名" clearable />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="申请项目:" prop="checkPUR">
<el-input v-model="queryParams.checkPUR" placeholder="请输入申请项目" clearable />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="时间类型:" prop="DateType">
<el-select v-model="queryParams.DateType" placeholder="请选择">
<el-option label="登记时间" value="登记时间" />
<el-option label="采样时间" value="采样时间" />
<el-option label="送出时间" value="送出时间" />
<el-option label="签收时间" value="签收时间" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="日期:" prop="times">
<el-date-picker v-model="queryParams.times" type="daterange" range-separator="-" start-placeholder="开始时间"
end-placeholder="结束时间" format="YYYY-MM-DD" value-format="YYYY-MM-DD" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</el-col>
</el-row>
</el-form>
</div>
<div class="mb10">
<el-button type="primary" @click="qsHandle(50)">标本签收</el-button>
<el-button type="primary" @click="qsHandle(110)">标本拒签</el-button>
<el-button type="primary" plain @click="bbThHandle">标本退回</el-button>
</div>
<div style="height: calc(100% - 180px)">
<CustomTable ref="tableRefs" :data="tableData" :columns="columns" :config="tableConfig" :pagination="pagination"
@selection-change="handleSelectionChange" @size-change="sizeChange" @page-change="currentChange">
<template #patAge="{ row }">
{{ row.patAge }}{{ row.ageUnit }}
</template>
<template #status="{ row }">
{{ formatDict(row.status, regdictList) }}
</template>
<template #patSex="{ row }">
{{ row.patSex == 1 ? '男' : '女' }}
</template>
</CustomTable>
</div>
</div>
</template>
<script setup lang="ts">
import CustomTable from '@/components/elTable/index.vue'
import { querySampleSign, sampleSign } from '@/api/regional/index'
import SelectTable from '@/components/SelectTable/index.vue';
// @ts-ignore
import { listhospital } from "@/api/regional/dict/hospital.js";
// @ts-ignore
import { listregdict } from "@/api/regional/dict/regdict.js";
import { classCom } from '@/utils/classCom';
import { ElMessage, ElMessageBox } from 'element-plus';
const aotuSize = classCom.useAutoSize();
import { useRouter } from 'vue-router'
const router = useRouter()
const queryParams: any = ref({
pageSize: 50,
pageNum: 1
})
const tableData: any = ref([])
const columns: any = ref([
{ type: 'selection', align: 'center', visible: true, width: 40 },
{ prop: 'barcode', label: '条码号', align: 'center', visible: true, width: 150 },
{ prop: 'srcHospName', label: '委托机构', align: 'center', visible: true, width: 250 },
{ prop: 'patName', label: '姓名', align: 'center', visible: true, width: 70 },
{ prop: 'patSex', label: '性别', align: 'center', visible: true, width: 60, slot: "patSex" },
{ prop: 'patAge', label: '年龄', align: 'center', visible: true, slot: "patAge", width: 60 },
{ prop: 'checkPUR', label: '申请项目', align: 'center', visible: true, width: 250 },
{ prop: 'sampleTypeName', label: '标本类型', align: 'center', visible: true, },
{ prop: 'tubeName', label: '采集容器', align: 'center', visible: true, },
{ prop: 'status', label: '标本状态', align: 'center', visible: true, slot: "status" },
// { prop: 'moveStateName', label: '流转状态', align: 'center', visible: true, },
{ prop: 'affirmUserName', label: '采样人', align: 'center', visible: true, },
{ prop: 'affirmTime', label: '采样时间', align: 'center', visible: true, width: 150 },
{ prop: 'dstHospName', label: '检测机构名称', align: 'center', visible: true, width: 150 },
])
const tableConfig = ref({
border: true, // 边框
height: '100%', // 高度
highlightCurrentRow: true, // 高亮当前行
// fit: true, // 列宽自适应
})
const pagination = ref({
show: true,
total: 0,
pageSize: 50,
currentPage: 1,
})
const ksdhFields = ref([
{ prop: 'label', label: '名称', width: 150, enablePinyinSearch: true },
{ prop: 'value', label: '代号', width: 120, enablePinyinSearch: true },
])
const barcodes = ref([])
const tableRefs = ref(null)
const handleSelectionChange = (val: any) => {
barcodes.value = val.map((item: any) => item.barcode)
}
const backReasons = ref('')
const bbThHandle = () => {
if (!barcodes.value.length) return ElMessage.warning('请选择数据!')
ElMessageBox.prompt('请输入退回理由:', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
inputPattern: /\S+/,
inputErrorMessage: '请输入退回理由',
})
.then(({ value }) => {
backReasons.value = value
qsHandle(100)
}).catch(() => {
backReasons.value = ''
});
}
//标本签收
const qsHandle = (val: number) => {
if (!barcodes.value.length) return ElMessage.warning('请选择数据!')
sampleSign({ status: val, barcode: barcodes.value, backReasons: backReasons.value }).then((res: any) => {
if (res.code == 0) {
ElMessage.success('操作成功!')
backReasons.value = ''
handleQuery()
}
})
}
const goThPage = () => {
router.push('/regional/circulation/bbth')
}
const resetHandle = () => {
queryParams.value = {
pageSize: 50,
pageNum: 1,
}
handleQuery()
}
const currentChange = (page: { currentPage: number, pageSize: number }) => {
console.log('page==>', page);
queryParams.value.pageNum = page.currentPage
handleQuery()
}
const sizeChange = (page: { currentPage: number, pageSize: number }) => {
queryParams.value.pageSize = page.pageSize
handleQuery()
}
const handleQuery = () => {
if (queryParams.value.times && queryParams.value.times.length > 0) {
queryParams.value.DateStart = queryParams.value.times[0]
queryParams.value.DateEnd = queryParams.value.times[1]
} else {
queryParams.value.DateStart = ''
queryParams.value.DateEnd = ''
}
getList()
}
const getList = () => {
querySampleSign(queryParams.value).then((res: any) => {
tableData.value = res.rows
pagination.value.total = res.total
})
}
const hosList = ref([])
const regdictList: any = ref([])
onMounted(() => {
getList()
listhospital().then((res: any) => {
hosList.value = res.rows.map((item: any) => {
return {
label: item.hospitalName,
value: item.hospitalCode
}
})
})
listregdict({ pageSize: 100, pageNum: 1, dictType: 'ZT' }).then((res: any) => {
regdictList.value = res.rows;
})
})
const formatDict = (v: string, arr: Array<any>) => {
return arr.find((item: any) => item.dictCode == v)?.dictName || v;
};
</script>
<style scoped lang="scss">
.compact-form {
height: 5rem;
.el-form-item {
margin-bottom: 5px;
}
}
.btns {
display: flex;
flex-direction: column;
justify-content: space-around;
&>button {
width: 100%;
margin-left: 0;
margin-bottom: 5px;
}
}
</style>

View File

@ -0,0 +1,223 @@
<template>
<div class="app-container">
<div class="compact-form">
<el-form :model="queryParams" ref="queryRef" label-width="5rem" style="width: 100%;" :size="aotuSize">
<el-row :gutter="10">
<el-col :span="5">
<el-form-item label="委托机构:" prop="SrcHospName">
<SelectTable v-model:data="queryParams.SrcHospName" :fields="ksdhFields" :tableData="hosList"
label="label" :size="aotuSize" value="value" objKey="value" :border="true" placeholder="请选择委托机构" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="检测医院:" prop="DstHospName">
<SelectTable v-model:data="queryParams.DstHospName" :fields="ksdhFields" :tableData="hosList"
label="label" :size="aotuSize" value="label" objKey="label" :border="true" placeholder="请选择" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="条码号:" prop="Barcode">
<el-input v-model="queryParams.Barcode" placeholder="请输入条码号" clearable />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="姓名:" prop="PatName">
<el-input v-model="queryParams.PatName" placeholder="请输入姓名" clearable />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="申请项目:" prop="checkPUR">
<el-input v-model="queryParams.checkPUR" placeholder="请输入申请项目" clearable />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="时间类型:" prop="DateType">
<el-select v-model="queryParams.DateType" placeholder="请选择">
<el-option label="登记时间" value="登记时间" />
<el-option label="采样时间" value="采样时间" />
<el-option label="送出时间" value="送出时间" />
<el-option label="签收时间" value="签收时间" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="日期:" prop="times">
<el-date-picker v-model="queryParams.times" type="daterange" range-separator="-" start-placeholder="开始时间"
end-placeholder="结束时间" format="YYYY-MM-DD" value-format="YYYY-MM-DD" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</el-col>
</el-row>
</el-form>
</div>
<div class="mb10">
<el-button type="primary" @click="thHandle(20)">重新采集</el-button>
<el-button type="primary" @click="thHandle(50)">撤销退回</el-button>
<el-button type="primary" @click="thHandle(90)">申请作废</el-button>
</div>
<div style="height: calc(100% - 180px)">
<CustomTable ref="tableRefs" :data="tableData" :columns="columns" :config="tableConfig" :pagination="pagination"
@selection-change="handleSelectionChange" @size-change="sizeChange" @page-change="currentChange">
<template #patAge="{ row }">
{{ row.patAge }}{{ row.ageUnit }}
</template>
<template #status="{ row }">
{{ formatDict(row.status, regdictList) }}
</template>
<template #patSex="{ row }">
{{ row.patSex == 1 ? '男' : '女' }}
</template>
</CustomTable>
</div>
</div>
</template>
<script setup lang="ts">
import CustomTable from '@/components/elTable/index.vue'
import { querySampleSignBack, sampleSign } from '@/api/regional/index'
import SelectTable from '@/components/SelectTable/index.vue';
import { classCom } from '@/utils/classCom';
// @ts-ignore
import { listhospital } from "@/api/regional/dict/hospital.js";
// @ts-ignore
import { listregdict } from "@/api/regional/dict/regdict.js";
import { ElMessage } from 'element-plus';
const aotuSize = classCom.useAutoSize();
const queryParams: any = ref({
pageSize: 50,
pageNum: 1,
})
const tableData: any = ref([])
const columns: any = ref([
{ type: 'selection', align: 'center', visible: true, width: 40 },
{ prop: 'barcode', label: '条码号', align: 'center', visible: true, },
{ prop: 'patName', label: '姓名', align: 'center', visible: true, width: 60 },
{ prop: 'patSex', label: '性别', align: 'center', visible: true, width: 60, slot: "patSex" },
{ prop: 'patAge', label: '年龄', align: 'center', visible: true, slot: "patAge", width: 60 },
{ prop: 'checkPUR', label: '申请项目', align: 'center', visible: true, width: 200 },
{ prop: 'srcHospName', label: '委托机构', align: 'center', visible: true, width: 200 },
{ prop: 'srcHospName', label: '检测机构', align: 'center', visible: true, width: 200 },
{ prop: 'Status', label: '标本状态', align: 'center', visible: true, slot: "status" },
{ prop: 'backReasons', label: '退回理由', align: 'center', visible: true, width: 150 },
{ prop: 'affirmTime', label: '采样时间', align: 'center', visible: true, width: 150 },
{ prop: 'backUserName', label: '操作人', align: 'center', visible: true, },
{ prop: 'backTime', label: '操作时间', align: 'center', visible: true, width: 150 },
])
const tableConfig = ref({
border: true, // 边框
height: '100%', // 高度
highlightCurrentRow: true, // 高亮当前行
// fit: true, // 列宽自适应
})
const pagination = ref({
show: true,
total: 0,
pageSize: 50,
currentPage: 1,
})
const ksdhFields = ref([
{ prop: 'label', label: '名称', width: 150, enablePinyinSearch: true },
{ prop: 'value', label: '代号', width: 120, enablePinyinSearch: true },
])
const barcodes = ref([])
const tableRefs = ref(null)
const thHandle = (val: number) => {
if (!barcodes.value.length) return ElMessage.warning('请选择数据!')
sampleSign({ status: val, barcode: barcodes.value }).then((res: any) => {
if (res.code == 0) {
ElMessage.success('操作成功!')
handleQuery()
}
})
}
const handleSelectionChange = (val: any) => {
barcodes.value = val.map((item: any) => item.barcode)
}
const currentChange = (page: { currentPage: number, pageSize: number }) => {
queryParams.value.pageNum = page.currentPage
handleQuery()
}
const sizeChange = (page: { currentPage: number, pageSize: number }) => {
queryParams.value.pageSize = page.pageSize
handleQuery()
}
const handleQuery = () => {
if (queryParams.value.times && queryParams.value.times.length > 0) {
queryParams.value.DateStart = queryParams.value.times[0]
queryParams.value.DateEnd = queryParams.value.times[1]
} else {
queryParams.value.DateStart = ''
queryParams.value.DateEnd = ''
}
getList()
}
const resetHandle = () => {
queryParams.value = {
pageSize: 50,
pageNum: 1,
}
handleQuery()
}
const getList = () => {
querySampleSignBack(queryParams.value).then((res: any) => {
tableData.value = res.rows
pagination.value.total = res.total
})
}
const hosList = ref([])
const regdictList: any = ref([])
onMounted(() => {
getList()
listhospital().then((res: any) => {
hosList.value = res.rows.map((item: any) => {
return {
label: item.hospitalName,
value: item.hospitalCode
}
})
})
listregdict({ pageSize: 100, pageNum: 1, dictType: 'ZT' }).then((res: any) => {
regdictList.value = res.rows;
})
})
const formatDict = (v: string, arr: Array<any>) => {
return arr.find((item: any) => item.dictCode == v)?.dictName || v;
};
</script>
<style scoped lang="scss">
.compact-form {
height: 5rem;
.el-form-item {
margin-bottom: 5px;
}
}
.btns {
display: flex;
flex-direction: column;
justify-content: space-around;
&>button {
width: 100%;
margin-left: 0;
margin-bottom: 5px;
}
}
</style>

View File

@ -0,0 +1,168 @@
<template>
<div>
<el-button @click="handleClick">查询病人</el-button>
<!-- 病人选择弹窗 -->
<el-dialog v-model="dialogVisible" :title="props.dialogTitle" width="500px" @close="handleDialogClose">
<el-input v-model="searchKey" placeholder="搜索(支持姓名、病人ID、简拼)..." class="mb-4" clearable @clear="filteredPatData"
@input="filteredPatData" @keyup.down="navigateTable('down')" @keyup.up="navigateTable('up')"
@keyup.enter="selectActiveItem" />
<el-table :data="filteredPatData" height="300px" border @row-click="selectItem" @row-dblclick="selectItem"
class="compact-form my-table">
<template #empty>
<div v-if="isPatLoading">加载中...</div>
<div v-else>没有匹配的病人数据</div>
</template>
<el-table-column prop="pid" label="病人ID" width="100" show-overflow-tooltip />
<el-table-column prop="name" label="姓名" width="100" show-overflow-tooltip />
<el-table-column prop="xb" label="性别" width="80" show-overflow-tooltip />
<el-table-column prop="nl" label="年龄" width="80" show-overflow-tooltip />
<el-table-column prop="ks" label="科室" width="100" show-overflow-tooltip />
<el-table-column prop="ch" label="床号" width="80" show-overflow-tooltip />
<el-table-column prop="pinyin" label="简拼" width="150" show-overflow-tooltip />
</el-table>
</el-dialog>
</div>
</template>
<script setup>
import { ref, computed, watch, onMounted } from 'vue';
import { queryPatList } from "@/api/mzcx/cydj.ts";
import { getFirstLetter } from '@/utils/pinyin'; // 引入拼音处理工具
// 组件参数
const props = defineProps({
pidValue: { type: [String, Number], default: '' },
PatType: { type: String },
placeholder: { type: String, default: '请输入或双击选择' },
clearable: { type: Boolean, default: true },
disabled: { type: Boolean, default: false },
dialogTitle: { type: String, default: '选择病人' }
});
// 组件事件
const emit = defineEmits(['update:pidValue', 'select']);
// 内部状态
const dialogVisible = ref(false);
const searchKey = ref('');
const PatData = ref([]); // 存储带简拼的病人数据
const isPatLoading = ref(true);
const activeRowIndex = ref(-1); // 键盘导航选中行索引
// 加载病人数据
const loadPatData = async () => {
isPatLoading.value = true;
queryPatList().then(response => {
// console.log('response:', response.data);
PatData.value = (response.data || []).map(item => ({
...item,
pinyin: getFirstLetter(item.name)
}));
}).catch(() => {
console.error(`加载病人列表失败:`, error);
PatData.value = [];
}).finally(() => {
isPatLoading.value = false;
});
};
// 过滤病人数据(使用 computed 提高性能)
const filteredPatData = computed(() => {
const key = searchKey.value.trim().toLowerCase();
if (!key) return PatData.value;
return PatData.value.filter(item => {
const matchName = item.name.toLowerCase().includes(key);
const matchPid = String(item.pid).toLowerCase().includes(key);
const matchPinyin = item.pinyin.toLowerCase().includes(key);
return matchName || matchPid || matchPinyin;
});
});
// 点击按钮事件处理
const handleClick = () => {
loadPatData();
// if (!props.disabled && !isPatLoading.value) {
dialogVisible.value = true;
searchKey.value = '';
activeRowIndex.value = -1;
// }
};
// 选择病人项
const selectItem = (item) => {
emit('update:pidValue', item.pid);
emit('select', item.pid);
dialogVisible.value = false;
};
// 键盘导航
const navigateTable = (direction) => {
if (!filteredPatData.value.length) return;
if (direction === 'down') {
activeRowIndex.value = (activeRowIndex.value + 1) % filteredPatData.value.length;
} else if (direction === 'up') {
activeRowIndex.value = (activeRowIndex.value - 1 + filteredPatData.value.length) % filteredPatData.value.length;
}
};
// 选择当前活动行
const selectActiveItem = () => {
if (activeRowIndex.value >= 0 && activeRowIndex.value < filteredPatData.value.length) {
selectItem(filteredPatData.value[activeRowIndex.value]);
}
};
// 关闭弹窗
const handleDialogClose = () => {
dialogVisible.value = false;
activeRowIndex.value = -1;
};
</script>
<style scoped>
/* 可选:添加活动行样式 */
:deep(.el-table__row.active) {
background-color: #e6f7ff !important;
}
::v-deep .my-table .el-table__row td {
padding: 1px 0;
/* 减小行高 */
}
::v-deep .my-table .el-table__header-wrapper th {
padding: 6px 0;
/* 表头内边距 */
background-color: #b3d8ff !important;
/* 表头背景色(保留之前的设置) */
color: #333;
/* 文字颜色加深,提升可读性 */
font-weight: 500;
/* 文字加粗 */
}
::v-deep .my-table .el-table__cell {
padding: 0 2px;
/* 减小列间距 */
}
/* 可选:调整表格整体样式 */
::v-deep .my-table {
font-size: 13px;
/* 适当减小字体 */
}
::v-deep .my-table .el-table__cell,
::v-deep .my-table .el-table__header-wrapper th {
border-width: 1px;
border-color: #ebeef5;
}
</style>

View File

@ -0,0 +1,543 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-position="left">
<el-row :gutter="5">
<el-form-item label="" label-width="0px" prop="brdh">
<el-col :span="6">
<div> 就诊卡号/病历号/磁卡号: </div>
<el-input v-model="queryParams.brdh" placeholder="就诊卡号/病历号/磁卡号" clearable @keyup.enter="handleQuery" />
</el-col>
<el-col :span="2">
<el-radio-group v-model="queryParams.zt" size="default">
<el-radio v-for="(item, index) in showconfirmOptions" :key="index" :value="item.value"
:disabled="item.disabled">{{ item.label }}</el-radio>
</el-radio-group>
</el-col>
<el-col :span="1">
<div> 申请获取期限: </div>
</el-col>
<el-col :span="6">
<el-radio-group v-model="queryParams.subday" size="default">
<el-radio v-for="(item, index) in subdayOptions" :key="index" :value="item.value"
:disabled="item.disabled">{{ item.label }}</el-radio>
</el-radio-group>
</el-col>
<el-col :span="3">
<el-select v-model="queryParams.cardtype" placeholder="卡类型" clearable :style="{ width: '100%' }">
<el-option v-for="(item, index) in cardtypeOptions" :key="index" :label="item.label" :value="item.value"
:disabled="item.disabled"></el-option>
</el-select>
</el-col>
<el-col :span="2">
<el-button type="primary" icon="Search" @click="readCard">读卡</el-button>
</el-col>
<el-col :span="2">
<PatSearchDialog @select="handlePatientSelect" />
</el-col>
</el-form-item>
</el-row>
</el-form>
<el-row :gutter="5" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Search" @click="handleQuery">查询</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Printer" :disabled="single" @click="printAll">打印</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Printer" :disabled="single" @click="printSigne">单打条码</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Printer" :disabled="freesingle" @click="printBack">单打回单</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Delete" @click="cancel">取消采样</el-button>
</el-col>
</el-row>
<el-row :gutter="5" class="table-container">
<el-table ref="tableRef" :data="reqmainList" @selection-change="handleSelectionChange" @select="handleSelect"
height="100%" :cell-style="tableCellStyle">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="项目名称" align="center" prop="sqxmmc" width="200" show-overflow-tooltip />
<el-table-column label="项目代码" align="center" prop="sqxmdh" width="100" show-overflow-tooltip />
<el-table-column label="项目类别" align="center" prop="cp_xmlb" />
<el-table-column label="样本类型" align="center" prop="yblx" />
<el-table-column label="条码号" align="center" prop="sqh" width="150" show-overflow-tooltip />
<el-table-column label="申请时间" align="center" prop="sqsj" width="180" show-overflow-tooltip>
<template #default="scope">
<span>{{ parseTime(scope.row.sqsj, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="病人姓名" align="center" prop="brxm" show-overflow-tooltip />
<el-table-column label="申请医生" align="center" prop="sqys" :formatter="formatDict('SRD')" show-overflow-tooltip />
<el-table-column label="序号" align="center" prop="xh" show-overflow-tooltip />
<el-table-column label="数量" align="center" prop="sl" show-overflow-tooltip />
<el-table-column label="单价" align="center" prop="dj" show-overflow-tooltip />
<el-table-column label="状态" align="center" prop="zt" show-overflow-tooltip />
<el-table-column label="计价" align="center" prop="jjzt">
<template #default="scope">
<el-checkbox :model-value="scope.row.jjzt === '1'" disabled>
</el-checkbox>
</template>
</el-table-column>
<el-table-column label="病人代号" align="center" prop="brdh" show-overflow-tooltip />
<el-table-column label="备注1" align="center" prop="detailBZ1" show-overflow-tooltip />
<el-table-column label="备注2" align="center" prop="detailBZ2" show-overflow-tooltip />
<el-table-column label="颜色" align="center" prop="cp_color" v-if="false" show-overflow-tooltip />
<el-table-column label="确认标识" align="center" prop="cp_cflag" v-if="false" show-overflow-tooltip />
<el-table-column label="科室" align="center" prop="ksdh" :formatter="formatDict('DP')" show-overflow-tooltip />
<el-table-column label="病人类型" align="center" prop="brly" :formatter="formatDict('PT')" show-overflow-tooltip />
<el-table-column label="性别" align="center" prop="brxb" :formatter="formatDict('SX')" show-overflow-tooltip />
<el-table-column label="生日" align="center" prop="brsr" width="180" show-overflow-tooltip>
<template #default="scope">
<span>{{ parseTime(scope.row.brsr, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="床号" align="center" prop="ch" width="50" show-overflow-tooltip />
<el-table-column label="诊断" align="center" prop="zd" width="150" show-overflow-tooltip />
<el-table-column label="条码类别" align="center" prop="bgddh" v-if="false" show-overflow-tooltip />
<el-table-column label="年龄" align="center" prop="nl" show-overflow-tooltip />
<el-table-column label="年龄单位" align="center" prop="nldw" :formatter="formatDict('AU')" show-overflow-tooltip />
<el-table-column label="采样时间" align="center" prop="cysj" width="180" show-overflow-tooltip>
<template #default="scope">
<span>{{ parseTime(scope.row.cysj, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
</el-table>
</el-row>
<!-- 汇总行 -->
<div class="table-summary">
<div class="summary-item">
<span class="summary-label">条码数:</span>
<span class="summary-value">{{ idsnew.length }}</span>
</div>
<div class="summary-item">
<span class="summary-label">项目数:</span>
<span class="summary-value">{{ totalRows }}</span>
</div>
<div class="summary-item">
<span class="summary-label">合计金额:</span>
<span class="summary-value">{{ totalPrice.toFixed(2) }}</span>
</div>
</div>
</div>
</template>
<script setup>
import {
querySQD,
queryPatList,
printBackpaper,
printBarcodeall
} from "@/api/mzcx/cydj.js";
import { querySample } from '@/api/regional/index'
import PatSearchDialog from '../components/OutPatList.vue'
// import PatSearchDialog from './components/OutPatList.vue'
import { classCom } from '@/utils/classCom';
const comDict = inject('comDict');
// 字典数据存储
const dictData = ref({});
const tableRef = ref(null);
const { proxy } = getCurrentInstance();
// 选中的行
const selectedRows = ref([]);
const reqmainList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
// 新增:计算属性,返回去重后的ids数组
const idsnew = computed(() => {
return [...new Set(ids.value)];
});
const single = ref(true);
const freesingle = ref(true);
const cardtypeOptions = ref([{ "label": "就诊卡", "value": 1 }, { "label": "医保卡", "value": 2 }, { "label": "电子医保卡", "value": 3 }, { "label": "身份证", "value": 4 }])
const showconfirmOptions = ref([{ "label": "未打印", "value": 1 }, { "label": "已打印", "value": 11 }])
const subdayOptions = ref([{ "label": "1天", "value": 1 }, { "label": "3天", "value": 3 }, { "label": "1周", "value": 7 }, { "label": "2周", "value": 14 }, { "label": "1月", "value": 30 }, { "label": "3月", "value": 90 }, { "label": "1年", "value": 365 }, { "label": "2年", "value": 730 }])
const data = reactive({
form: {},
queryParams: {
brdh: null,
stime: null,
etime: null,
klx: null,
zt: 1,
subday: 3000,
cardtype: null,
Status: '10'
},
rules: {
brdh: [
{ required: true, message: "病人代码不能为空", trigger: "blur" }
],
subday: [],
}
});
const { queryParams, form, rules } = toRefs(data);
// 标志位:是否是程序自动勾选(避免循环触发事件)
const isAutoSelect = ref(false);
/**
* 监听单选勾选/取消事件
* @param {Array} selection 目前已选中的行
* @param {Object} row 当前操作的行数据
* @param {Boolean} selected 是否勾选(true=勾选,false=取消)
*/
const handleSelect = (selection, row, selected) => {
if (isAutoSelect.value) return;
const targetSqh = row.sqh;
const targetxh = row.xh;
if (!targetSqh) return;
// 先收集需要自动勾选的行(避免在循环中修改数据)
const rowsToSelect = reqmainList.value.filter(
item => item.sqh === targetSqh && item.xh !== targetxh
);
// 如果有需要自动勾选的行,才开启标志位
if (rowsToSelect.length > 0) {
rowsToSelect.forEach(item => {
tableRef.value.toggleRowSelection(item, selected);
isAutoSelect.value = true;
});
setTimeout(() => isAutoSelect.value = false, 0);
}
};
// 字典格式化方法
const formatDict = (dictType) => {
return (row, column, value) => {
// 从全局字典中获取映射值
return dictData.value[dictType].find(item => String(item.value) === String(value).trim())?.label || value;
};
};
// 定义“空数据”的判断函数
const isEmptyData = (data) => {
// 处理 null/undefined
if (data === null || data === undefined) return true;
// 处理空数组
if (Array.isArray(data) && data.length === 0) return true;
// 处理空对象(无任何属性)
if (typeof data === 'object' && Object.keys(data).length === 0) return true;
// 处理空字符串
if (typeof data === 'string' && data.trim() === '') return true;
return false;
};
/**
* 获取指定天数偏移后的日期时间字符串
* @param {number} days 偏移天数(正数表示未来,负数表示过去)
* @returns {string} 格式化的日期时间字符串 'yyyy-mm-dd HH:MM:SS'
*/
function getDateOffset(days) {
const now = new Date();
const offsetTimestamp = now.getTime() + days * 24 * 60 * 60 * 1000;
const targetDate = new Date(offsetTimestamp);
const year = targetDate.getFullYear();
const month = String(targetDate.getMonth() + 1).padStart(2, '0');
const day = String(targetDate.getDate()).padStart(2, '0');
// const hours = String(targetDate.getHours()).padStart(2, '0');
// const minutes = String(targetDate.getMinutes()).padStart(2, '0');
//const seconds = String(targetDate.getSeconds()).padStart(2, '0');
// return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
return `${year}-${month}-${day} 00:00:00`;
}
function getSubday() {
const days = 0 - queryParams.value.subday;
queryParams.value.stime = getDateOffset(days);
queryParams.value.etime = getDateOffset(1);
}
/** 查询采样登记列表 */
function getList() {
freesingle.value = true;
if (isEmptyData(queryParams.value.brdh)) proxy.$modal.alert("请刷卡或输入门诊号!");
else {
loading.value = true;
getSubday();
querySample(queryParams.value).then(response => {
if (isEmptyData(response.data)) proxy.$modal.alert("没有检索的数据!");
reqmainList.value = response.data;
// console.log('response:', response.data);
loading.value = false;
single.value = false;
// 新增:数据加载完成后触发全选
// 延迟执行(确保DOM已更新)
setTimeout(() => {
if (tableRef.value) {
tableRef.value.toggleAllSelection(); // 调用全选方法
}
}, 0);
});
}
}
// 取消按钮
function cancel() {
// open.value = false;
// reset();
}
// 表单重置
function reset() {
form.value = {
sqh: null,
xh: null,
sqxmdh: null,
sqxmmc: null,
sl: null,
dj: null,
detailZT: null,
detailJJZT: null,
ksdh: null,
sqys: null,
sqsj: null,
jsys: null,
jssj: null,
brly: null,
brdh: null,
brxm: null,
zt: null,
jjzt: null,
brxb: null,
brsr: null,
jzbz: null,
cp_xmlb: null,
cp_color: null,
cp_cflag: null,
detailBZ1: null,
ch: null,
detailBZ2: null,
bz1: null,
bz2: null,
bz3: null,
yblx: null,
zxys: null,
zxsj: null,
bgddh: null,
nl: null,
nldw: null,
zd: null,
cysj: null
};
freesingle.value = false;
single.value = false;
proxy.resetForm("reqmainRef");
}
/** 搜索按钮操作 */
function handleQuery() {
getList();
}
function readCard() {
//getList();
}
// 处理病人选择事件
const handlePatientSelect = (patient) => {
// console.log('选中的病人:', patient);
queryParams.value.brdh = patient
// 处理选中的病人数据
handleQuery();
};
// 多选框选中数据
function handleSelectionChange(selection) {
if (isAutoSelect.value) return;
selectedRows.value = selection;
ids.value = selection.map(item => item.sqh);
}
/** 打印选择 */
function printAll(row) {
printSigne();
printBack();
}
/** 单打条码*/
function printSigne(row) {
if (idsnew.value.length === 0) {
return;
}
printBarcodeall(idsnew.value).then(response => {
proxy.$modal.msgSuccess("打印成功");
open.value = false;
freesingle.value = false;
}).catch(() => {
});
}
/** 打印回单 */
function printBack(row) {
if (idsnew.value.length === 0) {
return;
}
//console.log('idsnew:', idsnew.value)
printBackpaper(idsnew.value).then(response => {
proxy.$modal.msgSuccess("打印成功");
open.value = false;
}).catch(() => {
});
}
const totalRows = computed(() => {
return reqmainList.value.length || 0;
});
const totalPrice = computed(() => {
return reqmainList.value.reduce((sum, row) => {
const price = parseFloat(row.dj) || 0;
return sum + price;
}, 0);
});
// 组件挂载时加载字典
onMounted(async () => {
// 加载病人来源字典
const dictRefs = await comDict('PT', 'DP', 'SRD', 'BT', 'SX', 'AU');
// 从 ref 中获取实际数据
dictData.value = {
PT: toRaw(dictRefs.PT.value) || [],
DP: toRaw(dictRefs.DP.value) || [],
SRD: toRaw(dictRefs.SRD.value) || [],
BT: toRaw(dictRefs.BT.value) || [],
SX: toRaw(dictRefs.SX.value) || [],
AU: toRaw(dictRefs.AU.value) || []
};
});
// 表格单元格样式(仅作用于“项目类别”列)
const tableCellStyle = ({ row, column }) => {
// 只对“项目类别”列生效
if (column.label === '项目类别') {
// 1. 转换颜色(十进制→十六进制)
const bgColor = classCom.decimalToHexColor(row.cp_color);
// 2. 自动计算文字颜色(确保和背景色对比度足够)
const textColor = classCom.getContrastTextColor(bgColor);
return {
backgroundColor: bgColor, // 背景色(转换后的值)
color: textColor, // 文字色(自动适配)
textAlign: 'center', // 文字居中
fontWeight: '500' // 文字加粗(提升可读性)
};
}
return {}; // 其他列保持默认样式
};
</script>
<style scoped lang="scss">
.app-container {
display: flex;
flex-direction: column;
height: 90vh;
/* 容器高度等于窗口高度 */
overflow: hidden;
}
.compact-form {
height: 75px;
/* 固定高度 */
}
.mb8 {
height: 30px;
/* 固定高度 */
}
.table-summary {
height: 10px;
/* 固定高度 */
}
.table-container {
flex: 1;
/* 占满剩余高度 */
overflow: hidden;
/* 避免表格超出容器 */
}
.compact-form .el-form-item {
padding: 5px;
margin-bottom: 5px;
}
.compact-form .el-form-item__label {
padding-bottom: 0px;
}
.card-content {
max-height: 450px;
/* 设置最大高度 */
overflow-y: auto;
/* 超出高度时显示垂直滚动条 */
padding: 5px;
/* 保持与卡片默认一致的内边距 */
}
.clickable:hover {
cursor: pointer;
/* 鼠标悬停时显示手型 */
transition: all 0.3s;
/* 平滑过渡效果 */
color: blue;
}
/* 汇总行样式 */
.table-summary {
display: flex;
align-items: center;
justify-content: flex-start;
padding: 6px 16px;
margin-top: 8px;
background-color: #f5f7fa;
border: 1px solid #ebeef5;
border-radius: 4px;
font-weight: 500;
line-height: 24px;
/* 汇总行文字行高 */
.summary-item {
display: flex;
align-items: center;
margin-left: 24px;
.summary-label {
color: #606266;
margin-right: 8px;
}
.summary-value {
color: #303133;
min-width: 40px;
text-align: left;
/* 核心:数值左对齐 */
}
/* 单独设置"单价合计"的值为红色 */
&:nth-child(3) .summary-value {
color: #f56c6c;
/* Element UI 红色主题色 */
font-weight: 600;
/* 可选:加粗字体 */
}
}
}
</style>

View File

@ -0,0 +1,255 @@
<template>
<div class="app-container">
<div class="compact-form">
<el-form :model="queryParams" ref="queryRef" label-width="5rem" style="width: 100%;" :size="aotuSize">
<el-row :gutter="10">
<el-col :span="5">
<el-form-item label="委托机构:" prop="SrcHospName">
<SelectTable v-model:data="queryParams.SrcHospName" :fields="ksdhFields" :tableData="hosList"
label="label" :size="aotuSize" value="value" objKey="value" :border="true" placeholder="请选择委托机构" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="检测医院:" prop="DstHospName">
<SelectTable v-model:data="queryParams.DstHospName" :fields="ksdhFields" :tableData="hosList"
label="label" :size="aotuSize" value="label" objKey="label" :border="true" placeholder="请选择" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="条码号:" prop="Barcode">
<el-input v-model="queryParams.Barcode" placeholder="请输入条码号" clearable @change="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="姓名:" prop="PatName">
<el-input v-model="queryParams.PatName" placeholder="请输入姓名" clearable @change="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="申请项目:" prop="checkPUR">
<el-input v-model="queryParams.checkPUR" placeholder="请输入申请项目" clearable @change="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="时间类型:" prop="DateType">
<el-select v-model="queryParams.DateType" placeholder="请选择">
<el-option label="登记时间" value="登记时间" />
<el-option label="采样时间" value="采样时间" />
<el-option label="送出时间" value="送出时间" />
<el-option label="签收时间" value="签收时间" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="日期:" prop="times">
<el-date-picker v-model="queryParams.times" type="daterange" range-separator="-" start-placeholder="开始时间"
end-placeholder="结束时间" format="YYYY-MM-DD" value-format="YYYY-MM-DD" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</el-col>
</el-row>
</el-form>
</div>
<div class="cz_box">
<el-row :gutter="10">
<el-col :span="1.5"> 送检医院:</el-col>
<el-col :span="4">
<SelectTable v-model:data="dstHospCode" :fields="ksdhFields" :tableData="hosList" label="label"
:size="aotuSize" value="value" objKey="value" :border="true" placeholder="请选择" @get-data-value="getValue" />
</el-col>
<el-col :span="1.5"> <el-button type="primary" :size="aotuSize" @click="sjHandle(30)">标本送检</el-button></el-col>
<el-col :span="1.5"> <el-button type="primary" :size="aotuSize" @click="sjHandle(20)">取消送检</el-button></el-col>
</el-row>
</div>
<CustomTable ref="tableRefs" :data="tableData" :columns="columns" :config="tableConfig" :pagination="pagination"
@selection-change="handleSelectionChange" @size-change="sizeChange" @page-change="currentChange">
<template #patAge="{ row }">
{{ row.patAge }}{{ row.ageUnit }}
</template>
<template #status="{ row }">
{{ formatDict(row.status, regdictList) }}
</template>
<template #patSex="{ row }">
{{ row.patSex == 1 ? '男' : '女' }}
</template>
</CustomTable>
</div>
</template>
<script setup lang="ts">
import CustomTable from '@/components/elTable/index.vue'
import { querySample, sampleSign } from '@/api/regional/index'
// @ts-ignore
import { listhospital } from "@/api/regional/dict/hospital.js";
// @ts-ignore
import { listregdict } from "@/api/regional/dict/regdict.js";
import SelectTable from '@/components/SelectTable/index.vue';
import { classCom } from '@/utils/classCom';
import { ElMessage } from 'element-plus';
const aotuSize = classCom.useAutoSize();
const queryParams: any = ref({
pageSize: 50,
pageNum: 1,
Status: '30'
})
const tableData: any = ref([])
const columns: any = ref([
{ type: 'selection', align: 'center', visible: true, width: 40 },
{ prop: 'barcode', label: '条码号', align: 'center', visible: true, },
{ prop: 'srcHospName', label: '委托机构', align: 'center', visible: true, width: 250 },
{ prop: 'patName', label: '姓名', align: 'center', visible: true, width: 60 },
{ prop: 'patSex', label: '性别', align: 'center', visible: true, width: 60, slot: "patSex" },
{ prop: 'patAge', label: '年龄', align: 'center', visible: true, slot: "patAge", width: 60 },
{ prop: 'checkPUR', label: '申请项目', align: 'center', visible: true, width: 250 },
{ prop: 'sampleTypeName', label: '标本类型', align: 'center', visible: true, },
{ prop: 'status', label: '标本状态', align: 'center', visible: true, slot: "status" },
{ prop: 'affirmUserName', label: '采样人', align: 'center', visible: true, },
{ prop: 'affirmTime', label: '采样时间', align: 'center', visible: true, width: 150 },
{ prop: 'affirmTime', label: '送检时间', align: 'center', visible: true, },
{ prop: 'dstHospName', label: '检测机构名称', align: 'center', visible: true, },
])
const tableConfig = ref({
border: true, // 边框
height: '70vh', // 高度
highlightCurrentRow: true, // 高亮当前行
// fit: true, // 列宽自适应
})
const pagination = ref({
show: true,
total: 0,
pageSize: 50,
currentPage: 1,
})
const ksdhFields = ref([
{ prop: 'label', label: '名称', width: 150, enablePinyinSearch: true },
{ prop: 'value', label: '代号', width: 120, enablePinyinSearch: true },
])
const dstHospName = ref('')
const dstHospCode = ref('')
const barcodes = ref([])
const handleSelectionChange = (val: any) => {
barcodes.value = val.map((item: any) => item.barcode)
}
const getValue = (val: any) => {
console.log('val==>', val);
dstHospName.value = val.label
}
const sjHandle = (val: number) => {
if (!barcodes.value.length) return ElMessage.warning('请选择数据!')
if (!dstHospCode.value) return ElMessage.warning('请选择送检医院!')
const params = {
barcode: barcodes.value,
dstHospName: dstHospName.value,
dstHospCode: dstHospCode.value,
status: val
}
sampleSign(params).then((res: any) => {
if (res.code == 0) {
ElMessage.success('操作成功!')
handleQuery()
dstHospCode.value = ''
}
})
}
const currentChange = (page: { currentPage: number, pageSize: number }) => {
queryParams.value.pageNum = page.currentPage
handleQuery()
}
const sizeChange = (page: { currentPage: number, pageSize: number }) => {
queryParams.value.pageSize = page.pageSize
handleQuery()
}
const handleQuery = () => {
if (queryParams.value.times && queryParams.value.times.length > 0) {
queryParams.value.DateStart = queryParams.value.times[0]
queryParams.value.DateEnd = queryParams.value.times[1]
} else {
queryParams.value.DateStart = ''
queryParams.value.DateEnd = ''
}
getList()
}
const resetHandle = () => {
queryParams.value = {
pageSize: 50,
pageNum: 1,
Status: '30'
}
handleQuery()
}
const getList = () => {
querySample(queryParams.value).then((res: any) => {
tableData.value = res.rows
pagination.value.total = res.total
})
}
const hosList = ref([])
const regdictList: any = ref([])
onMounted(() => {
getList()
listhospital().then((res: any) => {
hosList.value = res.rows.map((item: any) => {
return {
label: item.hospitalName,
value: item.hospitalCode
}
})
})
listregdict({ pageSize: 100, pageNum: 1, dictType: 'ZT' }).then((res: any) => {
regdictList.value = res.rows;
})
})
const formatDict = (v: string, arr: Array<any>) => {
return arr.find((item: any) => item.dictCode == v)?.dictName || v;
};
</script>
<style scoped lang="scss">
.compact-form {
height: 5rem;
.el-form-item {
margin-bottom: 5px;
}
}
.btns {
display: flex;
flex-direction: column;
justify-content: space-around;
&>button {
width: 100%;
margin-left: 0;
margin-bottom: 5px;
}
}
.cz_box {
padding: .3125rem 0;
border-top: 1px solid #ccc;
}
</style>

View File

@ -0,0 +1,802 @@
<template>
<div class="app-container ">
<div ref="compactForm">
<el-row :gutter="10" class="compact-form" v-show="showSearch">
<el-form :model="queryParams" ref="queryRef" :inline="true" :size="aotuSize" :rules="queryRules">
<el-form-item label="日期:" prop="failed1">
<el-date-picker v-model="queryParams.times" type="datetimerange" range-separator="-"
start-placeholder="开始时间" end-placeholder="结束时间" format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss" @change="handletime" style="width: 25rem;" />
</el-form-item>
<el-form-item label="委托机构:" prop="SrcHospName">
<SelectTable v-model:data="queryParams.SrcHospName" :fields="ksdhFields" :tableData="hosList" label="label"
width="12.5rem" :size="aotuSize" value="label" objKey="label" :border="true" placeholder="请选择委托机构" />
</el-form-item>
<el-form-item label="条码状态:" prop="zt">
<el-select v-model="queryParams.zt" placeholder="请选择" style="width: 6.25rem;">
<el-option v-for="item in dictData.ST" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="" prop="failed4">
<el-select v-model="queryParams.failed4" placeholder="请选择" style="width:8.75rem">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="" prop="failed5">
<el-input v-model="queryParams.failed5" clearable placeholder="条件搜索" @keyup.enter="handleQuery"
@clear="handleQuery" />
</el-form-item>
<el-form-item label="">
<el-button icon="search" type="primary" @click="handleQuery" :size="aotuSize"> 搜索 </el-button>
<el-button icon="Refresh" @click="resetQuery" :size="aotuSize">重置</el-button>
</el-form-item>
</el-form>
</el-row>
</div>
<el-row :gutter="10">
<el-col :span="16" class="right-table">
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" :size="aotuSize" :loading="btnLoading" plain icon="Plus"
@click="printHandle">生成条码</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" :size="aotuSize" plain icon="Edit" @click="selectStatusRows">选中所有未打印</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" :size="aotuSize" plain @click="printPdf">打印条码</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" :size="aotuSize" plain icon="Upload" @click="openBlock('采样登记')">采样登记</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" :size="aotuSize" plain @click="openBlock('送检登记')">送检登记</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" :size="aotuSize" plain @click="goReport">报告查询</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" :size="aotuSize" plain @click="cancelHandle">条码作废</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" :size="aotuSize" plain @click="sendSampleHandle">清单打印</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" :size="aotuSize" plain @click="changePrinter">打印机设置</el-button>
</el-col>
</el-row>
<CustomTable ref="tableRef" :data="tableData" :columns="columns" :config="tableConfig" :loading="loading"
@row-click="rowHandle" @selection-change="selectionChange" :enable-column-drag="true"
@column-drag-end="handleColumnDragEnd">
<template #dy="{ row }">
<svg-icon v-if="row.zt != 1" icon-class="lvgou" />
</template>
<template #srcHospName="{ row }">
武汉市汉阳区江堤街社区卫生服务中心
</template>
<template #jzbz="{ row }">
{{ row.jzbz == '1' ? '急' : '' }}
</template>
<template #jjzt="{ row }">
{{ row.jjzt == '1' ? '计价' : '无' }}
</template>
<template #brly="{ row }">
{{ formatDict(row.brly, 'PT') }}
</template>
<template #zt="{ row }">
{{ formatDict(row.zt.trim(), 'ST') }}
</template>
<template #yljg="{ row }">
{{ formatDict(row.yljg, 'HOS') }}
</template>
</CustomTable>
</el-col>
<el-col :span="8" class="right-table">
<!-- <div class="title"> 项目 </div> -->
<el-button type="primary" plain class="mb8" :size="aotuSize">拆分选中项目</el-button>
<CustomTable :data="rightTableData" :columns="rightColumns" :config="rightTableConfig">
<template #jjzt="{ row }">
{{ row.jjzt == '1' ? '计价' : '无' }}
</template>
<template #zt="{ row }">
{{ formatDict(row.zt, 'ST') }}
</template>
</CustomTable>
</el-col>
</el-row>
<!-- 样本流程 -->
<div class="time-line-box">
<div v-for="(item, i) in timelineItems" :key="i" class="time-line-item">
<div v-if="i != 0" class="timeline-connector">
<img class="timg" src="@/assets/images/yjt.png" alt="">
</div>
<div :class="['timeline-content', i > lastTimeIndex ? 'no_active' : '']">
<div :class="['index', lastTimeIndex == i ? 'active' : '']">{{ i + 1 }}</div>
<div class="timeline-title">{{ item.title }}</div>
<div class="timeline-time">{{ item.time }}</div>
</div>
</div>
</div>
<!-- 采样登记 -->
<el-dialog v-model="dialogVisible" :title="title" draggable :close-on-click-modal="false" width="70vw"
@close="closeDialog">
<div class="flex-between">
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-input v-model="sqhText" clearable placeholder="条形码" @keyup.enter="sqdQuery" @clear="sqdQuery" />
</el-col>
<el-col :span="1.5">
<el-button type="primary" @click="sqdQuery" plain>读取</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="delete">删除选中行</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain>打印</el-button>
</el-col>
</el-row>
<!-- <el-button type="primary" plain>保存</el-button> -->
</div>
<CustomTable :data="cyTableData" :columns="cyColumns" :config="cyTableConfig">
<template #zt="{ row }">
{{ formatDict(row.zt, 'ST') }}
</template>
</CustomTable>
</el-dialog>
<el-dialog v-model="previewShow" title="预览" width="90vw" :close-on-click-modal="false">
<iFrame v-if="pdfUrl" :src="pdfUrl" />
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, toRaw, computed, watch, nextTick, onMounted, } from 'vue';
import { HiprintPrinter } from '@/utils/hiprintPrinter';
import { classCom } from '@/utils/classCom';
import CustomTable from '@/components/elTable/index.vue'
import { useRouter } from 'vue-router'
import { usePrintStore } from '@/store/modules/printStore'
import { fetchCodeList, addObj, fetchCodeDetail, fetchCodeExec, fetchCodeReqmain, printSendSample, printsetup } from '@/api/checkCode/index'
// @ts-ignore
import { listhospital } from "@/api/regional/dict/hospital.js";
const aotuSize = classCom.useAutoSize();
//@ts-ignore
import { comDict } from '@/utils/dict'
import SelectTable from '@/components/SelectTable/index.vue';
import { ElMessage, ElMessageBox } from 'element-plus'
// @ts-ignore
import iFrame from "@/components/iFrame/index.vue";
import { checkPrintService } from '@/utils/printHelper';
const router = useRouter()
const printStore = usePrintStore();
const printerList = computed(() => printStore.printerList);
const printName = ref(printStore.defaultPrinter || '');
const compactForm = ref<HTMLElement | null>(null);
const heightForm = ref(90);
const dialogVisible = ref(false)
const title = ref('采样登记')
const sqhText = ref('')
const tableRef = ref()
interface QueryParams {
times: string[]; // 明确类型为字符串元组
yljg: string;
zt: string;
failed4: string;
failed5: string;
SrcHospName: string;
userid: string;
}
// 提交表单数据
const queryParams = reactive<QueryParams>({
times: ['2025-07-18 00:00:00', '2025-07-18 23:59:59'],
userid: '',
yljg: '1',
zt: '',
SrcHospName: '',
failed4: '',
failed5: '',
});
const showSearch = ref(true);
const queryRef = ref()
// 定义校验规则
const queryRules = ref({
// clientId: [
// { required: true, message: '编号不能为空', trigger: 'blur' },
// ],
// failed3: [
// { required: true, message: '条码状态不能为空', trigger: 'change' },
// ],
})
const options = [
{
value: '1',
label: '通过姓名搜索',
},
{
value: '2',
label: '通过病人号搜索',
},
{
value: '3',
label: '通过床号搜索',
},
]
interface DictData {
SX?: Array<any>;
HOS?: Array<any>;
[key: string]: any[] | undefined; // 添加索引签名以支持动态访问
}
// 字典数据存储
const dictData = ref<DictData>({});
const handleQuery = async () => {
const valid = await queryRef.value.validate().catch(() => { });
if (!valid) return false;
getList()
}
// 重置
const resetQuery = () => {
queryRef.value?.resetFields();
getList()
}
const loading = ref(true);
// 数据源
const tableData = ref([])
// 配置项
const columns = ref([
{ type: 'selection', visible: true, align: 'center', width: 40, label: '多选框' },
{ prop: 'srcHospName', label: '委托机构', visible: true, align: 'center', width: 200, slot: 'srcHospName' },
{ prop: 'zt', label: '打印', visible: true, align: 'center', slot: 'dy', width: 40 },
{ prop: 'jzbz', label: '急', align: 'center', visible: true, slot: 'jzbz', width: 30 },
{ prop: 'ch', label: '床号', visible: true, align: 'center', width: 40 },//sortable: true,
{ prop: 'brxm', label: '姓名', align: 'center', visible: true, width: 50 },
{ prop: 'brxbname', label: '性别', align: 'center', visible: true, width: 30 },
{ prop: 'jymd', label: '项目名称', visible: true, width: 130 },
{ prop: 'bgddhname', label: '类别', align: 'center', visible: true, width: 80 },
{ prop: 'sampletips', label: '采样提示', align: 'center', visible: true, width: 60 },
{ prop: 'yblx', label: '样本类型', align: 'center', visible: true, width: 60 },
{ prop: 'brdh', label: '病人号', align: 'center', visible: true, width: 90 },
{ prop: 'ksname', label: '科室名称', align: 'center', visible: true, width: 100 },
{ prop: 'sqh', label: '申请号/条码', align: 'center', visible: true, width: 100 },
{ prop: 'zt', label: '状态', align: 'center', visible: true, slot: 'zt', width: 40 },
{ prop: 'brly', label: '病人来源', align: 'center', visible: true, slot: 'brly', width: 60 },
{ prop: 'sqysname', label: '申请医生', align: 'center', visible: true, width: 60 },
{ prop: 'sqsj', label: '申请时间', align: 'center', visible: true, width: 150 },
{ prop: 'jjzt', label: '计价标志', align: 'center', visible: true, slot: 'jjzt', width: 60 },
{ prop: 'zxysname', label: '执行医生', align: 'center', visible: true, width: 60 },
{ prop: 'bbsjrname', label: '送检人', align: 'center', visible: true, width: 50 },
{ prop: 'yljg', label: '检验机构', align: 'center', visible: true, slot: 'yljg', width: 150 },
])
const single = ref(true);
const multiple = ref(true);
const sqhs = ref([]);
// 单元格样式
const cellStyleHd = ({ row, column, rowIndex, columnIndex }: {
row: any;
column: any;
rowIndex: number;
columnIndex: number;
}) => {
// console.log(row, column, rowIndex, columnIndex);
if (column.label == "急" && row.jzbz == "1") {
return { color: '#f00' };
}
if (column.label == "类别") {
const bgColor = classCom.decimalToHexColor(row.bkcolor);
const textColor = classCom.getContrastTextColor(bgColor);
return {
backgroundColor: `${bgColor} !important`,
color: textColor,
};
}
};
const ksdhFields = ref([
{ prop: 'label', label: '名称', width: 150, enablePinyinSearch: true },
{ prop: 'value', label: '代号', width: 120, enablePinyinSearch: true },
])
const rowClassNameHd = ({ row, rowIndex }: {
row: any;
rowIndex: number;
}) => {
return 'custom-row-class'; // 返回自定义类名
};
// 时间线数据
const timelineItems = ref(
[
{ title: '检验申请', time: '' },
{ title: '标本采集', time: '' },
{ title: '标本送检', time: '' },
{ title: '标本签收', time: '' },
{ title: '上机检验', time: '' },
{ title: '结果审核', time: '' },
]
);
// 计算最后一个有时间的节点索引
const lastTimeIndex = computed(() => {
const lastIndex = timelineItems.value.findLastIndex(item => item.time);
if (lastIndex === -1) {
return -1
} else {
return lastIndex;
}
});
// 点击行
const rowHandle = (row: any) => {
timelineItems.value =
[
{ title: '检验申请', time: row.sqsj },
{ title: '标本采集', time: row.cysj },
{ title: '标本送检', time: row.bbsjsj },
{ title: '标本签收', time: row.jssj },
{ title: '上机检验', time: row.sjsj },
{ title: '结果审核', time: row.confirmtime },
]
getRightTable(row)
};
const selectionChange = (selection: any) => {
sqhs.value = selection;
single.value = selection.length != 1;
multiple.value = !selection.length;
}
const handleColumnDragEnd = (data: any) => {
// 更新列配置
columns.value = data.columns;
// 可以在这里保存列顺序到本地存储等
// localStorage.setItem('tableColumnOrder', JSON.stringify(data.columns));
};
// 左侧表格配置
const tableConfig = ref({
// stripe: true, // 斑马纹
border: true, // 边框
index: true, // 序号
height: '', // 高度
highlightCurrentRow: true, // 高亮当前行
cellStyle: cellStyleHd,
rowClassName: rowClassNameHd,
fit: true
})
// 右侧数据源
const rightTableData = ref([])
// 配置项
const rightColumns = ref([
{ prop: 'sqxmdh', label: '项目代号', visible: true, sortable: true, width: '110px' },
{ prop: 'sqxmmc', label: '项目名称', visible: true, width: '120px' },
{ prop: 'dj', label: '单价', align: 'center', visible: true, },
{ prop: 'sl', label: '数量', align: 'center', visible: true, },
{ prop: 'zt', label: '状态', align: 'center', visible: true, slot: 'zt', },
{ prop: 'jjzt', label: '计价标志', align: 'center', visible: true, slot: 'jjzt', },
])
// 表格配置
const rightTableConfig = ref({
// stripe: true, // 斑马纹
border: true, // 边框
height: '', // 高度
highlightCurrentRow: true, // 高亮当前行
})
// 采样数据源
const cyTableData = ref([])
// 配置项
const cyColumns = ref([
{ prop: 'sqh', label: '申请号/条形码', align: 'center', visible: true, sortable: true, width: 140 },
{ prop: 'ksdh', label: '科室病区', align: 'center', visible: true, width: 120 },
{ prop: 'ch', label: '床号', align: 'center', visible: true, sortable: true, },
{ prop: 'brxm', label: '姓名', align: 'center', visible: true, },
{ prop: 'brdh', label: '病人号', align: 'center', visible: true, },
{ prop: 'brxb', label: '性别', align: 'center', visible: true, },
{ prop: 'yblx', label: '样本类型', align: 'center', visible: true, },
{ prop: 'zt', label: '状态', align: 'center', visible: true, slot: 'zt', },
{ prop: 'jzbz', label: '急诊', align: 'center', visible: true, },
{ prop: 'jjzt', label: '采样人', align: 'center', visible: true, },
{ prop: 'cysj', label: '采样时间', align: 'center', visible: true, },
{ prop: 'zxysname', label: '执行医生', align: 'center', visible: true, },
{ prop: 'zxsj', label: '执行时间', align: 'center', visible: true, },
])
// 表格配置
const cyTableConfig = ref({
border: true, // 边框
height: '100%', // 高度
highlightCurrentRow: true, // 高亮当前行
})
// 采样登记
const openBlock = (value: string) => {
if (sqhs.value.length > 0) {
ElMessageBox.confirm(`确定操作选中的数据吗?`, "提示", {
confirmButtonText: "确认",
cancelButtonText: "取消",
beforeClose: async (action, instance, done) => {
if (action === "confirm") {
// 生成请求Promise数组
const requests = sqhs.value.map((item: any) => { return item.sqh });
fetchCodeExec({
sqh: requests.join(','),
userid: 'lis',
status: value == '采样登记' ? 12 : 13,
yljg: 1
}).then((res: any) => {
if (res.code == 0) {
ElMessage.success('调用成功');
done();
getList()
} else {
ElMessage.error('调用失败');
}
})
} else {
done();
}
},
}).catch(() => { });
} else {
title.value = value
dialogVisible.value = true
}
}
// 采样读取
const sqdQuery = () => {
const index = cyTableData.value.findIndex((item: any) => item.sqh == sqhText.value)
if (index !== -1) return ElMessage.warning('该申请单数据已存在!')
fetchCodeReqmain({ sqh: sqhText.value }).then((res: any) => {
if (res.code == 0 && res.data.sqh) {
fetchCodeExec({
sqh: res.data.sqh,
userid: 'lis',
status: 12,
yljg: 1
})
cyTableData.value = cyTableData.value.concat(res.data)
}
})
}
// 关闭弹窗清空
const closeDialog = () => {
cyTableData.value = []
sqhText.value = ''
}
interface ColumnItem {
prop: string;
label: string;
visible: boolean;
key: number;
align: string;
slot: string;
width: string;
}
// 更新列
// const updateColumns = (arr: Array<ColumnItem>) => {
// columns.value = arr
// };
const getRightTable = (row: any) => {
fetchCodeDetail({ sqh: row.sqh }).then((res: any) => {
if (res.code == 0) {
rightTableData.value = res.data
}
})
}
const goReport = () => {
// 跳转到报告查询页面
router.push('/regional/inspectionReport/report?startdate=2025-08-19&endate=2025-08-19&deptcode=0210&userid=00910&brdh=')
};
const cancelHandle = () => {
if (sqhs.value.length <= 0) return ElMessage.warning('请选择数据!')
ElMessageBox.confirm(`确定作废选中的数据吗?`, "提示", {
confirmButtonText: "确认",
cancelButtonText: "取消",
beforeClose: async (action, instance, done) => {
if (action === "confirm") {
const requests = sqhs.value.map((item: any) => { return item.sqh });
fetchCodeExec({
sqh: requests.join(','),
userid: 'lis',
status: 9,
yljg: 1
}).then((res: any) => {
if (res.code == 0) {
ElMessage.success('调用成功');
done();
getList()
} else {
ElMessage.error('调用失败');
}
})
} else {
done();
}
},
}).catch(() => { });
}
const pdfUrl = ref('')
const previewShow = ref(false)
const sendSampleHandle = () => {
const selections = tableRef.value.allSelection()
if (selections.length <= 0) return ElMessage.warning('请选择数据!')
const arr = selections.map((item: any) => { return item.sqh });
printSendSample(arr).then((res: any) => {
if (res.code == 0) {
const url = res.data
if (!url) return ElMessage.warning('未查询到文件')
pdfUrl.value = `data:application/pdf;base64,${url}`
previewShow.value = true
}
})
}
const changePrinter = (value: string) => {
checkPrintService().then((isConnected) => {
if (isConnected) {
printsetup()
}
})
};
const hosList = ref([])
onMounted(async () => {
// 初始化3天区间(今天-前两天)
// const end = dayjs().format('YYYY-MM-DD HH:mm:ss');
// const start = dayjs().subtract(2, 'day').format('YYYY-MM-DD HH:mm:ss'); //add 时间往后
// queryParams.times = [start, end];
// console.log(queryParams.times);
getList()
adjustTableHeight();
// 加载病人来源字典
const dictRefs = await comDict('PT', 'HOS', 'ST');
// 从 ref 中获取实际数据
dictData.value = {
PT: toRaw(dictRefs.PT.value) || [],
HOS: toRaw(dictRefs.HOS.value) || [],
ST: toRaw(dictRefs.ST.value) || [],
};
listhospital().then((res: any) => {
hosList.value = res.rows.map((item: any) => {
return {
label: item.hospitalName,
value: item.hospitalCode
}
})
});
})
// 字典格式化方法
const formatDict = (v: string, dictType: string) => {
return dictData.value[dictType]?.find((item: any) => item.value == v)?.label || v;
};
// 计算table高度
watch(showSearch, () => {
nextTick(() => {
adjustTableHeight();
})
}, { immediate: true });
function adjustTableHeight() {
if (compactForm.value) {
// 获取高度
heightForm.value = compactForm.value.offsetHeight;
tableConfig.value.height = `calc(74vh - ${heightForm.value}px)`; // 设置表格容器的高度
rightTableConfig.value.height = `calc(74vh - ${heightForm.value}px)`;
}
}
const handletime = (val: Array<string>) => {
// console.log('时间', val);
}
const btnLoading = ref(false);
// 生成条码
const printHandle = () => {
btnLoading.value = true;
const data = {
dept: '0235',
userid: 'lis',
st: '',
et: '',
yljg: queryParams.yljg
}
if (queryParams.times && queryParams.times.length) {
data.st = queryParams.times[0]
data.et = queryParams.times[1]
}
addObj(data).then((res: any) => {
if (res.code == 0) {
getList()
}
}).finally(() => {
btnLoading.value = false;
});
}
// 查询申请单
const getList = () => {
loading.value = true;
const data = {
dept: '0235',
userid: 'lis',
st: queryParams.times[0],
et: queryParams.times[1],
yljg: queryParams.yljg
}
fetchCodeList(data).then((response: any) => {
if (response.code == 0) {
loading.value = false;
tableData.value = response.data
if (tableData.value.length > 0) {
rowHandle(response.data[0])
getRightTable(response.data[0])
tableRef.value.setCurrentRow(response.data[0])
}
}
})
}
const selectStatusRows = () => {
tableRef.value.clearSelection()
tableData.value.forEach((item: any) => {
if (item.zt == 1) {
tableRef.value.toggleRowSelection(item, true)
}
})
}
// 打印pdf
const printPdf = () => {
checkPrintService().then((isConnected) => {
if (!isConnected) return
const selections = tableRef.value.allSelection()
if (selections.length <= 0) return ElMessage.warning('请选择数据!')
ElMessageBox.confirm(`确定打印选中的数据吗?`, "提示", {
confirmButtonText: "确认",
cancelButtonText: "取消",
beforeClose: async (action, instance, done) => {
if (action === "confirm") {
const requests = selections.map((item: any) => item.sqh)
const res = await fetchCodeExec({
sqh: requests.join(','),
userid: queryParams.userid,
status: 11,
yljg: queryParams.yljg
})
if (res.code === 0) {
done()
getList()
}
} else {
done()
}
},
}).catch(() => { })
})
}
</script>
<style scoped lang="scss">
.custom-row-class {
background-color: #c6c3ff !important;
/* 设置行背景色 */
}
.right-table {
border: 1px solid #E1E9F7;
padding-top: .3125rem;
}
.title {
border-bottom: 1px solid #E1E9F7;
margin-bottom: .625rem;
padding: .625rem;
font-weight: 700;
}
.time-line-box {
display: flex;
justify-content: space-around;
align-items: center;
margin-top: .35rem;
background-color: #f0f3f8;
padding: .3rem 2.5rem;
}
.time-line-item {
display: flex;
align-items: center;
justify-content: space-around;
width: 16.6%;
// padding: 0 30px;
.timeline-content {
display: flex;
flex-direction: column;
align-items: center;
.index {
width: 1.875rem;
height: 1.875rem;
line-height: 1.875rem;
background: #E1E9F7;
border-radius: 50%;
text-align: center;
font-family: SourceHanSansCN, SourceHanSansCN;
font-weight: 500;
font-size: 1.125rem;
color: #4767A3;
}
.active {
background-color: #4096ff;
box-shadow: 0 0 0 .25rem rgba(64, 150, 255, 0.2);
color: #FFF;
}
.timeline-title {
font-family: SourceHanSansCN, SourceHanSansCN;
font-weight: 500;
font-size: 1rem;
color: #4767A3;
}
.timeline-time {
font-family: SourceHanSansCN, SourceHanSansCN;
font-weight: 400;
font-size: .875rem;
color: #4767A3;
}
}
.timg {
width: 3.125rem;
}
}
</style>

View File

@ -0,0 +1,228 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="诊断编码" prop="diagCode">
<el-input v-model="queryParams.diagCode" placeholder="请输入诊断编码" clearable style="width: 200px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="诊断名称" prop="diagName">
<el-input v-model="queryParams.diagName" placeholder="请输入诊断名称" clearable style="width: 200px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="诊断状态" clearable style="width: 200px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="diagnosisList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="诊断编号" align="center" prop="diagId" />
<el-table-column label="诊断编码" align="center" prop="diagCode" />
<el-table-column label="诊断名称" align="center" prop="diagName" />
<el-table-column label="诊断排序" align="center" prop="diagSort" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
<!-- 添加或修改诊断对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="diagnosisRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="诊断名称" prop="diagName">
<el-input v-model="form.diagName" placeholder="请输入诊断名称" />
</el-form-item>
<el-form-item label="诊断编码" prop="diagCode">
<el-input v-model="form.diagCode" placeholder="请输入编码名称" />
</el-form-item>
<el-form-item label="诊断顺序" prop="diagSort">
<el-input-number v-model="form.diagSort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="诊断状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label
}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="diagnosis">
import { listdiagnosis, adddiagnosis, deldiagnosis, getdiagnosis, updatediagnosis } from "@/api/regional/dict/diagnosis";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const diagnosisList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 15,
diagCode: undefined,
diagName: undefined,
status: undefined
},
rules: {
diagName: [{ required: true, message: "诊断名称不能为空", trigger: "blur" }],
diagCode: [{ required: true, message: "诊断编码不能为空", trigger: "blur" }],
diagSort: [{ required: true, message: "诊断顺序不能为空", trigger: "blur" }],
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询诊断列表 */
function getList() {
loading.value = true;
listdiagnosis(queryParams.value).then(response => {
diagnosisList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
diagId: undefined,
diagCode: undefined,
diagName: undefined,
diagSort: 0,
status: "0",
remark: undefined
};
proxy.resetForm("diagnosisRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.diagId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加诊断";
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const diagId = row.diagId || ids.value;
getdiagnosis(diagId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改诊断";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["diagnosisRef"].validate(valid => {
if (valid) {
if (form.value.diagId != undefined) {
updatediagnosis(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
adddiagnosis(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const diagIds = row.diagId || ids.value;
proxy.$modal.confirm('是否确认删除诊断编号为"' + diagIds + '"的数据项?').then(function () {
return deldiagnosis(diagIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => { });
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/diagnosis/export", {
...queryParams.value
}, `diag_${new Date().getTime()}.xlsx`);
}
getList();
</script>

View File

@ -0,0 +1,227 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="医疗机构编码" prop="hospitalCode">
<el-input v-model="queryParams.hospitalCode" placeholder="请输入医疗机构编码" clearable style="width: 200px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="医疗机构名称" prop="hospitalName">
<el-input v-model="queryParams.hospitalName" placeholder="请输入医疗机构名称" clearable style="width: 200px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="有效状态" clearable style="width: 200px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" prop="hospitalId" />
<el-table-column label="医疗机构编码" align="center" prop="hospitalCode" />
<el-table-column label="医疗机构名称" align="center" prop="hospitalName" />
<el-table-column label="接口平台密钥" align="center" prop="hospitalUserinfo" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
<!-- 添加或修改医疗机构对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="postRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="医疗机构名称" prop="hospitalName">
<el-input v-model="form.hospitalName" placeholder="请输入医疗机构名称" />
</el-form-item>
<el-form-item label="医疗机构编码" prop="hospitalCode">
<el-input v-model="form.hospitalCode" placeholder="请输入编码名称" />
</el-form-item>
<el-form-item label="医疗机构密钥" prop="hospitalUserinfo">
<el-input v-model="form.hospitalUserinfo" placeholder="请输入编码密钥" />
</el-form-item>
<el-form-item label="医疗机构状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label
}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="hospital">
import { listhospital, addhospital, delhospital, gethospital, updatehospital } from "@/api/regional/dict/hospital.js";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const postList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
hospitalCode: undefined,
hospitalName: undefined,
status: undefined
},
rules: {
hospitalName: [{ required: true, message: "医疗机构名称不能为空", trigger: "blur" }],
hospitalCode: [{ required: true, message: "医疗机构编码不能为空", trigger: "blur" }],
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询医疗机构列表 */
function getList() {
loading.value = true;
listhospital(queryParams.value).then(response => {
postList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
hospitalId: undefined,
hospitalCode: undefined,
hospitalName: undefined,
hospitalUserinfo: undefined,
status: "0",
remark: undefined
};
proxy.resetForm("postRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.hospitalId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加医疗机构";
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const hospitalId = row.hospitalId || ids.value;
gethospital(hospitalId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改医疗机构";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["postRef"].validate(valid => {
if (valid) {
if (form.value.hospitalId != undefined) {
updatehospital(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addhospital(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const hospitalIds = row.hospitalId || ids.value;
proxy.$modal.confirm('是否确认删除医疗机构编号为"' + hospitalIds + '"的数据项?').then(function () {
return delhospital(hospitalIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => { });
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("transitdict/hospital/export", {
...queryParams.value
}, `hospital_${new Date().getTime()}.xlsx`);
}
getList();
</script>

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
</template>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,274 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="项目类别编码" prop="itemclassCode">
<el-input v-model="queryParams.itemclassCode" placeholder="请输入项目类别编码" clearable style="width: 200px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="项目类别名称" prop="itemclassName">
<el-input v-model="queryParams.itemclassName" placeholder="请输入项目类别名称" clearable style="width: 200px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="有效状态" clearable style="width: 200px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange"
:cell-style="tableCellStyle">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" prop="itemclassId" />
<el-table-column label="项目类别编码" align="center" prop="itemclassCode" />
<el-table-column label="项目类别名称" align="center" prop="itemclassName" show-overflow-tooltip />
<el-table-column label="试管名称" align="center" prop="itemclassTips" show-overflow-tooltip />
<el-table-column label="试管颜色" align="center" prop="itemclassBkcolor" show-overflow-tooltip />
<el-table-column label="默认样本类型" align="center" prop="itemclassYblx" show-overflow-tooltip />
<el-table-column label="打印次数" align="center" prop="itemclassPrintcnt" />
<el-table-column label="抗凝样本" width="80" align="center" prop="itemclassKn">
<template #default="scope">
<el-checkbox :checked="scope.row.itemclassKn === 1 || scope.row.itemclassKn === '1'" disabled />
</template>
</el-table-column>
<el-table-column label="排序" align="center" prop="itemclassSort" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
<!-- 添加或修改项目类别对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="postRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="项目类别名称" prop="itemclassName">
<el-input v-model="form.itemclassName" placeholder="请输入类别名称" />
</el-form-item>
<el-form-item label="项目类别编码" prop="itemclassCode">
<el-input v-model="form.itemclassCode" placeholder="请输入类别编码" />
</el-form-item>
<el-form-item label="试管名称" prop="itemclassTips">
<el-input v-model="form.itemclassUserinfo" placeholder="请输入试管名称" />
</el-form-item>
<el-form-item label="试管颜色" prop="itemclassBkcolor">
<el-input-number v-model="form.itemclassBkcolor" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="默认样本类型" prop="itemclassYblx">
<el-input v-model="form.itemclassYblx" placeholder="请输入默认样本类型" />
</el-form-item>
<el-form-item label="打印次数" prop="itemclassPrintcnt">
<el-input-number v-model="form.itemclassPrintcnt" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="抗凝样本" prop="itemclassKn">
<el-checkbox v-model="form.itemclassKn" true-label="1" false-label="0" />
</el-form-item>
<el-form-item label="类别顺序" prop="itemclassSort">
<el-input-number v-model="form.itemclassSort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="项目类别状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label
}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="itemclass">
import { listitemclass, additemclass, delitemclass, getitemclass, updateitemclass } from "@/api/regional/dict/itemclass.js";
import { classCom } from '@/utils/classCom';
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const postList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 15,
itemclassCode: undefined,
itemclassName: undefined,
status: undefined
},
rules: {
itemclassName: [{ required: true, message: "项目类别名称不能为空", trigger: "blur" }],
itemclassCode: [{ required: true, message: "项目类别编码不能为空", trigger: "blur" }],
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询项目类别列表 */
function getList() {
loading.value = true;
listitemclass(queryParams.value).then(response => {
postList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
itemclassId: undefined,
itemclassCode: undefined,
itemclassName: undefined,
itemclassUserinfo: undefined,
itemclassTips: undefined,
itemclassBkcolor: 255,
itemclassYblx: undefined,
itemclassPrintcnt: 1,
itemclassKn: 0,
status: "0",
remark: undefined
};
proxy.resetForm("postRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.itemclassId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加项目类别";
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const itemclassId = row.itemclassId || ids.value;
getitemclass(itemclassId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改项目类别";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["postRef"].validate(valid => {
if (valid) {
if (form.value.itemclassId != undefined) {
updateitemclass(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
additemclass(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const itemclassIds = row.itemclassId || ids.value;
proxy.$modal.confirm('是否确认删除项目类别编号为"' + itemclassIds + '"的数据项?').then(function () {
return delitemclass(itemclassIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => { });
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("transitdict/itemclass/export", {
...queryParams.value
}, `itemclass_${new Date().getTime()}.xlsx`);
}
const tableCellStyle = ({ row, column }) => {
// 只对“项目类别”列生效
if (column.label === '试管颜色') {
// 1. 转换颜色(十进制→十六进制)
const bgColor = classCom.decimalToHexColor(row.itemclassBkcolor);
// 2. 自动计算文字颜色(确保和背景色对比度足够)
const textColor = classCom.getContrastTextColor(bgColor);
return {
backgroundColor: bgColor, // 背景色(转换后的值)
color: textColor, // 文字色(自动适配)
textAlign: 'center', // 文字居中
fontWeight: '500' // 文字加粗(提升可读性)
};
}
return {}; // 其他列保持默认样式
};
getList();
</script>

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
</template>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,238 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item :label="menuname + '编码'" prop="dictCode">
<el-input v-model="queryParams.dictCode" :placeholder="`请输入${menuname}编码`" clearable style="width: 200px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item :label="`${menuname}名称`" prop="dictName">
<el-input v-model="queryParams.dictName" :placeholder="`请输入${menuname}名称`" clearable style="width: 200px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="状态" clearable style="width: 200px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="regdictList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column :label="`${menuname}编号`" align="center" prop="dictId" v-if="false" />
<el-table-column :label="`${menuname}编码`" align="center" prop="dictCode" />
<el-table-column :label="`${menuname}名称`" align="center" prop="dictName" />
<el-table-column label="排序" align="center" prop="dictSort" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
<!-- 添加或修改字典对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="regdictRef" :model="form" :rules="rules" label-width="150px">
<el-form-item :label="`${menuname}编码`" prop="dictCode">
<el-input v-model="form.dictCode" :placeholder="`请输入${menuname}编码名称`" />
</el-form-item>
<el-form-item :label="`${menuname}名称`" prop="dictName">
<el-input v-model="form.dictName" :placeholder="`请输入${menuname}名称`" />
</el-form-item>
<el-form-item label="顺序" prop="dictSort">
<el-input-number v-model="form.dictSort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label
}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="regdict">
import { listregdict, addregdict, delregdict, getregdict, updateregdict } from "@/api/regional/dict/regdict.js";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const route = useRoute();
const regdictList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const menuname = ref("字典");
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 15,
dictCode: undefined,
dictName: undefined,
dictType: undefined,
status: undefined
},
rules: {
dictName: [{ required: true, message: menuname.value + "名称不能为空", trigger: "blur" }],
dictCode: [{ required: true, message: menuname.value + "编码不能为空", trigger: "blur" }],
dictSort: [{ required: true, message: menuname.value + "顺序不能为空", trigger: "blur" }],
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询字典列表 */
function getList() {
loading.value = true;
listregdict(queryParams.value).then(response => {
regdictList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
dictId: undefined,
dictCode: undefined,
dictName: undefined,
dictType: queryParams.value.dictType,
dictSort: 0,
status: "0",
remark: undefined
};
proxy.resetForm("regdictRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.dictId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加" + menuname.value;
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const dictId = row.dictId || ids.value;
getregdict(dictId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改" + menuname.value;
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["regdictRef"].validate(valid => {
if (valid) {
if (form.value.dictId != undefined) {
updateregdict(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addregdict(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const dictIds = row.dictId || ids.value;
proxy.$modal.confirm('是否确认删除"' + menuname + '"编号为"' + dictIds + '"的数据项?').then(function () {
return delregdict(dictIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => { });
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/regdict/export", {
...queryParams.value
}, `dict_${new Date().getTime()}.xlsx`);
}
getTypes(route.query && route.query.dictType, route.query && route.query.typeName);
/** 查询字典类型详细 */
function getTypes(dictType, typeName) {
queryParams.value.dictType = dictType;
menuname.value = typeName;
getList();
}
</script>

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
</template>
<style scoped lang="scss">
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,238 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="参数代号" prop="dictCode">
<el-input v-model="queryParams.dictCode" placeholder="请输入" clearable style="width: 200px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="参数名称" prop="dictName">
<el-input v-model="queryParams.dictName" placeholder="请输入" clearable style="width: 200px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="状态" clearable style="width: 200px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="regdictList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="参数代号" align="center" prop="dictCode" />
<el-table-column label="参数名称" align="center" prop="dictName" />
<el-table-column label="参数值" align="center" prop="remark" />
<el-table-column label="排序" align="center" prop="dictSort" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" />
<!-- 添加或修改字典对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="regdictRef" :model="form" :rules="rules" label-width="150px">
<el-form-item label="参数代号" prop="dictCode">
<el-input v-model="form.dictCode" placeholder="请输入参数代号" />
</el-form-item>
<el-form-item label="参数名称" prop="dictName">
<el-input v-model="form.dictName" placeholder="请输入参数名称" />
</el-form-item>
<el-form-item label="顺序" prop="dictSort">
<el-input-number v-model="form.dictSort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label
}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="参数值" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="regdict">
import { listregdict, addregdict, delregdict, getregdict, updateregdict } from "@/api/regional/dict/regdict.js";
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const route = useRoute();
const regdictList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const menuname = ref("字典");
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 15,
dictCode: undefined,
dictName: undefined,
dictType: undefined,
status: undefined
},
rules: {
dictName: [{ required: true, message: "参数名称不能为空", trigger: "blur" }],
dictCode: [{ required: true, message: "参数代号不能为空", trigger: "blur" }],
dictSort: [{ required: true, message: "顺序不能为空", trigger: "blur" }],
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询字典列表 */
function getList() {
loading.value = true;
listregdict(queryParams.value).then(response => {
regdictList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
dictId: undefined,
dictCode: undefined,
dictName: undefined,
dictType: queryParams.value.dictType,
dictSort: 0,
status: "0",
remark: undefined
};
proxy.resetForm("regdictRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.dictId);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加参数"
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const dictId = row.dictId || ids.value;
getregdict(dictId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改参数"
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["regdictRef"].validate(valid => {
if (valid) {
if (form.value.dictId != undefined) {
updateregdict(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addregdict(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const dictIds = row.dictId || ids.value;
proxy.$modal.confirm('是否确认删除参数编号为' + dictIds + '"的数据项?').then(function () {
return delregdict(dictIds);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => { });
}
/** 导出按钮操作 */
function handleExport() {
proxy.download("system/regdict/export", {
...queryParams.value
}, `dict_${new Date().getTime()}.xlsx`);
}
getTypes(route.query && route.query.dictType, route.query && route.query.typeName);
/** 查询字典类型详细 */
function getTypes(dictType, typeName) {
queryParams.value.dictType = dictType;
menuname.value = typeName;
getList();
}
</script>

View File

@ -0,0 +1,223 @@
<template>
<div class="app-container">
<div class="compact-form">
<el-form :model="queryParams" ref="queryRef" label-width="5rem" style="width: 100%;" :size="aotuSize">
<el-row :gutter="10">
<el-col :span="5">
<el-form-item label="委托机构:" prop="SrcHospName">
<SelectTable v-model:data="queryParams.SrcHospName" :fields="ksdhFields" :tableData="hosList"
label="label" :size="aotuSize" value="value" objKey="value" :border="true" placeholder="请选择委托机构" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="检测医院:" prop="DstHospName">
<SelectTable v-model:data="queryParams.DstHospName" :fields="ksdhFields" :tableData="hosList"
label="label" :size="aotuSize" value="label" objKey="label" :border="true" placeholder="请选择" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="条码号:" prop="Barcode">
<el-input v-model="queryParams.Barcode" placeholder="请输入条码号" clearable />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="姓名:" prop="PatName">
<el-input v-model="queryParams.PatName" placeholder="请输入姓名" clearable />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="申请项目:" prop="checkPUR">
<el-input v-model="queryParams.checkPUR" placeholder="请输入申请项目" clearable />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="时间类型:" prop="DateType">
<el-select v-model="queryParams.DateType" placeholder="请选择">
<el-option label="登记时间" value="登记时间" />
<el-option label="采样时间" value="采样时间" />
<el-option label="送出时间" value="送出时间" />
<el-option label="签收时间" value="签收时间" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="日期:" prop="times">
<el-date-picker v-model="queryParams.times" type="daterange" range-separator="-" start-placeholder="开始时间"
end-placeholder="结束时间" format="YYYY-MM-DD" value-format="YYYY-MM-DD" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</el-col>
</el-row>
</el-form>
</div>
<div class="mb10">
<el-button type="primary" @click="thHandle(20)">重新采集</el-button>
<el-button type="primary" @click="thHandle(50)">撤销退回</el-button>
<el-button type="primary" @click="thHandle(90)">申请作废</el-button>
</div>
<div style="height: calc(100% - 180px)">
<CustomTable ref="tableRefs" :data="tableData" :columns="columns" :config="tableConfig" :pagination="pagination"
@selection-change="handleSelectionChange" @size-change="sizeChange" @page-change="currentChange">
<template #patAge="{ row }">
{{ row.patAge }}{{ row.ageUnit }}
</template>
<template #status="{ row }">
{{ formatDict(row.status, regdictList) }}
</template>
<template #patSex="{ row }">
{{ row.patSex == 1 ? '男' : '女' }}
</template>
</CustomTable>
</div>
</div>
</template>
<script setup lang="ts">
import CustomTable from '@/components/elTable/index.vue'
import { querySampleSignBack, sampleSign } from '@/api/regional/index'
import SelectTable from '@/components/SelectTable/index.vue';
import { classCom } from '@/utils/classCom';
// @ts-ignore
import { listhospital } from "@/api/regional/dict/hospital.js";
// @ts-ignore
import { listregdict } from "@/api/regional/dict/regdict.js";
import { ElMessage } from 'element-plus';
const aotuSize = classCom.useAutoSize();
const queryParams: any = ref({
pageSize: 50,
pageNum: 1,
})
const tableData: any = ref([])
const columns: any = ref([
{ type: 'selection', align: 'center', visible: true, width: 40 },
{ prop: 'barcode', label: '条码号', align: 'center', visible: true, },
{ prop: 'patName', label: '姓名', align: 'center', visible: true, width: 60 },
{ prop: 'patSex', label: '性别', align: 'center', visible: true, width: 60, slot: "patSex" },
{ prop: 'patAge', label: '年龄', align: 'center', visible: true, slot: "patAge", width: 60 },
{ prop: 'checkPUR', label: '申请项目', align: 'center', visible: true, width: 200 },
{ prop: 'srcHospName', label: '委托机构', align: 'center', visible: true, width: 200 },
{ prop: 'srcHospName', label: '检测机构', align: 'center', visible: true, width: 200 },
{ prop: 'Status', label: '标本状态', align: 'center', visible: true, slot: "status" },
{ prop: 'backReasons', label: '退回理由', align: 'center', visible: true, width: 150 },
{ prop: 'affirmTime', label: '采样时间', align: 'center', visible: true, width: 150 },
{ prop: 'backUserName', label: '操作人', align: 'center', visible: true, },
{ prop: 'backTime', label: '操作时间', align: 'center', visible: true, width: 150 },
])
const tableConfig = ref({
border: true, // 边框
height: '100%', // 高度
highlightCurrentRow: true, // 高亮当前行
// fit: true, // 列宽自适应
})
const pagination = ref({
show: true,
total: 0,
pageSize: 50,
currentPage: 1,
})
const ksdhFields = ref([
{ prop: 'label', label: '名称', width: 150, enablePinyinSearch: true },
{ prop: 'value', label: '代号', width: 120, enablePinyinSearch: true },
])
const barcodes = ref([])
const tableRefs = ref(null)
const thHandle = (val: number) => {
if (!barcodes.value.length) return ElMessage.warning('请选择数据!')
sampleSign({ status: val, barcode: barcodes.value }).then((res: any) => {
if (res.code == 0) {
ElMessage.success('操作成功!')
handleQuery()
}
})
}
const handleSelectionChange = (val: any) => {
barcodes.value = val.map((item: any) => item.barcode)
}
const currentChange = (page: { currentPage: number, pageSize: number }) => {
queryParams.value.pageNum = page.currentPage
handleQuery()
}
const sizeChange = (page: { currentPage: number, pageSize: number }) => {
queryParams.value.pageSize = page.pageSize
handleQuery()
}
const handleQuery = () => {
if (queryParams.value.times && queryParams.value.times.length > 0) {
queryParams.value.DateStart = queryParams.value.times[0]
queryParams.value.DateEnd = queryParams.value.times[1]
} else {
queryParams.value.DateStart = ''
queryParams.value.DateEnd = ''
}
getList()
}
const resetHandle = () => {
queryParams.value = {
pageSize: 50,
pageNum: 1,
}
handleQuery()
}
const getList = () => {
querySampleSignBack(queryParams.value).then((res: any) => {
tableData.value = res.rows
pagination.value.total = res.total
})
}
const hosList = ref([])
const regdictList: any = ref([])
onMounted(() => {
getList()
listhospital().then((res: any) => {
hosList.value = res.rows.map((item: any) => {
return {
label: item.hospitalName,
value: item.hospitalCode
}
})
})
listregdict({ pageSize: 100, pageNum: 1, dictType: 'ZT' }).then((res: any) => {
regdictList.value = res.rows;
})
})
const formatDict = (v: string, arr: Array<any>) => {
return arr.find((item: any) => item.dictCode == v)?.dictName || v;
};
</script>
<style scoped lang="scss">
.compact-form {
height: 5rem;
.el-form-item {
margin-bottom: 5px;
}
}
.btns {
display: flex;
flex-direction: column;
justify-content: space-around;
&>button {
width: 100%;
margin-left: 0;
margin-bottom: 5px;
}
}
</style>

View File

@ -0,0 +1,188 @@
<template>
<div class="app-container">
<div class="compact-form">
<el-form :model="queryParams" ref="queryRef" label-width="5rem" style="width: 100%;" :size="aotuSize">
<el-row :gutter="10">
<el-col :span="5">
<el-form-item label="就诊医院:" prop="SrcHospName">
<SelectTable v-model:data="queryParams.SrcHospName" :fields="ksdhFields" :tableData="hosList"
label="label" :size="aotuSize" value="value" objKey="value" :border="true" placeholder="请选择委托机构" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="检测医院:" prop="DstHospName">
<SelectTable v-model:data="queryParams.DstHospName" :fields="ksdhFields" :tableData="hosList"
label="label" :size="aotuSize" value="label" objKey="label" :border="true" placeholder="请选择" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="日期:" prop="times">
<el-date-picker v-model="queryParams.times" type="daterange" range-separator="-" start-placeholder="开始时间"
end-placeholder="结束时间" format="YYYY-MM-DD" value-format="YYYY-MM-DD" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button @click="resetHandle">重置</el-button>
</el-col>
</el-row>
</el-form>
</div>
<div class="mb10">
<!-- <el-button type="primary" @click="thHandle(20)">重新采集</el-button>
<el-button type="primary" @click="thHandle(50)">撤销退回</el-button>
<el-button type="primary" @click="thHandle(90)">申请作废</el-button> -->
</div>
<div style="height: calc(100% - 100px);">
<CustomTable ref="tableRefs" :data="tableData" :columns="columns" :config="tableConfig" :pagination="pagination"
@size-change="sizeChange" @page-change="currentChange">
</CustomTable>
</div>
</div>
</template>
<script setup lang="ts">
import CustomTable from '@/components/elTable/index.vue'
import { sampleitemCount, sampleSign } from '@/api/regional/index'
import SelectTable from '@/components/SelectTable/index.vue';
import { classCom } from '@/utils/classCom';
// @ts-ignore
import { listhospital } from "@/api/regional/dict/hospital.js";
// @ts-ignore
import { listregdict } from "@/api/regional/dict/regdict.js";
import { ElMessage } from 'element-plus';
const aotuSize = classCom.useAutoSize();
import dayjs from 'dayjs';
const today = dayjs().format('YYYY-MM-DD');
const queryParams: any = ref({
pageSize: 50,
pageNum: 1,
times: [today, today]
})
const tableData: any = ref([])
const columns: any = ref([
{ prop: 'SrcHospName', label: '就诊医院', align: 'center', visible: true, },
{ prop: 'SrcOrderItemCode', label: '组合编码', align: 'center', visible: true, },
{ prop: 'SrcOrderItemName', label: '组合名称', align: 'center', visible: true, },
{ prop: 'sl', label: '数量(份)', align: 'center', visible: true, },
{ prop: 'cost', label: '费用', align: 'center', visible: true, },
{ prop: 'DstHospName', label: '检测医院', align: 'center', visible: true, },
])
const tableConfig = ref({
border: true, // 边框
height: '100%', // 高度
highlightCurrentRow: true, // 高亮当前行
summary: true,
summaryField: ['sl', 'cost'],//计算列总和
sumText: '合计'
})
const pagination = ref({
show: true,
total: 0,
pageSize: 50,
currentPage: 1,
})
const ksdhFields = ref([
{ prop: 'label', label: '名称', width: 150, enablePinyinSearch: true },
{ prop: 'value', label: '代号', width: 120, enablePinyinSearch: true },
])
const barcodes = ref([])
const tableRefs = ref(null)
const thHandle = (val: number) => {
if (!barcodes.value.length) return ElMessage.warning('请选择数据!')
sampleSign({ status: val, barcode: barcodes.value }).then((res: any) => {
if (res.code == 0) {
ElMessage.success('操作成功!')
handleQuery()
}
})
}
const handleSelectionChange = (val: any) => {
barcodes.value = val.map((item: any) => item.barcode)
}
const currentChange = (page: { currentPage: number, pageSize: number }) => {
queryParams.value.pageNum = page.currentPage
handleQuery()
}
const sizeChange = (page: { currentPage: number, pageSize: number }) => {
queryParams.value.pageSize = page.pageSize
handleQuery()
}
const handleQuery = () => {
if (queryParams.value.times && queryParams.value.times.length > 0) {
queryParams.value.DateStart = queryParams.value.times[0]
queryParams.value.DateEnd = queryParams.value.times[1]
} else {
queryParams.value.DateStart = ''
queryParams.value.DateEnd = ''
}
getList()
}
const resetHandle = () => {
queryParams.value = {
pageSize: 50,
pageNum: 1,
times: [today, today]
}
handleQuery()
}
const getList = () => {
sampleitemCount(queryParams.value).then((res: any) => {
tableData.value = res.rows
pagination.value.total = res.total
})
}
const hosList = ref([])
const regdictList: any = ref([])
onMounted(() => {
handleQuery()
listhospital().then((res: any) => {
hosList.value = res.rows.map((item: any) => {
return {
label: item.hospitalName,
value: item.hospitalCode
}
})
})
listregdict({ pageSize: 100, pageNum: 1, dictType: 'ZT' }).then((res: any) => {
regdictList.value = res.rows;
})
})
const formatDict = (v: string, arr: Array<any>) => {
return arr.find((item: any) => item.dictCode == v)?.dictName || v;
};
</script>
<style scoped lang="scss">
.compact-form {
height: 2.5rem;
.el-form-item {
margin-bottom: 5px;
}
}
.btns {
display: flex;
flex-direction: column;
justify-content: space-around;
&>button {
width: 100%;
margin-left: 0;
margin-bottom: 5px;
}
}
</style>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,510 @@
@charset "UTF-8";
/* CSS Document */
.bg {
margin: 0 auto;
width: 100%;
min-height: 100vh;
background: url(../images/bg2.jpg) no-repeat;
background-size: 100% 100%;
padding-top: 0rem;
padding: 0rem 3.125rem;
}
/*.conIn{
display:flex;
display: -webkit-flex;}*/
.title {
width: 100%;
font-size: 1.875rem;
line-height: 4.6875rem;
color: rgba(14, 253, 255, 1);
text-align: center;
font-weight: bold;
}
.border_bg_leftTop {
position: absolute;
left: -0.125rem;
top: -0.625rem;
width: 5.78125rem;
height: 0.78125rem;
display: block;
background: #01279d url(../images/title_left_bg.png) no-repeat;
background-size: cover;
}
.border_bg_rightTop {
position: absolute;
right: -0.15625rem;
top: -0.15625rem;
width: 1.5625rem;
height: 1.5625rem;
display: block;
background: url(../images/border_bg.jpg) no-repeat;
background-size: cover;
}
.border_bg_leftBottom {
position: absolute;
left: -0.125rem;
bottom: -0.125rem;
width: 1.5625rem;
height: 1.5625rem;
display: block;
background: url(../images/border_bg.jpg) no-repeat;
background-size: cover;
}
.border_bg_rightBottom {
position: absolute;
right: -0.15625rem;
bottom: -0.15625rem;
width: 1.25rem;
height: 1.25rem;
display: block;
background: url(../images/title_right_bg.png) no-repeat;
background-size: cover;
}
.leftMain {
width: 75%;
float: left;
padding-right: 1.5625rem;
padding-top: 1.5625rem;
}
.rightMain {
width: 25%;
float: left;
padding-top: 1.5625rem;
}
.leftMain_top {
width: 100%;
padding-bottom: 1.5625rem;
}
.leftMain_top ul {
display: flex;
display: -webkit-flex;
}
.leftMain_top ul li {
float: left;
width: 25%;
padding-right: 1.5625rem;
}
.leftMain_top ul li:last-child {
padding: 0;
}
.leftMain_top ul li .liIn {
border: 0.125rem solid rgba(14, 253, 255, 0.5);
width: 100%;
min-height: 3.75rem;
position: relative;
padding: .625rem 1.5625rem;
}
.leftMain_top ul li .liIn h3 {
font-size: 1.25rem;
font-weight: 700;
color: #fff;
}
.leftMain_top ul li .liIn .shu {
font-size: 1.875rem;
color: rgba(14, 253, 255, 1);
font-family: dig;
margin-bottom: 0.3125rem;
}
.leftMain_top ul li .liIn .shu i {
font-size: 1rem;
margin-left: 0.9375rem;
font-style: normal;
}
.leftMain_top ul li .liIn .zi {
font-size: 0.625rem;
color: #fff;
position: relative;
z-index: 10;
}
.leftMain_top ul li .liIn .zi .span1 {
margin-right: 1.5625rem;
}
.leftMain_middle {
width: 100%;
padding-bottom: 1.5625rem;
display: flex;
display: -webkit-flex;
}
.leftMain_middle .leftMain_middle_left {
width: 60%;
padding-right: 1.5625rem;
}
.leftMain_middle .leftMain_middle_left .leftMain_middle_leftIn {
border: 0.125rem solid rgba(14, 253, 255, 0.5);
width: 100%;
min-height: 3.75rem;
position: relative;
padding: .625rem;
}
.leftMain_middle_leftIn_zhe {
margin-top: 2vh;
}
.leftMain_middle .leftMain_middle_left .leftMain_middle_leftIn h3 {
font-size: 1.25rem;
color: #fff;
font-weight: 700;
margin-bottom: 0.78125rem;
}
.leftMain_middle .leftMain_middle_left .leftMain_middle_leftIn .biaoge {
min-height: 12.5rem;
}
.leftMain_middle .leftMain_middle_right {
width: 40%;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn {
border: 0.125rem solid rgba(14, 253, 255, 0.5);
width: 100%;
min-height: 3.75rem;
position: relative;
padding: .625rem;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn h3 {
font-size: 1.25rem;
color: #fff;
font-weight: 700;
margin-bottom: 0.78125rem;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge {
min-height: 12.5rem;
}
/*左边中间部分排行榜*/
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai {
width: 100%;
height: 68vh;
overflow: hidden;
}
/* .leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul{
height: 68vh;
} */
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn {
display: flex;
display: -webkit-flex;
align-items: center;
color: #fff;
font-size: 0.9375rem;
height: 2.8125rem;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn .liIn_left {
width: 43%;
position: relative;
padding-left: 1.25rem;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn .liIn_left .bot {
width: 1.25rem;
height: 1.25rem;
background: #05d1fc;
border-radius: 62.5rem;
display: block;
position: absolute;
left: 0.3125rem;
top: 0;
bottom: 0;
margin: auto 0;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn2 .liIn_left .bot {
background: #e7feb8;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn3 .liIn_left .bot {
background: #fdea8a;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn4 .liIn_left .bot {
background: #8ff9f8;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn5 .liIn_left .bot {
background: #d890fa;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn6 .liIn_left .bot {
background: #05d1fc;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn .liIn_left zi {
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn .liIn_line {
width: 40%;
height: 1.25rem;
background: rgba(255, 255, 255, 0.5);
border-radius: 125rem;
overflow: hidden;
position: relative;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn .liIn_line .line_lineIn {
width: 100%;
height: 1.25rem;
background: #05d1fc;
border-radius: 125rem;
-webkit-animation: widthMove1 2s ease-in-out;
}
.line_lineIn .per {
position: absolute;
top: 0;
left: 50%;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn2 .liIn_line .line_lineIn {
background: #e7feb8;
-webkit-animation: widthMove2 2s ease-in-out;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn3 .liIn_line .line_lineIn {
background: #fdea8a;
-webkit-animation: widthMove3 2s ease-in-out;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn4 .liIn_line .line_lineIn {
background: #8ff9f8;
-webkit-animation: widthMove4 2s ease-in-out;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn5 .liIn_line .line_lineIn {
background: #d890fa;
-webkit-animation: widthMove5 2s ease-in-out;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn6 .liIn_line .line_lineIn {
background: #05d1fc;
-webkit-animation: widthMove6 2s ease-in-out;
}
@-webkit-keyframes widthMove1 {
0% {
width: 0%;
}
100% {
width: 98.5%;
}
}
@-webkit-keyframes widthMove2 {
0% {
width: 0%;
}
100% {
width: 88.5%;
}
}
@-webkit-keyframes widthMove3 {
0% {
width: 0%;
}
100% {
width: 68.5%;
}
}
@-webkit-keyframes widthMove4 {
0% {
width: 0%;
}
100% {
width: 40.5%;
}
}
@-webkit-keyframes widthMove5 {
0% {
width: 0%;
}
100% {
width: 22.5%;
}
}
@-webkit-keyframes widthMove6 {
0% {
width: 0%;
}
100% {
width: 10.5%;
}
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_pai ul li .liIn .num {
width: 18%;
font-family: dig;
padding-left: 0.3125rem;
}
/*左边底部*/
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_bi ul {
display: flex;
display: -webkit-flex;
flex-wrap: wrap;
width: 100%;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_bi ul li {
width: 33.3%;
text-align: center;
margin-bottom: 0.78125rem;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_bi ul li .shu {
font-size: 2.1875rem;
color: rgba(14, 253, 255, 1);
font-family: dig;
padding: 1.875rem 0 0.3125rem;
font-weight: normal;
}
.leftMain_middle .leftMain_middle_right .leftMain_middle_rightIn .biaoge_bi ul li .zi {
font-size: 0.9375rem;
color: #fff;
}
/*右边部分*/
.rightMain .rightMain_top {
width: 100%;
padding-bottom: 1.5625rem;
}
.rightMain .rightMain_topIn {
border: 0.125rem solid rgba(14, 253, 255, 0.5);
width: 100%;
min-height: 3.75rem;
position: relative;
padding: .625rem;
}
.rightMain .rightMain_topIn h3 {
font-size: 1.25rem;
color: #fff;
margin-bottom: 0.78125rem;
font-weight: 700;
}
.rightMain .rightMain_topIn .biaoge {
min-height: 12.5rem;
}
.rightMain .rightMain_bottom {
width: 100%;
}
.rightMain .rightMain_bottomIn {
border: 0.125rem solid rgba(14, 253, 255, 0.5);
width: 100%;
min-height: 3.75rem;
position: relative;
padding: 1.25rem 0.78125rem;
}
.rightMain .rightMain_bottomIn h3 {
font-size: 1.25rem;
color: #fff;
margin-bottom: 0.78125rem;
font-weight: 700;
}
/*右下角表格*/
.rightMain .rightMain_bottomIn .biaoge {
min-height: 12.5rem;
}
.rightMain .rightMain_bottomIn .biaoge_list {
overflow: hidden;
position: relative;
}
.rightMain .rightMain_bottomIn .biaoge_list .biaoge_listIn .ul_list {
overflow: hidden;
position: relative;
}
.rightMain .rightMain_bottomIn .biaoge_list .biaoge_listIn .ul_listIn {
-webkit-animation: 14s gundong linear infinite normal;
animation: 14s gundong linear infinite normal;
position: relative;
}
@keyframes gundong {
0% {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
100% {
-webkit-transform: translate3d(0, -30vh, 0);
transform: translate3d(0, -30vh, 0);
}
}
.rightMain .rightMain_bottomIn .biaoge_list ul {
display: flex;
display: -webkit-flex;
width: 100%;
}
.rightMain .rightMain_bottomIn .biaoge_list .ul_title {
background: linear-gradient(left, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.1));
background: -ms-linear-gradient(left, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.1));
background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.1));
background: -moz-linear-gradient(left, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.1));
}
.rightMain .rightMain_bottomIn .biaoge_list .ul_con {
border-bottom: 0.125rem solid rgba(14, 253, 255, 0.5);
}
.rightMain .rightMain_bottomIn .biaoge_list ul li {
width: 20%;
text-align: center;
color: #fff;
font-size: 0.9375rem;
height: 3.125rem;
line-height: 3.125rem;
}
.rightMain .rightMain_bottomIn .biaoge_list ul li:frist-child {
text-align: left;
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,524 @@
<template>
<div class="bg">
<div class="title">区域检验数据中心</div>
<div class="leftMain">
<div class="leftMain_top">
<div class="leftMain_topIn">
<ul>
<li v-for="item in source">
<div class="liIn">
<h3>{{ item.name }}</h3>
<p class="shu"><span class="shu1">{{ item.num }}</span><i>{{ item.unit }}</i></p>
<span class="border_bg_leftTop"></span>
<span class="border_bg_rightTop"></span>
<span class="border_bg_leftBottom"></span>
<span class="border_bg_rightBottom"></span>
</div>
</li>
</ul>
</div>
</div>
<div class="leftMain_middle">
<div class="leftMain_middle_left">
<div class="leftMain_middle_leftIn">
<h3>委托机构当月送检标本数量</h3>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div class="biaoge" style="width:100%; height:30vh" ref="chartmain" id="chartmain"></div>
<span class="border_bg_leftTop"></span>
<span class="border_bg_rightTop"></span>
<span class="border_bg_leftBottom"></span>
<span class="border_bg_rightBottom"></span>
</div>
<div class="leftMain_middle_leftIn leftMain_middle_leftIn_zhe">
<h3>近一个月送检标本数量趋势图</h3>
<div class="biaoge" style="width:100%; height:30vh" ref="chartmain_zhe" id="chartmain_zhe"></div>
<span class="border_bg_leftTop"></span>
<span class="border_bg_rightTop"></span>
<span class="border_bg_leftBottom"></span>
<span class="border_bg_rightBottom"></span>
</div>
</div>
<div class="leftMain_middle_right">
<div class="leftMain_middle_rightIn">
<h3>委托机构当月送检标本占比</h3>
<div class="biaoge biaoge_pai">
<div class="biaoge_paiIn">
<ul>
<!-- <Vue3SeamlessScroll :list="listData" :step="0.5 as any" :hover="true as any" :key="listData.length"
:limitMoveNum="14"> -->
<li v-for="(item, i) in listData">
<div class="liIn">
<div class="liIn_left"><span class="zi">{{ item.groupname }}</span></div>
<div class="liIn_line">
<div class="line_lineIn" :style="{ width: ` ${item.percentage}` }">
<div class="per">{{ item.percentage }}</div>
</div>
</div>
<p class="num">{{ item.groupsum }}</p>
</div>
</li>
<!-- </Vue3SeamlessScroll> -->
</ul>
</div>
</div>
<span class="border_bg_leftTop"></span>
<span class="border_bg_rightTop"></span>
<span class="border_bg_leftBottom"></span>
<span class="border_bg_rightBottom"></span>
</div>
</div>
</div>
</div>
<div class="rightMain">
<div class="rightMain_top">
<div class="rightMain_topIn">
<h3>当日送检样本情况</h3>
<div class="biaoge" style="width:100%; height:35vh" ref="chartmain_bing" id="chartmain_bing"></div>
<span class="border_bg_leftTop"></span>
<span class="border_bg_rightTop"></span>
<span class="border_bg_leftBottom"></span>
<span class="border_bg_rightBottom"></span>
</div>
</div>
<div class="rightMain_bottom">
<div class="rightMain_bottomIn">
<h3>送检项目分类占比</h3>
<div class="biaoge biaoge_list" ref="sjRef" style="width:100%; height:34vh">
</div>
<span class="border_bg_leftTop"></span>
<span class="border_bg_rightTop"></span>
<span class="border_bg_leftBottom"></span>
<span class="border_bg_rightBottom"></span>
</div>
</div>
</div>
<div style="clear:both;"></div>
</div>
</template>
<script setup lang="ts">
import * as echarts from 'echarts';
import { Vue3SeamlessScroll } from 'vue3-seamless-scroll'
import { getallcount } from '@/api/regional'
const source = ref([
{ name: '区域机构', num: 0, unit: '家', pre: 'jgs' },
{ name: '检验人数', num: 0, unit: '人', pre: 'rs' },
{ name: '检验管数', num: 0, unit: '个', pre: 'gs' },
{ name: '检验报告数', num: 0, unit: '份', pre: 'bgs' },
{ name: '检验项目数', num: 0, unit: '个', pre: 'xms' },
])
const listData: any = ref([])
const chartmain = ref()
const getEcharts1 = (data: any) => {
const Intance = echarts.init(chartmain.value);
var dataAxis = data.map((item: any) => item.daynum + '日')
var data = data.map((item: any) => item.sl)
const option = {
title: {
text: '',
subtext: ''
},
grid: {
x: 40,
y: 40,
x2: 20,
y2: 50,
},
tooltip: {
trigger: 'axis'
},
xAxis: {
data: dataAxis,
axisLabel: {
/*inside: true,*/
interval: 0,
color: '#fff',
fontSize: 12
},
axisTick: {
show: false,
},
axisLine: {
show: true,
symbol: ['none', 'arrow'],
symbolOffset: 12,
lineStyle: {
color: '#fff',
}
},
lineStyle: {
color: '#fff',
},
z: 10
},
dataZoom: [{
type: 'slider',
show: true, //flase直接隐藏图形
xAxisIndex: [0],
textStyle: {
color: '#0efdff', // 文字颜色(如白色,根据主题调整)
fontSize: 12, // 文字大小
fontWeight: 'normal' // 文字粗细
},
left: '9%', //滚动条靠左侧的百分比
bottom: 0,
start: 0,//滚动条的起始位置
end: 70 //滚动条的截止位置(按比例分割你的柱状图x轴长度)
}],
yAxis: {
type: 'value',
name: '单位:个',
axisLine: {
show: true,
symbol: ['none', 'arrow'],
symbolOffset: 12,
lineStyle: {
color: '#fff',
}
},
axisTick: {
show: false
},
axisLabel: {
color: '#fff',
fontSize: 12
}
},
series: [
{
type: 'bar',
itemStyle: {
color: new echarts.graphic.LinearGradient(
0, 0, 0, 1,
[
{ offset: 0, color: '#0efdff' },
{ offset: 0.5, color: '#188df0' },
{ offset: 1, color: '#188df0' }
]
)
},
emphasis: {
itemStyle: {
color: new echarts.graphic.LinearGradient(
0, 0, 0, 1,
[
{ offset: 0, color: '#2378f7' },
{ offset: 0.7, color: '#2378f7' },
{ offset: 1, color: '#0efdff' }
]
)
}
},
data: data
}
]
};
Intance.setOption(option);
}
const chartmain_bing = ref()
const getEcharts2 = (data: any) => {
const names = data.map((item: any) => item.name)
const Intance = echarts.init(chartmain_bing.value);
const option = {
title: {
text: '数据情况统计',
subtext: '',
left: 'right',
textStyle: {
color: '#fff',
fontSize: 12
}
},
tooltip: {
trigger: 'item',
formatter: '{b} : {c} ({d}%)'
},
legend: {
// orient: 'vertical',
// top: 'middle',
type: 'scroll',
orient: 'vertical',
right: 10,
top: 40,
bottom: 20,
left: 'right',
data: names,
textStyle: {
color: '#fff',
fontSize: 12
}
},
grid: {
x: '-10%',
y: 40,
x2: 20,
y2: 20,
},
color: ['#09d0fb', '#f88cfb', '#95f8fe', '#f9f390', '#ecfeb7'],
series: [
{
type: 'pie',
radius: '65%',
center: ['45%', '50%'],
selectedMode: 'single',
data: data,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
Intance.setOption(option);
}
const chartmain_zhe = ref()
const getEcharts3 = () => {
const Intance = echarts.init(chartmain_zhe.value);
const xData = listData.value[0].dayline.map((item: any) => item.daynum + '日')
const tooltips = listData.value.map((item: any) => item.groupname)
const colors = ['#ff7f50', '#87cefa', '#da70d6', '#32cd32', '#6495ed', '#ff69b4', '#ba55d3', '#cd5c5c', '#ffa500', '#40e0d0',
'#1e90ff', '#ff6347', '#7b68ee', '#d0648a', '#ffd700', '#6b8e23', '#4ea397', '#3cb371', '#b8860b']
const arr = listData.value.map((item: any, i: number) => {
return {
name: item.groupname,
type: 'line',
data: item.dayline.map((v: any) => v.sl),
itemStyle: {
color: colors[i],
},
lineStyle: {
color: colors[i],
width: 2,
}
}
})
const option = {
title: {
text: ''
},
tooltip: {
trigger: 'axis', // 或 'item',根据图表类型选择
},
legend: {
type: 'scroll', // 开启滚动
textStyle: {
color: '#fff', // 文字颜色(保持与你的主题一致)
fontSize: 12
},
// 滚动箭头样式(兼容写法)
pageIcon: 'circle', // 箭头形状(可选:'arrow'/'circle'等)
pageIconColor: '#0efdff', // 箭头颜色(核心配置,替代pageButtonItemStyle)
pageIconSize: 12, // 箭头大小
pageIconInactiveColor: '#666666', // 首尾不可滚动时的箭头颜色
pageTextStyle: {
color: '#0efdff' // 分页文字颜色(若显示数字分页)
},
data: tooltips
},
grid: {
x: 40,
y: 40,
x2: 20,
y2: 50,
},
toolbox: {
feature: {
//saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
axisLabel: {
/*inside: true,*/
interval: 0,
color: '#fff',
fontSize: 12
},
axisTick: {
show: false,
},
axisLine: {
show: true,
symbol: ['none', 'arrow'],
symbolOffset: 12,
lineStyle: {
color: '#fff',
}
},
data: xData
},
dataZoom: [{
type: 'slider',
show: true, //flase直接隐藏图形
xAxisIndex: [0],
textStyle: {
color: '#0efdff', // 文字颜色(如白色,根据主题调整)
fontSize: 12, // 文字大小
fontWeight: 'normal' // 文字粗细
},
left: '9%', //滚动条靠左侧的百分比
bottom: 0,
start: 0,//滚动条的起始位置
end: 70 //滚动条的截止位置(按比例分割你的柱状图x轴长度)
}],
yAxis: {
type: 'value',
axisLine: {
show: true,
symbol: ['none', 'arrow'],
symbolOffset: 12,
lineStyle: {
color: '#fff',
}
},
axisTick: {
show: false
},
axisLabel: {
color: '#fff',
fontSize: 12
}
},
series: arr
};
Intance.setOption(option);
}
const sjRef = ref()
const getEcharts4 = (data: any) => {
const names = data.map((item: any) => item.name)
const Intance = echarts.init(sjRef.value);
const option = {
title: {
text: '数据情况统计',
subtext: '',
left: 'right',
textStyle: {
color: '#fff',
fontSize: 12
}
},
tooltip: {
trigger: 'item',
formatter: '{b} : {c} ({d}%)'
},
legend: {
// orient: 'vertical',
// top: 'middle',
type: 'scroll',
orient: 'vertical',
right: 10,
top: 40,
bottom: 20,
left: 'right',
data: names,
textStyle: {
color: '#fff',
fontSize: 12
},
// 滚动箭头样式(兼容写法)
pageIcon: 'circle', // 箭头形状(可选:'arrow'/'circle'等)
pageIconColor: '#0efdff', // 箭头颜色(核心配置,替代pageButtonItemStyle)
pageIconSize: 12, // 箭头大小
pageIconInactiveColor: '#666666', // 首尾不可滚动时的箭头颜色
pageTextStyle: {
color: '#0efdff' // 分页文字颜色(若显示数字分页)
},
},
grid: {
x: '-10%',
y: 40,
x2: 20,
y2: 20,
},
color: ['#09d0fb', '#f88cfb', '#95f8fe', '#f9f390', '#ecfeb7'],
series: [
{
type: 'pie',
radius: '65%',
center: ['45%', '50%'],
selectedMode: 'single',
data: data,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
Intance.setOption(option);
}
const getDataInfo = () => {
getallcount().then((res: any) => {
source.value.forEach(item => {
item.num = res.data.regStatAll[item.pre]
})
listData.value = res.data.regStatHospMonth
// nextTick(() => {
// // 数据更新后强制重绘
// (document.querySelector('.Vue3SeamlessScroll') as any)?._init();
// })
const data2 = res.data.regStatStatus.map((item: any) => {
return {
name: item.dict_name,
value: item.sl,
}
})
const data4 = res.data.regStatSample.map((item: any) => {
return {
name: item.SampleTypeName,
value: item.sl,
}
})
getEcharts1(res.data.regStatMonth)
getEcharts2(data2)
getEcharts3()
getEcharts4(data4)
})
}
onMounted(() => {
getDataInfo()
})
</script>
<style scoped>
@import './css/icon.css';
@import './css/index.css';
@import './css/public.css';
</style>

View File

@ -1,352 +1,295 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="菜单名称" prop="menuName">
<el-input
v-model="queryParams.menuName"
placeholder="请输入菜单名称"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="菜单状态" clearable style="width: 200px">
<el-option
v-for="dict in sys_normal_disable"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
<el-form-item label="菜单名称" prop="menuName">
<el-input v-model="queryParams.menuName" placeholder="请输入菜单名称" clearable style="width: 200px"
@keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="菜单状态" clearable style="width: 200px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:menu:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="Sort" @click="toggleExpandAll">展开/折叠</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-if="refreshTable" v-loading="loading" :data="menuList" row-key="menuId"
:default-expand-all="isExpandAll" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
height="calc(100vh - 200px)">
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
<el-table-column prop="icon" label="图标" align="center" width="100">
<template #default="scope">
<svg-icon :icon-class="scope.row.icon" />
</template>
</el-table-column>
<el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
<el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="status" label="状态" width="80">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" width="160" prop="createTime">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="210" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['system:menu:edit']">修改</el-button>
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)"
v-hasPermi="['system:menu:add']">新增</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['system:menu:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改菜单对话框 -->
<el-dialog :title="title" v-model="open" width="680px" append-to-body>
<el-form ref="menuRef" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="24">
<el-form-item label="上级菜单">
<el-tree-select v-model="form.parentId" :data="menuOptions"
:props="{ value: 'menuId', label: 'menuName', children: 'children' }" value-key="menuId"
placeholder="选择上级菜单" check-strictly />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="菜单类型" prop="menuType">
<el-radio-group v-model="form.menuType">
<el-radio value="M">目录</el-radio>
<el-radio value="C">菜单</el-radio>
<el-radio value="F">按钮</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24" v-if="form.menuType != 'F'">
<el-form-item label="菜单图标" prop="icon">
<el-popover placement="bottom-start" :width="540" trigger="click">
<template #reference>
<el-input v-model="form.icon" placeholder="点击选择图标" @blur="showSelectIcon" readonly>
<template #prefix>
<svg-icon v-if="form.icon" :icon-class="form.icon" class="el-input__icon"
style="height: 32px;width: 16px;" />
<el-icon v-else style="height: 32px;width: 16px;">
<search />
</el-icon>
</template>
</el-input>
</template>
<icon-select ref="iconSelectRef" @selected="selected" :active-icon="form.icon" />
</el-popover>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="菜单名称" prop="menuName">
<el-input v-model="form.menuName" placeholder="请输入菜单名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="显示排序" prop="orderNum">
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 'F'">
<el-form-item>
<template #label>
<span>
<el-tooltip content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>是否外链
</span>
</template>
<el-radio-group v-model="form.isFrame">
<el-radio value="0">是</el-radio>
<el-radio value="1">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 'F'">
<el-form-item prop="path">
<template #label>
<span>
<el-tooltip content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
路由地址
</span>
</template>
<el-input v-model="form.path" placeholder="请输入路由地址" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item prop="component">
<template #label>
<span>
<el-tooltip content="访问的组件路径,如:`system/user/index`,默认在`views`目录下" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
组件路径
</span>
</template>
<el-input v-model="form.component" placeholder="请输入组件路径" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 'M'">
<el-form-item>
<el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
<template #label>
<span>
<el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:user:list')`)" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
权限字符
</span>
</template>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item>
<el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" />
<template #label>
<span>
<el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
路由参数
</span>
</template>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item>
<template #label>
<span>
<el-tooltip content="选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
是否缓存
</span>
</template>
<el-radio-group v-model="form.isCache">
<el-radio value="0">缓存</el-radio>
<el-radio value="1">不缓存</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 'F'">
<el-form-item>
<template #label>
<span>
<el-tooltip content="选择隐藏则路由将不会出现在侧边栏,但仍然可以访问" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
显示状态
</span>
</template>
<el-radio-group v-model="form.visible">
<el-radio v-for="dict in sys_show_hide" :key="dict.value" :value="dict.value">{{ dict.label
}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<template #label>
<span>
<el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
菜单状态
</span>
</template>
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label
}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['system:menu:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="Sort"
@click="toggleExpandAll"
>展开/折叠</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table
v-if="refreshTable"
v-loading="loading"
:data="menuList"
row-key="menuId"
:default-expand-all="isExpandAll"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
<el-table-column prop="icon" label="图标" align="center" width="100">
<template #default="scope">
<svg-icon :icon-class="scope.row.icon" />
</template>
</el-table-column>
<el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
<el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="status" label="状态" width="80">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" width="160" prop="createTime">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="210" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:menu:edit']">修改</el-button>
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:menu:add']">新增</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:menu:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改菜单对话框 -->
<el-dialog :title="title" v-model="open" width="680px" append-to-body>
<el-form ref="menuRef" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="24">
<el-form-item label="上级菜单">
<el-tree-select
v-model="form.parentId"
:data="menuOptions"
:props="{ value: 'menuId', label: 'menuName', children: 'children' }"
value-key="menuId"
placeholder="选择上级菜单"
check-strictly
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="菜单类型" prop="menuType">
<el-radio-group v-model="form.menuType">
<el-radio value="M">目录</el-radio>
<el-radio value="C">菜单</el-radio>
<el-radio value="F">按钮</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 'F'">
<el-form-item label="菜单图标" prop="icon">
<el-popover
placement="bottom-start"
:width="540"
trigger="click"
>
<template #reference>
<el-input v-model="form.icon" placeholder="点击选择图标" @blur="showSelectIcon" readonly>
<template #prefix>
<svg-icon
v-if="form.icon"
:icon-class="form.icon"
class="el-input__icon"
style="height: 32px;width: 16px;"
/>
<el-icon v-else style="height: 32px;width: 16px;"><search /></el-icon>
</template>
</el-input>
</template>
<icon-select ref="iconSelectRef" @selected="selected" :active-icon="form.icon" />
</el-popover>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="显示排序" prop="orderNum">
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="菜单名称" prop="menuName">
<el-input v-model="form.menuName" placeholder="请输入菜单名称" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item prop="routeName">
<template #label>
<span>
<el-tooltip content="默认不填则和路由地址相同:如地址为:`user`,则名称为`User`(注意:因为router会删除名称相同路由,为避免名字的冲突,特殊情况下请自定义,保证唯一性)" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
路由名称
</span>
</template>
<el-input v-model="form.routeName" placeholder="请输入路由名称" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 'F'">
<el-form-item>
<template #label>
<span>
<el-tooltip content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>是否外链
</span>
</template>
<el-radio-group v-model="form.isFrame">
<el-radio value="0">是</el-radio>
<el-radio value="1">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 'F'">
<el-form-item prop="path">
<template #label>
<span>
<el-tooltip content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
路由地址
</span>
</template>
<el-input v-model="form.path" placeholder="请输入路由地址" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item prop="component">
<template #label>
<span>
<el-tooltip content="访问的组件路径,如:`system/user/index`,默认在`views`目录下" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
组件路径
</span>
</template>
<el-input v-model="form.component" placeholder="请输入组件路径" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 'M'">
<el-form-item>
<el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
<template #label>
<span>
<el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:user:list')`)" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
权限字符
</span>
</template>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item>
<el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" />
<template #label>
<span>
<el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
路由参数
</span>
</template>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item>
<template #label>
<span>
<el-tooltip content="选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
是否缓存
</span>
</template>
<el-radio-group v-model="form.isCache">
<el-radio value="0">缓存</el-radio>
<el-radio value="1">不缓存</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 'F'">
<el-form-item>
<template #label>
<span>
<el-tooltip content="选择隐藏则路由将不会出现在侧边栏,但仍然可以访问" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
显示状态
</span>
</template>
<el-radio-group v-model="form.visible">
<el-radio
v-for="dict in sys_show_hide"
:key="dict.value"
:value="dict.value"
>{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<template #label>
<span>
<el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">
<el-icon><question-filled /></el-icon>
</el-tooltip>
菜单状态
</span>
</template>
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in sys_normal_disable"
:key="dict.value"
:value="dict.value"
>{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="Menu">
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from "@/api/system/menu"
import SvgIcon from "@/components/SvgIcon/index.vue"
import IconSelect from "@/components/IconSelect/index.vue"
import type { SysMenu, MenuQueryParams } from '@/types/api/system/menu'
<script setup name="Menu">
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from "@/api/system/menu";
import SvgIcon from "@/components/SvgIcon";
import IconSelect from "@/components/IconSelect";
const { proxy } = getCurrentInstance()
const { sys_show_hide, sys_normal_disable } = proxy.useDict("sys_show_hide", "sys_normal_disable")
const { proxy } = getCurrentInstance();
const { sys_show_hide, sys_normal_disable } = proxy.useDict("sys_show_hide", "sys_normal_disable");
const menuList = ref<any[]>([])
const open = ref<boolean>(false)
const loading = ref<boolean>(true)
const showSearch = ref<boolean>(true)
const title = ref<string>("")
const menuOptions = ref<any[]>([])
const isExpandAll = ref<boolean>(false)
const refreshTable = ref<boolean>(true)
const iconSelectRef = ref<any | null>(null)
const menuList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const title = ref("");
const menuOptions = ref([]);
const isExpandAll = ref(false);
const refreshTable = ref(true);
const iconSelectRef = ref(null);
const data = reactive({
form: {} as SysMenu,
form: {},
queryParams: {
menuName: undefined,
visible: undefined
} as MenuQueryParams,
},
rules: {
menuName: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }],
orderNum: [{ required: true, message: "菜单顺序不能为空", trigger: "blur" }],
path: [{ required: true, message: "路由地址不能为空", trigger: "blur" }]
},
})
});
const { queryParams, form, rules } = toRefs(data)
const { queryParams, form, rules } = toRefs(data);
/** 查询菜单列表 */
function getList() {
loading.value = true
loading.value = true;
listMenu(queryParams.value).then(response => {
menuList.value = proxy.handleTree(response.data, "menuId")
loading.value = false
})
menuList.value = proxy.handleTree(response.data, "menuId");
loading.value = false;
});
}
/** 查询菜单下拉树结构 */
function getTreeselect() {
menuOptions.value = []
menuOptions.value = [];
listMenu().then(response => {
const menu = { menuId: 0, menuName: "主类目", children: [] }
menu.children = proxy.handleTree(response.data, "menuId")
menuOptions.value.push(menu)
})
const menu = { menuId: 0, menuName: "主类目", children: [] };
menu.children = proxy.handleTree(response.data, "menuId");
menuOptions.value.push(menu);
});
}
/** 取消按钮 */
function cancel() {
open.value = false
reset()
open.value = false;
reset();
}
/** 表单重置 */
function reset() {
form.value = {
@ -360,94 +303,85 @@ function reset() {
isCache: "0",
visible: "0",
status: "0"
}
proxy.resetForm("menuRef")
};
proxy.resetForm("menuRef");
}
/** 展示下拉图标 */
function showSelectIcon() {
iconSelectRef.value?.reset()
iconSelectRef.value.reset();
}
/** 选择图标 */
function selected(name: string) {
form.value.icon = name
function selected(name) {
form.value.icon = name;
}
/** 搜索按钮操作 */
function handleQuery() {
getList()
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef")
handleQuery()
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd(row?: SysMenu) {
reset()
getTreeselect()
function handleAdd(row) {
reset();
getTreeselect();
if (row != null && row.menuId) {
form.value.parentId = row.menuId
form.value.parentId = row.menuId;
} else {
form.value.parentId = 0
form.value.parentId = 0;
}
open.value = true
title.value = "添加菜单"
open.value = true;
title.value = "添加菜单";
}
/** 展开/折叠操作 */
function toggleExpandAll() {
refreshTable.value = false
isExpandAll.value = !isExpandAll.value
refreshTable.value = false;
isExpandAll.value = !isExpandAll.value;
nextTick(() => {
refreshTable.value = true
})
refreshTable.value = true;
});
}
/** 修改按钮操作 */
async function handleUpdate(row: SysMenu) {
reset()
await getTreeselect()
getMenu(row.menuId!).then(response => {
form.value = response.data!
open.value = true
title.value = "修改菜单"
})
async function handleUpdate(row) {
reset();
await getTreeselect();
getMenu(row.menuId).then(response => {
form.value = response.data;
open.value = true;
title.value = "修改菜单";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["menuRef"].validate((valid: boolean) => {
proxy.$refs["menuRef"].validate(valid => {
if (valid) {
if (form.value.menuId != undefined) {
updateMenu(form.value).then(() => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
})
updateMenu(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addMenu(form.value).then(() => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
})
addMenu(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
})
});
}
/** 删除按钮操作 */
function handleDelete(row: SysMenu) {
proxy.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?').then(function() {
return delMenu(row.menuId!)
function handleDelete(row) {
proxy.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?').then(function () {
return delMenu(row.menuId);
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => { });
}
getList()
getList();
</script>

View File

@ -48,7 +48,7 @@ export default defineConfig(({ mode, command }) => {
proxy: {
// https://cn.vitejs.dev/config/#server-proxy
'/dev-api': {
target: 'http://47.97.125.165:8904',
target: 'http://47.97.125.165:8905',
changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api/, '')
},