| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798 |
- <template>
- <el-table
- v-loading="props.loading"
- :data="props.list"
- :header-cell-style="tableHeaderColor"
- :maxHeight="props.height ? props.height : tableHeight()"
- @selection-change="handleSelectionChange"
- @row-click="handleRowClick"
- @sort-change="handleSortChange"
- >
- <el-table-column width="35" v-if="isResolve || isRadio" fixed>
- <template #default="scope">
- <el-radio v-model="radioId" :label="scope.row.id" />
- </template>
- </el-table-column>
- <el-table-column
- type="selection"
- :selectable="handleSelectable"
- width="40"
- v-if="props.selection"
- fixed
- />
- <el-table-column header-align="center" align="center" label="编号" width="62" fixed>
- <template #default="scope">
- {{
- scope.$index +
- (props.queryParams.pageNo * props.queryParams.pageSize - props.queryParams.pageSize) +
- 1
- }}
- </template>
- </el-table-column>
- <template v-for="(item, index) in props.columns" :key="index">
- <!-- 常规渲染 -->
- <el-table-column
- show-overflow-tooltip
- v-if="!item.type"
- :prop="item.field"
- header-align="center"
- :align="item.align || 'center'"
- :label="item.label"
- :formatter="item.format ? (item.format2 ? dateFormatter : dateFormatter2) : undefined"
- :width="item.width"
- :fixed="item.fixed ? true : false"
- :sortable="item.sortable || false"
- />
- <!-- 字典值渲染 -->
- <el-table-column
- v-if="item.type == 1"
- :prop="item.field"
- header-align="center"
- align="center"
- :label="item.label"
- >
- <template #default="scope">
- {{ getDictLabel(item.dictArr, scope.row[item.field]) || formatterLabel(scope.row, item) }}
- </template>
- </el-table-column>
- <!-- tag标签渲染 -->
- <el-table-column
- v-if="item.type == 2"
- :prop="item.field"
- header-align="center"
- align="center"
- :label="item.label"
- :width="item.width"
- >
- <template #default="scope">
- <dict-tag :type="item.dictArr" :value="scope.row[item.field]" />
- </template>
- </el-table-column>
- <!-- 数字 -->
- <el-table-column
- v-if="item.type == 3"
- :prop="item.field"
- header-align="center"
- align="center"
- :label="item.label"
- :width="item.width"
- >
- <template #default="scope">
- {{ formatNum(scope.row[item.field]) }}
- </template>
- </el-table-column>
- <!-- 根据插槽渲染 -->
- <el-table-column
- v-if="item.type == 4"
- :prop="item.field"
- header-align="center"
- align="center"
- :label="item.label"
- >
- <template #default="scope">
- <el-progress
- :text-inside="true"
- :stroke-width="15"
- :percentage="scope.row[item.field]"
- :color="[
- { color: '#f56c6c', percentage: 35 }, // 0-35
- { color: '#e6a23c', percentage: 70 }, // 71-100
- { color: '#5cb87a', percentage: 100 }
- ]"
- />
- </template>
- </el-table-column>
- <!-- 日期数组转换 -->
- <el-table-column
- v-if="item.type == 5"
- :prop="item.field"
- header-align="center"
- align="center"
- :label="item.label"
- >
- <template #default="scope">
- {{
- scope.row[item.field] ? formatTime(scope.row[item.field].join('-'), 'yyyy-MM-dd') : ''
- }}
- </template>
- </el-table-column>
- <!-- 颜色 -->
- <el-table-column
- v-if="item.type == 6"
- :prop="item.field"
- header-align="center"
- align="center"
- :label="item.label"
- >
- <template #default="scope">
- <div
- :style="{ background: scope.row[item.field] }"
- style="width: 100px; height: 30px; margin: auto"
- ></div>
- </template>
- </el-table-column>
- <!-- 切割识别 -->
- <el-table-column
- v-if="item.type == 8"
- header-align="center"
- align="center"
- :label="item.label"
- >
- <template #default="scope">
- {{ getText(scope.row, item.field) }}
- </template>
- </el-table-column>
- <!-- 时分秒 -->
- <el-table-column
- show-overflow-tooltip
- v-if="item.type == 9"
- :prop="item.field"
- header-align="center"
- :align="item.align || 'center'"
- :label="item.label"
- :formatter="dateFormatter"
- :width="item.width"
- />
- <!-- 合并拼接 -->
- <el-table-column
- v-if="item.type == 10"
- header-align="center"
- align="center"
- :label="item.label"
- :width="item.width"
- >
- <template #default="scope">
- {{ mergeText(scope.row, item.field, item.desc) }}
- </template>
- </el-table-column>
- <el-table-column
- show-overflow-tooltip
- v-if="item.type == 99 && userStore.getOrgTenant.multiple"
- :prop="item.field"
- header-align="center"
- :align="item.align || 'center'"
- :label="item.label"
- :fixed="item.fixed ? true : false"
- :width="item.width"
- />
- <!-- 标题中添加提示 -->
- <el-table-column
- v-if="item.type == 11"
- header-align="center"
- align="center"
- :label="item.label"
- :width="item.width"
- >
- <template #header>
- {{ item.label }}
- <el-tooltip class="item" effect="dark" :content="item.content" placement="top-start">
- <Icon icon="ep:info-filled" />
- </el-tooltip>
- </template>
- <template #default="scope">
- <dict-tag :type="item.dictArr" :value="scope.row[item.field]" />
- </template>
- </el-table-column>
- <el-table-column
- v-if="item.type == 12"
- header-align="center"
- align="center"
- :label="item.label"
- :width="item.width"
- >
- <template #default="scope">
- <span v-if="scope.row[item.field] == 1">{{
- getDictLabel(item.dictArr, scope.row[item.field]) || formatterLabel(scope.row, item)
- }}</span>
- <span v-else>{{ scope.row.deviceName }}</span>
- </template>
- </el-table-column>
- <!-- 综合配置数字 -->
- <el-table-column
- v-if="item.type == 13"
- :prop="item.field"
- header-align="center"
- align="center"
- :label="item.label"
- :width="item.width"
- >
- <template #default="scope">
- {{ calcPrice(scope.row, item) }}
- </template>
- </el-table-column>
- <!-- 综合配置数字-各值取整相加 -->
- <el-table-column
- v-if="item.type == 14"
- :prop="item.field"
- header-align="center"
- align="center"
- :label="item.label"
- :width="item.width"
- >
- <template #default="scope">
- {{ formatActualPrice(scope.row, item) }}
- </template>
- </el-table-column>
- <!-- 入院账单 && isMonthlyExpense && 【入院账单月度费用向上取整设置】是向上取整 -->
- <el-table-column
- v-if="item.type == 15"
- :prop="item.field"
- header-align="center"
- align="center"
- :label="item.label"
- :width="item.width"
- >
- <template #default="scope">
- {{ formatAdmissionBillRoundUp(scope.row, item) }}
- </template>
- </el-table-column>
- <!-- 数组类型的字典数据渲染 -->
- <el-table-column
- v-if="item.type == 16"
- :prop="item.field"
- header-align="center"
- align="center"
- :label="item.label"
- :width="item.width"
- >
- <template #default="scope">
- {{ getDictLabelArr(item.dictArr, scope.row[item.field]) }}
- </template>
- </el-table-column>
- <el-table-column
- v-if="item.type == 17"
- :prop="item.field"
- header-align="center"
- align="center"
- :label="item.label"
- :width="item.width"
- >
- <template #default="scope">
- {{ scope.row.payStatus != 0 ? toFixedNum(scope.row.payableAmount) : '0.00' }}
- </template>
- </el-table-column>
- <el-table-column
- v-if="item.type == 18"
- :prop="item.field"
- header-align="center"
- align="center"
- :label="item.label"
- :width="item.width"
- >
- <template #default="scope">
- <el-popover :title="scope.row.elderName" :width="530" placement="top-start">
- <template #reference>
- <el-tag
- :type="!scope.row.otherFiles || scope.row.otherFiles == '' ? 'warning' : 'primary'"
- >{{
- !scope.row.otherFiles || scope.row.otherFiles == '' ? '未上传' : '已上传'
- }}</el-tag
- >
- </template>
- <el-table :data="parsingJSON(scope.row.otherFiles)">
- <el-table-column label="预览" width="80" align="center">
- <template #default="{ row }">
- <el-image
- v-if="isImageFile(row.fileUrl)"
- :src="row.fileUrl"
- :preview-src-list="[row.fileUrl]"
- fit="cover"
- style="width: 40px; height: 40px; cursor: pointer"
- />
- <Icon v-else icon="ep:document" style="font-size: 20px; color: #909399" />
- </template>
- </el-table-column>
- <el-table-column
- width="150"
- property="fileName"
- label="附件名称"
- show-overflow-tooltip
- />
- <el-table-column width="180" property="createTime" label="创建时间" />
- <el-table-column width="90" label="操作" align="center">
- <template #default="{ row }">
- <el-button type="primary" link size="small" @click="handleDownload(row)"
- >下载</el-button
- >
- </template>
- </el-table-column>
- </el-table>
- </el-popover>
- </template>
- </el-table-column>
- </template>
- <el-table-column
- label="操作"
- align="center"
- name="op"
- :width="opWidth"
- v-if="!props.isResolve && props.showOp"
- fixed="right"
- >
- <template #default="scope">
- <slot name="pre" :scope="scope.row"></slot>
- <el-button
- link
- type="primary"
- @click="handleEdit(scope.row)"
- v-hasPermi="[permissionStr + ':relaunch']"
- v-show="scope.row.status == 3 || scope.row.status == 4"
- >
- 重新发起
- </el-button>
- <el-button
- link
- type="primary"
- @click="handleCheckIn(scope.row)"
- v-hasPermi="[permissionStr + ':checkIn']"
- >
- 入住
- </el-button>
- <el-button
- link
- type="primary"
- @click="handleUpload(scope.row)"
- v-hasPermi="[permissionStr + ':upload-contract']"
- >
- 上传合同
- </el-button>
- <el-button
- link
- type="primary"
- @click="handleEdit(scope.row)"
- v-hasPermi="[permissionStr + ':renew']"
- :disabled="isDisabledRenewal(scope.row)"
- >
- 续签
- </el-button>
- <el-button
- link
- type="warning"
- @click="handleCheck(scope.row)"
- v-hasPermi="[permissionStr + ':change']"
- >
- 变更
- </el-button>
- <!-- <el-button
- link
- type="primary"
- @click="handleCheck(scope.row)"
- v-hasPermi="[permissionStr + ':check']"
- v-show="scope.row.status == 1"
- >
- 办理
- </el-button> -->
- <el-button
- link
- type="primary"
- @click="handleEdit(scope.row)"
- v-hasPermi="[permissionStr + ':edit']"
- v-show="props.showEditCondition(scope.row)"
- >
- 编辑
- </el-button>
- <el-button
- link
- type="primary"
- @click="handleDetail(scope.row)"
- v-hasPermi="[permissionStr + ':detail']"
- v-show="props.showDetailCondition(scope.row)"
- >
- 详情
- </el-button>
- <el-button
- link
- type="danger"
- @click="handleCancel(scope.row)"
- v-hasPermi="[permissionStr + ':cancel']"
- v-show="scope.row.status == 1"
- >
- 撤销
- </el-button>
- <!-- 不走流程的打印 -->
- <el-button
- link
- type="primary"
- @click="handlePrint(scope.row)"
- v-hasPermi="[permissionStr + ':print']"
- >
- 打印
- </el-button>
- <!-- 走流程的打印 -->
- <el-button
- link
- type="primary"
- @click="handlePrint(scope.row)"
- v-hasPermi="[permissionStr + ':p-print']"
- v-show="scope.row.status == 2 || scope.row.status == 5"
- >
- 打印
- </el-button>
- <el-button
- link
- type="danger"
- @click="handleDelete(scope.row)"
- v-hasPermi="[permissionStr + ':delete']"
- v-show="props.showDeleteCondition(scope.row)"
- >
- 删除
- </el-button>
- <slot name="next" :scope="scope.row"></slot>
- <slot name="del" :scope="scope.row"></slot>
- </template>
- </el-table-column>
- </el-table>
- </template>
- <script setup lang="ts">
- import { TableColumn } from '@/types/table'
- import { dateFormatter, dateFormatter2 } from '@/utils/formatTime'
- import { getDictLabel, getDictOptions } from '@/utils/dict'
- import { useAppStore } from '@/store/modules/app'
- import { fixedNum, formatCeil, formatNum, formatRound, formatTrunc } from '@/utils/formatter'
- import { tableHeaderColor } from '@/utils/table'
- import { breakpointsTailwind, useBreakpoints } from '@vueuse/core'
- import { formatTime } from '@/utils'
- import { useUserStore } from '@/store/modules/user'
- import { useSettingStore } from '@/store/modules/setting'
- import { FileItem, isImageFile } from '@/components/UploadFile'
- const userStore = useUserStore()
- const settingStore = useSettingStore()
- const radioId = ref() // 单选表格
- const isDisabledRenewal = (row) => {
- // 暂时不做“到期前两个月内才可续签”的时间限制,只看 isRenew
- // if (!row.expireTime) return false
- // const expireDate = new Date(row.expireTime)
- // const halfMonthLater = new Date()
- // halfMonthLater.setMonth(halfMonthLater.getMonth() + 2)
- // return expireDate > halfMonthLater && (row.isRenew || 0) == 0
- return (row.isRenew || 0) != 0
- }
- const props = defineProps({
- // 加载
- loading: {
- type: Boolean,
- default: false
- },
- // 数据
- list: {
- type: Array as PropType<Recordable[]>,
- default: () => []
- },
- // 列
- columns: {
- type: Array as PropType<TableColumn[]>,
- default: () => []
- },
- // 搜索
- queryParams: {
- type: Object,
- default: () => {}
- },
- // 是否多选
- selection: {
- type: Boolean,
- default: false
- },
- // 是否视图加载
- isResolve: {
- type: Boolean,
- default: false
- },
- showOp: {
- type: Boolean,
- default: true
- },
- opWidth: {
- type: Number,
- default: 180
- },
- isRadio: {
- // 是否显示单选框
- type: Boolean,
- default: false
- },
- disabledSelectedText: {
- // 控制是否可以选中
- type: String,
- default: ''
- },
- formRef: {
- type: Object,
- default: () => {}
- },
- tree: {
- type: Number,
- default: 1
- },
- height: {
- type: [Number, String],
- default: ''
- },
- showDetailCondition: {
- type: Function,
- default: () => true
- },
- showEditCondition: {
- type: Function,
- default: () => true
- },
- showDeleteCondition: {
- type: Function,
- default: () => true
- }
- })
- const toFixedNum = (num: any) => {
- try {
- return num.toFixed(2)
- } catch (e) {
- return '0.00'
- }
- }
- const parsingJSON = (row) => {
- if (!row || row == '') {
- return []
- } else {
- let json = JSON.parse(row)
- return json
- }
- }
- const handleSelectable = (row) => {
- if (props.disabledSelectedText) {
- return row[props.disabledSelectedText] != 1
- }
- return true
- }
- const handleDownload = (row: FileItem) => {
- console.log(row)
- fetch(row.fileUrl)
- .then((response) => {
- if (!response.ok) throw new Error('下载失败')
- return response.blob()
- })
- .then((blob) => {
- const url = URL.createObjectURL(blob)
- const a = document.createElement('a')
- a.href = url
- a.download = row.fileName
- document.body.appendChild(a)
- a.click()
- document.body.removeChild(a)
- URL.revokeObjectURL(url)
- })
- .catch((error) => console.error('下载失败:', error))
- }
- const getDictLabelArr = (dictArr, field) => {
- const dictLabelArr = getDictOptions(dictArr)
- let fields = field.map((item) => item.mealName)
- let str = ''
- str = dictLabelArr
- .filter((item) => fields.includes(item.value))
- .map((item) => item.label)
- .join(',')
- return str
- }
- const formatterLabel = (row, item) => {
- if (Object.keys(row).length > 0) {
- // 性别
- if (item.field.indexOf('.') > -1) {
- let arr = item.field.split('.')
- if (arr[0] && arr[1] && row[arr[0]] && row[arr[0]][arr[1]])
- return getDictLabel(item.dictArr, row[arr[0]][arr[1]])
- } else if (row[item.field] && String(row[item.field]).indexOf(',') > -1) {
- // 药物过敏史,返回字符串
- let str = '',
- tempStr = ''
- let arr = JSON.parse(row[item.field])
- if (row[item.field].includes('0-')) {
- // 0 为 其他
- let temp = arr.pop()
- arr.push('0')
- tempStr = String(temp.split('-')[1])
- }
- arr.map((a) => {
- str += ',' + getDictLabel(item.dictArr, a)
- })
- str = str.substring(1)
- if (tempStr) {
- return str + '-' + tempStr
- }
- return str
- }
- }
- }
- const getText = (row, item) => {
- if (row) {
- const arr = item.split(':')
- return formatTime(row[arr[0]], 'yyyy-MM-dd') + ' ' + row[arr[1]]
- }
- }
- const mergeText = (row, t1, t2) => {
- return row[t2] + ' - ' + row[t1]
- }
- const breakpoints = useBreakpoints(breakpointsTailwind)
- const smallerThanLg = breakpoints.smaller('xl') // only larger than md
- const tableHeight = () => {
- return smallerThanLg.value ? 'auto' : '60vh'
- // window.outerHeight - (30 + 35 + 40 + 77 + 15 + 20 + 10 + 110 + 180)
- }
- const formatActualPrice = (item, type) => {
- // 统一口径:先对各分量求和成总额 rawSum,再对总额做一次性取整/保留小数。
- // 不可逐项取整再加总——分量为负时直接向 0 截断/取整会放大误差(如 -787.5→-787 使 3712.5 变 3713)
- const rawSum =
- Number(item['bedAmount']) +
- Number(item['nurseAmount']) +
- Number(item['mealAmount']) +
- Number(item['otherAmount']) +
- Number(item['insuranceAmount'])
- if (item.type == 1) {
- if (settingStore.getAdmissionBill == 2) {
- // 向上取整
- return formatNum(formatCeil(rawSum))
- } else if (settingStore.getAdmissionBill == 3) {
- // 四舍五入保留两位
- return formatNum(fixedNum(rawSum))
- } else if (settingStore.getAdmissionBill == 4) {
- // 四舍五入取整
- return formatNum(formatRound(rawSum))
- } else {
- // 应收,不取整
- return formatNum(rawSum)
- }
- } else if (settingStore.getRounding) {
- // 直丢小数
- return formatNum(formatTrunc(rawSum))
- } else if (settingStore.getFix2Num) {
- // 四舍五入保留两位
- return formatNum(fixedNum(rawSum))
- } else {
- return formatNum(item[type.field])
- }
- }
- const formatAdmissionBillRoundUp = (item, type) => {
- if (item.type == 1) {
- if (settingStore.getAdmissionBill == 2) {
- // 向上取整
- return formatCeil(item[type.field])
- } else if (settingStore.getAdmissionBill == 3) {
- // 四舍五入保留两位
- return fixedNum(item[type.field])
- } else if (settingStore.getAdmissionBill == 4) {
- // 四舍五入取整
- return formatRound(item[type.field])
- } else {
- return formatNum(item[type.field])
- }
- } else if (settingStore.getRounding) {
- return formatTrunc(item[type.field])
- } else if (settingStore.getFix2Num) {
- return fixedNum(item[type.field])
- } else {
- return formatNum(item[type.field])
- }
- }
- const calcPrice = (row, item) => {
- // 入院账单"四舍五入取整"(getAdmissionBill==4)仍走四舍五入
- if (row.type == 1 && settingStore.getAdmissionBill == 4) {
- return formatRound(row[item.otherField || item.field])
- } else if (settingStore.getRounding) {
- // 账单金额单项取整设置:直丢小数
- return formatTrunc(row[item.otherField || item.field])
- } else if (settingStore.getFix2Num) {
- return fixedNum(row[item.field])
- } else {
- return formatNum(row[item.field])
- }
- }
- const emit = defineEmits([
- 'edit',
- 'detail',
- 'del',
- 'sign',
- 'print',
- 'selectionChange',
- 'row-click',
- 'sortChange',
- 'checkIn',
- 'upload',
- 'check',
- 'audit',
- 'cancel'
- ])
- const handleEdit = (row) => {
- emit('edit', row)
- }
- const handleDetail = (row) => {
- emit('detail', row)
- }
- const handleDelete = (row) => {
- emit('del', row.id)
- }
- const handleCancel = (row) => {
- emit('cancel', row.processInstanceId)
- }
- const handleSign = (row) => {
- emit('sign', row)
- }
- const handlePrint = (row) => {
- emit('print', row)
- }
- const handleSelectionChange = (val) => {
- emit('selectionChange', val)
- }
- const handleRowClick = (row) => {
- radioId.value = row.id
- emit('row-click', row)
- }
- const handleSortChange = (val) => {
- emit('sortChange', val)
- }
- const handleCheckIn = (row) => {
- emit('checkIn', row)
- }
- const handleUpload = (row) => {
- emit('upload', row)
- }
- const handleCheck = (row) => {
- emit('check', row)
- }
- const handleAudit = (row) => {
- emit('audit', row)
- }
- const route = useRoute() // 路由信息
- const permissionStr = ref('') // 权限字符串
- onMounted(() => {
- const arr = route.fullPath.substring(1).split('/')
- if (props.tree == 1) {
- // 需要确定页面有没有携带参数
- const str = arr[props.tree].split('?')[0]
- permissionStr.value = str
- } else if (props.tree == 2) {
- permissionStr.value = `${arr[props.tree - 1]}:${arr[props.tree]}` //可能有第三级菜单
- }
- console.log('权限路径', permissionStr.value, route.fullPath)
- })
- </script>
|