2025-11-12 14:32:01 +08:00

454 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<x-search-bar class="mb-8-2">
<template #default="{ gutter, colSpan }">
<a-form :model="searchFormData" layout="inline" labelAlign="left">
<a-row :gutter="[24, 24]">
<!-- 所在区域 -->
<a-col :span="8" v-if="platForm !== 'yunying'">
<a-form-item label="所属服务组织" name="station">
<node-tree v-model:value="searchFormData.station" />
</a-form-item>
</a-col>
<!-- 姓名 -->
<a-col :span="8">
<a-form-item label="姓名" name="name">
<a-input v-model:value="searchFormData.name" placeholder="请输入姓名" />
</a-form-item>
</a-col>
<!-- 身份证号 -->
<a-col :span="8">
<a-form-item label="联系电话" name="phone">
<a-input v-model:value="searchFormData.phone" placeholder="请输入联系电话" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="护理人员类型" name="serviceType">
<a-select v-model:value="searchFormData.serviceType" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.STAFF_TYPE" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="护理人员状态" name="status">
<a-select v-model:value="searchFormData.status" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.STAFF_STATUS" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="用工形式" name="workType">
<a-select v-model:value="searchFormData.workType" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.USE_TYPE" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<!-- 操作按钮 -->
<a-col class="align-right" :span="24">
<a-space>
<a-button @click="handleResetSearch">{{ $t('button.reset') }}</a-button>
<a-button ghost type="primary" @click="handleSearch">
{{ $t('button.search') }}
</a-button>
</a-space>
</a-col>
</a-row>
</a-form>
</template>
</x-search-bar>
<a-row :gutter="8" :wrap="false">
<a-col flex="auto">
<a-card title="服务人员列表">
<template #extra>
<a-space>
<a-button type="primary" @click="$refs.editDialogRef.handleCreate(record)">新建</a-button>
<a-button type="primary">导出</a-button>
<a-button type="dashed">导出记录</a-button>
</a-space>
</template>
<a-table :columns="columns" :data-source="listData" bordered="true" :loading="loading"
:pagination="paginationState" :scroll="{ x: 'max-content' }" @change="onTableChange">
<template #bodyCell="{ index, column, record }">
<template v-if="column.key === 'serialNumber'">
<span>{{ index + 1 }}</span>
</template>
<template v-if="column.key === 'workType'">
<span>{{ dicsStore.getDictLabel('USE_TYPE', record.workType) }}</span>
</template>
<template v-if="column.key === 'gender'">
<span v-if="record.gender == '1'">男</span>
<span v-else>女</span>
</template>
<template v-if="column.key === 'status'">
<a-tag>{{ dicsStore.getDictLabel('STAFF_STATUS', record.status) }}</a-tag>
</template>
<template v-if="column.key === 'serviceType'">
<span>{{ dicsStore.getDictLabel('STAFF_TYPE', record.serviceType) }}</span>
</template>
<template v-if="'action' === column.key">
<x-action-button @click="$refs.editDialogRef.handleEdit(record)">
<span>编辑</span>
</x-action-button>
<x-action-button @click="$refs.detailRef.handleEdit(record)">
<span>详情</span>
</x-action-button>
<x-action-button @click="treeHandleEdit(record.id)" v-if="platForm === 'yunying'">
<span>服务项目</span>
</x-action-button>
<x-action-button @click="handleStop(record)"
v-if="platForm === 'yunying' && (record.status == '1' || record.status == '4')">
<span v-if="record.status === '1'">停用</span>
<span v-if="record.status === '4'">启用</span>
</x-action-button>
<x-action-button @click="handleDelete(record)">
<span style="color: #ff4d4f;">删除</span>
</x-action-button>
</template>
</template>
</a-table>
</a-card>
</a-col>
</a-row>
<edit-dialog ref="editDialogRef" @ok="onOk"></edit-dialog>
<detail ref="detailRef"></detail>
<a-modal v-model:open="treeOpen" title="绑定服务项目" @ok="handleOk">
<a-card>
<a-spin :spinning="spinning">
<a-tree v-model:expandedKeys="expandedKeys" v-model:selectedKeys="selectedKeys"
v-model:checkedKeys="checkedKeys" checkable :tree-data="treeData" @check="onCheck">
<template #title="{ title, key }">
<span v-if="key === '0-0-1-0'" style="color: #1890ff">{{ title }}</span>
<template v-else>{{ title }}</template>
</template>
</a-tree>
</a-spin>
</a-card>
</a-modal>
</template>
<script setup>
import { message, Modal } from 'ant-design-vue'
import { ref } from 'vue'
import apis from '@/apis'
import { config } from '@/config'
import { usePagination } from '@/hooks'
import { useI18n } from 'vue-i18n'
import EditDialog from './components/EditDialog.vue'
import { useDicsStore } from '@/store'
import AreaCascader from '@/components/AreaCascader/index.vue'
import detail from './components/detail.vue'
import dayjs from 'dayjs'
import NodeTree from '@/components/NodeTree/index.vue'
import storage from '@/utils/storage'
import { getBirthDate, spliceUrl } from '@/utils/util'
defineOptions({
name: 'allocation',
})
const currentId = ref('')
const spinning = ref(false)
const expandedKeys = ref([])
const selectedKeys = ref([])
const checkedKeys = ref([])
const treeData = ref([])
const treeOpen = ref(false)
const dicsStore = useDicsStore()
const platForm = storage.local.getItem('platform')
const columns = [
{
title: '序号',
dataIndex: 'serialNumber',
key: 'serialNumber',
align: 'center',
width: 80,
},
{
title: '姓名',
dataIndex: 'name',
key: 'name',
align: 'center',
width: 100,
},
{
title: '性别',
dataIndex: 'gender',
key: 'gender',
align: 'center',
width: 80,
},
{
title: '电话',
dataIndex: 'phone',
key: 'phone',
align: 'center',
width: 80,
},
{
title: '身份证号',
dataIndex: 'idCard',
key: 'idCard',
align: 'center',
width: 180,
},
{
title: '护理人员类型',
dataIndex: 'serviceType',
key: 'serviceType',
align: 'center',
width: 120,
},
{
title: '用工形式',
dataIndex: 'workType',
key: 'workType',
align: 'center',
width: 120,
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
align: 'center',
width: 120,
},
{
title: '所属服务组织',
dataIndex: 'stationName',
key: 'stationName',
align: 'center',
width: 120,
},
// {
// title: '组织所在区域',
// dataIndex: 'areaLabels',
// key: 'areaLabels',
// align: 'center',
// width: 120,
// },
{
title: '操作',
dataIndex: 'action',
key: 'action',
align: 'center',
width: 250,
fixed: 'right',
}
];
const { t } = useI18n() // 解构出t方法
const { listData, loading, showLoading, hideLoading, paginationState, resetPagination, searchFormData } = usePagination()
const editDialogRef = ref()
const detailRef = ref()
getPageList()
async function getPageList() {
try {
loading.value = true
const { pageSize, current } = paginationState
const { success, data, total } = await apis.serviceStaffList
.getProjectList({
companyId: storage.local.getItem('companyId'),
stationId: storage.local.getItem('stationId'),
pageSize,
current: current,
...searchFormData.value,
})
.catch(() => {
throw new Error()
})
if (config('http.code.success') === success) {
listData.value = data
paginationState.total = total
loading.value = false
getServerProject()
}
} catch (error) {
loading.value = false
}
}
// 判断是否为叶子节点
function isLeafNode(nodeKey, data = treeData.value) {
for (const item of data) {
if (item.key === nodeKey) {
return !item.children || item.children.length === 0;
}
if (item.children && item.children.length > 0) {
const found = isLeafNode(nodeKey, item.children);
if (found !== null) return found;
}
}
return null; // 未找到
}
// 获取所有叶子节点(递归)
function getAllLeafKeys(data) {
let leaves = [];
data.forEach(item => {
if (!item.children || item.children.length === 0) {
leaves.push(item.key);
} else {
leaves = leaves.concat(getAllLeafKeys(item.children));
}
});
return leaves;
}
// 处理勾选
const onCheck = (checkedKeysObj, info) => {
console.log(checkedKeysObj)
// const { checked, halfChecked } = checkedKeysObj;
// 只保留叶子节点
const leafCheckedKeys = checkedKeysObj.filter(key => {
return isLeafNode(key) === true;
});
// 更新受控的 checkedKeys可选只显示叶子被选中
checkedKeys.value = leafCheckedKeys;
};
/**核销 */
const getServerProject = async (id) => {
try {
currentId.value = id
const { data, success } = await apis.serviceStaffList.getTreeData({ categoryType: '1' })
if (success) {
treeData.value = transformCategories(data)
}
} catch (error) {
console.log(error.msg)
}
}
async function treeHandleEdit(id){
try {
currentId.value=id
spinning.value=true
treeOpen.value = true
const {data,success}=await apis.serviceStaffList.getProject({current:1,pageSize:99,servicePersonId:id})
if (success) {
checkedKeys.value=data.map(item=>item.projectId)
console.log(selectedKeys.value)
}
spinning.value=false
} catch (error) {
spinning.value=false
}
}
function transformCategories(data) {
return data.map(category => ({
key: category.categoryId,
title: category.categoryName,
children: category.projects.map(project => ({
key: project.id,
title: project.name
}))
}));
}
const handleOk = async () => {
try {
const params = { servicePersonId: currentId.value, projectIds: checkedKeys.value }
const {success} = await apis.serviceStaffList.createProject(params)
if(success){
message.success('绑定成功')
treeOpen.value=false
checkedKeys.value=[]
}
} catch (error) {
console.log(error)
}
}
const handleStop = async (record) => {
let params = {
...record,
birthDay: record.birthDate2
}
if (record.laborContract && record.laborContract.length > 0) {
params.laborContractStartAt = record.laborContract[0]
params.laborContractEndAt = record.laborContract[1]
}
params.imgs = (record.imgs && record.imgs.length) > 0 ? record.imgs.map(item => spliceUrl(item)) : []
params.attachments = (record.attachments && record.attachments.length) > 0 ? record.attachments.map(item => spliceUrl(item)) : []
params.commissionRate = record.commissionRate ?? record.commissionRate / 100
params.status = record.status == '4' ? '1' : '4'
console.log(params)
const { success } = await apis.serviceStaffList.updateItem(params).catch(() => {
throw new Error()
})
if (success) {
getPageList()
}
}
/**
* 删除
*/
function handleDelete({ id }) {
Modal.confirm({
title: t('pages.system.user.delTip'),
content: t('button.confirm'),
okText: t('button.confirm'),
onOk: () => {
return new Promise((resolve, reject) => {
; (async () => {
try {
const { success } = await apis.productOrder.delItem(id).catch(() => {
throw new Error()
})
if (config('http.code.success') === success) {
resolve()
message.success(t('component.message.success.delete'))
await getPageList()
}
} catch (error) {
reject()
}
})()
})
},
})
}
/**
* 分页
*/
function onTableChange({ current, pageSize }) {
paginationState.current = current
paginationState.pageSize = pageSize
getPageList()
}
/**
* 搜索
*/
function handleSearch() {
resetPagination()
getPageList()
}
/**
* 重置
*/
function handleResetSearch() {
searchFormData.value = {}
resetPagination()
getPageList()
}
/**
* 编辑完成
*/
async function onOk() {
await getPageList()
}
</script>
<style lang="less" scoped></style>