init
This commit is contained in:
2025-06-27 17:42:38 +08:00
commit bd6402478b
5317 changed files with 785994 additions and 0 deletions
@@ -0,0 +1,83 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
enum Api {
list = '/health-emergency/emergency/emergencySeriousDisease/list',
save = '/health-emergency/emergency/emergencySeriousDisease/add',
edit = '/health-emergency/emergency/emergencySeriousDisease/edit',
deleteOne = '/health-emergency/emergency/emergencySeriousDisease/delete',
deleteBatch = '/health-emergency/emergency/emergencySeriousDisease/deleteBatch',
importExcel = '/health-emergency/emergency/emergencySeriousDisease/importExcel',
exportXls = '/health-emergency/emergency/emergencySeriousDisease/exportXls',
queryById = '/health-emergency/emergency/emergencySeriousDisease/queryById',
getZHospital = '/health-emergency/api/emergency/resource/selectStationHospitalList',
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
export const queryByIdUrl = Api.queryById;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
export const getZHospitalApi = () => defHttp.get({ url: Api.getZHospital });
/**
* 删除单个
*/
export const deleteOne = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () =>
defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
}),
});
};
/**
* 批量删除
* @param params
* @param handleSuccess
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
},
});
};
/**
* 保存或者更新
* @param params
* @param isUpdate
*/
export const saveOrUpdate = (params, isUpdate) => {
const url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
@@ -0,0 +1,438 @@
import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
import { render } from '/@/utils/common/renderUtils';
import { getHospitalsList, getNewHospitalApi } from '../../system/user/user.api';
import { personType } from '/@/views/emergency/outburst/ScheduleCustom/ScheduleDefault.api';
import dayjs from 'dayjs';
import { onSitePersonNewApi } from '/@/views/emergency/communication/components/commApi';
import { useMessage } from '/@/hooks/web/useMessage';
import moment from 'moment';
import { getZHospitalApi } from '/@/views/emergency/EmergencySeriousDisease/EmergencySeriousDisease.api';
const { createMessage } = useMessage();
//列表数据
export const columns: BasicColumn[] = [
{
title: '就医人员',
align: 'center',
dataIndex: 'realname',
customRender: ({ record }) => {
const { realname, sex_dictText, age } = record;
return `${realname}-${sex_dictText}-${age}`;
},
},
{
title: '部门',
align: 'center',
dataIndex: 'userDepart',
},
// {
// title: '就医人员',
// align: 'center',
// dataIndex: 'sex_dictText',
// ifShow: false,
// },
{
title: '预约医院',
align: 'center',
dataIndex: 'hospitalName',
},
{
title: '挂号类别',
align: 'center',
dataIndex: 'registerCategory',
customRender: ({ text }) => {
return render.renderDict(text, 'category');
},
},
{
title: '预约科室',
align: 'center',
dataIndex: 'reservationOffice',
},
{
title: '预约医生',
align: 'center',
dataIndex: 'reservationDoctor',
},
{
title: '预约时间',
align: 'center',
dataIndex: 'reservationTime',
// return !text ? '' : text.length > 10 ? text.substr(0, 14) : text;
customRender: ({ text }) => {
if (text) {
return moment(text).format('yyyy-MM-DD HH:mm');
} else {
return '';
}
},
},
{
title: '期望预约时间',
align: 'center',
dataIndex: 'desireTime',
customRender: ({ text }) => {
if (text) {
return moment(text).format('yyyy-MM-DD HH:mm');
} else {
return '';
}
},
},
// {
// title: '真实姓名',
// align: 'center',
// dataIndex: 'realname',
// },
{
title: '驻场人员',
align: 'center',
dataIndex: 'stationUserName',
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
{
label: '就医人员',
field: 'realname',
component: 'Input',
colProps: {
span: 6,
},
},
{
label: '医院',
field: 'hospitalId',
component: 'ApiSelect',
colProps: {
span: 6,
},
componentProps: {
api: getNewHospitalApi,
resultField: 'list',
labelField: 'name',
valueField: 'id',
immediate: true,
},
},
{
label: '挂号类别',
field: 'registerCategory',
component: 'JDictSelectTag',
colProps: {
span: 6,
},
componentProps: {
dictCode: 'category',
},
},
{
label: '期望预约时间',
field: 'desireTime',
component: 'DatePicker',
componentProps: {
// format: 'YYYY-MM-DD HH:mm',
// showTime: { format: 'YYYY-MM-DD HH:mm' },
valueFormat: 'YYYY-MM-DD HH:mm:ss',
placeholder: '请选择期望预约时间',
},
},
];
function checkAge(_, value) {
if (!value) {
return Promise.reject('请输入年龄');
}
if (!Number.isInteger(value)) {
return Promise.reject('年龄必须是整数');
}
if (Number(value) < 1) {
return Promise.reject('请输入正确年龄');
} else {
return Promise.resolve();
}
}
//表单数据
// @ts-ignore
export const formSchema: FormSchema[] = [
{
label: '就医人员',
field: 'realname',
component: 'Input',
required: true,
componentProps: {
placeholder: '请选择就医人员',
readOnly: true,
onClick: () => {
// 弹窗选择所有用户
selUserModal.openModal();
},
},
},
{
label: '年龄',
field: 'age',
component: 'InputNumber',
rules: [{ required: true, trigger: 'blur', validator: checkAge }],
},
{
label: '性别',
field: 'sex',
component: 'JDictSelectTag',
required: true,
componentProps: {
dictCode: 'sex2',
type: 'radio',
// stringToNumber: true,
},
},
{
label: '部门',
field: 'userDepart',
component: 'Input',
ifShow: false,
},
{
label: '手机号码',
field: 'telPhone',
component: 'Input',
rules: [{ required: true, pattern: /^1[3456789]\d{9}$/, message: '${label}格式有误' }],
},
{
label: '身份证号',
field: 'idNo',
component: 'Input',
rules: [
{
required: true,
pattern: /^\d{6}(18|19|20)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|[xX])$/,
message: '${label}格式有误',
},
],
},
{
label: '',
field: 'userId', // 就医人员选中的用户ID
component: 'Input',
show: false,
},
{
label: '预约医院',
field: 'hospitalId',
component: 'ApiSelect',
required: true,
componentProps: ({ formModel }) => {
return {
api: getZHospitalApi,
resultField: 'list',
labelField: 'name',
valueField: 'id',
immediate: true,
onChange: (val, option) => {
formModel.hospitalId = val;
formModel.stationUserId = '';
formModel.stationUserName = '';
formModel.hospitalName = option?.label;
},
onDeselect: () => {
formModel.hospitalId = '';
formModel.stationUserId = '';
formModel.stationUserName = '';
},
// // 请求后回调
// onOptionsChange: (options) => {
// console.log('get options', options.length, options);
// },
onOptionsChange: () => {
// console.log("options",options)
},
};
},
},
{
label: '',
field: 'hospitalName', // 医院名称选中的医院ID
component: 'Input',
show: false,
},
{
label: '就诊卡号',
field: 'medicalCardNo',
component: 'Input',
rules: [
{
pattern: /^[0-9]*$/,
trigger: 'blur',
message: '就诊卡号格式有误',
required: false,
},
],
},
{
label: '挂号类别 ',
field: 'registerCategory',
component: 'JDictSelectTag',
required: true,
componentProps: {
dictCode: 'category',
},
},
// {
// label: '预约号',
// field: 'reservationNo',
// required: true,
// component: 'Input',
// },
{
label: '预约时间',
field: 'reservationTime',
component: 'DatePicker',
required: true,
componentProps: {
format: 'YYYY-MM-DD HH:mm',
valueFormat: 'YYYY-MM-DD HH:mm:ss',
showTime: { format: 'YYYY-MM-DD HH:mm' },
placeholder: '请选择预约时间',
},
},
{
label: '期望预约时间',
field: 'desireTime',
component: 'DatePicker',
required: true,
componentProps: {
format: 'YYYY-MM-DD HH:mm',
valueFormat: 'YYYY-MM-DD HH:mm:ss',
showTime: { format: 'YYYY-MM-DD HH:mm' },
placeholder: '请选择期望预约时间',
},
},
{
label: '预约科室',
field: 'reservationOffice',
component: 'Input',
},
{
label: '预约医生',
field: 'reservationDoctor',
component: 'Input',
},
{
label: '病情描述',
field: 'diseaseDescribe',
component: 'InputTextArea',
},
// {
// label: '特殊要求',
// field: 'specialRequirements',
// component: 'InputTextArea',
// },
{
label: '状态',
field: 'state',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'serious_medical_condition',
},
},
{
label: '驻场人员',
field: 'stationUserId',
component: 'ApiSelect',
componentProps: ({ formModel }) => {
return {
getPopupContainer: () => document.body,
api: onSitePersonNewApi,
params: {
personType: '7',
hospital: formModel.hospitalId || '@&^*G',
pageSize: 999,
},
resultField: 'list',
labelField: 'realname',
valueField: 'id',
immediate: true,
onChange: (e, option) => {
formModel.stationUserId = e;
formModel.stationUserName = option.label;
},
onFocus: () => {
if (!formModel.hospitalId) {
return createMessage.warn('请先选择医院!');
}
},
};
},
},
{
label: '驻场人员',
field: 'stationUserName',
component: 'Input',
show: false,
},
{
label: '派单时间',
field: 'sendOrderTime',
component: 'DatePicker',
componentProps: {
format: 'YYYY-MM-DD HH:mm',
valueFormat: 'YYYY-MM-DD HH:mm:ss',
showTime: { format: 'YYYY-MM-DD HH:mm' },
placeholder: '请选择派单时间',
},
},
{
label: '操作人员',
field: 'operatorId',
component: 'ApiSelect',
componentProps: () => {
return {
getPopupContainer: () => document.body,
api: personType,
params: {
personType: '5',
pageSize: 999,
},
resultField: 'list',
labelField: 'realname',
valueField: 'id',
immediate: true,
};
},
},
{
label: '驳回时间',
field: 'rejectionTime',
component: 'DatePicker',
componentProps: {
format: 'YYYY-MM-DD HH:mm',
valueFormat: 'YYYY-MM-DD HH:mm:ss',
showTime: { format: 'YYYY-MM-DD HH:mm' },
placeholder: '请选择驳回时间',
},
},
{
label: '驳回原因',
field: 'rejectionReason',
component: 'InputTextArea',
},
// TODO 主键隐藏字段,目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
];
/**
* 流程表单调用这个方法获取formSchema
* @param _formData
*/
export function getBpmFormSchema(_formData): FormSchema[] {
// 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
return formSchema;
}
@@ -0,0 +1,145 @@
<template>
<div>
<!--引用表格-->
<BasicTable :rowSelection="rowSelection" @register="registerTable">
<!--插槽:table标题-->
<template #tableTitle>
<a-button v-auth="'emergency:emergency_serious_disease:add'" preIcon="ant-design:plus-outlined" type="primary" @click="handleAdd">
新增
</a-button>
<a-button type="primary" @click="batchHandleDelete" preIcon="ant-design:delete-outlined"> 批量删除 </a-button>
<a-button
v-auth="'emergency:emergency_serious_disease:exportXls'"
preIcon="ant-design:export-outlined"
type="primary"
@click="onExportXls"
>导出</a-button
>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
</BasicTable>
<!-- 表单区域 -->
<EmergencySeriousDiseaseModal @register="registerDrawer" @success="handleSuccess" />
</div>
</template>
<script lang="ts" name="emergency-emergencySeriousDisease" setup>
import { BasicTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import EmergencySeriousDiseaseModal from './components/EmergencySeriousDiseaseModal.vue';
import { columns, searchFormSchema } from './EmergencySeriousDisease.data';
import { batchDelete, deleteOne, list } from './EmergencySeriousDisease.api';
import { message } from 'ant-design-vue';
import { useDrawer } from '/@/components/Drawer';
//注册model
const [registerDrawer, { openDrawer }] = useDrawer();
//注册table数据
const { tableContext, onExportXls } = useListPage({
tableProps: {
title: '大病就医',
api: list,
columns,
canResize: false,
clearSelectOnPageChange: true,
beforeFetch: (params) => {
return params;
},
formConfig: {
labelWidth: 90,
schemas: searchFormSchema,
autoSubmitOnEnter: true,
showAdvancedButton: false,
fieldMapToNumber: [],
fieldMapToTime: [],
},
actionColumn: {
width: 160,
fixed: 'right',
},
},
});
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
/**
* 新增事件
*/
function handleAdd() {
openDrawer(true, {
isUpdate: false,
showFooter: true,
title: '新增',
});
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
openDrawer(true, {
record,
isUpdate: true,
showFooter: true,
title: '编辑',
});
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
openDrawer(true, {
record,
isUpdate: true,
showFooter: false,
title: '详情',
});
}
/**
* 删除事件
*/
function handleDelete(record: Recordable) {
deleteOne({ id: record.id }, handleSuccess);
}
/**
* 批量删除事件
*/
function batchHandleDelete() {
if (selectedRowKeys.value.length === 0) {
return message.warning('未选中任何数据');
}
batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record: Recordable) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
auth: 'emergency:emergency_serious_disease:edit',
},
{
label: '详情',
onClick: handleDetail.bind(null, record),
},
{
label: '删除',
onClick: handleDelete.bind(null, record),
auth: 'emergency:emergency_serious_disease:delete',
},
];
}
</script>
<style scoped lang="less">
:deep(.ant-popover-inner) {
min-width: 150px;
}
</style>
@@ -0,0 +1,175 @@
<template>
<div>
<BasicDrawer
v-bind="$attrs"
:showFooter="showFooter"
@register="registerModal"
destroyOnClose
:title="title"
:width="800"
@ok="handleSubmit"
:maskClosable="false"
>
<BasicForm @register="registerForm" style="overflow: auto" />
</BasicDrawer>
<!-- <UserSelectModal rowKey="id" @register="registerSelUserModal" @getSelectResult="onSelectUserOk" />-->
<replace-other ref="replaceOtherRef" title="选择用户" @choose-employ="onSelectUserOk" />
<list-user-by-person-type @register="registerListModal" />
</div>
</template>
<script lang="ts" setup>
import { ref, unref } from 'vue';
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from '../EmergencySeriousDisease.data';
import { saveOrUpdate } from '../EmergencySeriousDisease.api';
import UserSelectModal from '/@/components/Form/src/jeecg/components/modal/UserSelectModalIllness.vue';
import { useModal } from '/@/components/Modal';
import { useDrawer } from '/@/components/Drawer';
import ListUserByPersonType from '/@/views/emergency/EmergencySeriousDisease/components/listUserByPersonType.vue';
import ReplaceOther from '/@/views/emergency/communication/components/replaceOther.vue';
const [registerSelUserModal, selUserModal] = useDrawer();
const [registerListModal, { openDrawer: openListModal }] = useDrawer();
// Emits声明
const emit = defineEmits(['register', 'success']);
const replaceOtherRef = ref();
const isUpdate = ref(true);
const showFooter = ref<boolean>(true);
//设置标题
const title = ref<string>('');
formSchema[0].componentProps.onClick = () => {
replaceOtherRef.value.showModal();
};
formSchema[7].componentProps.onOptionsChange = (options) => {
onSelectHospital(options);
};
function c(type, title) {
openListModal(true, {
personType: type,
title: title,
});
}
//
// formSchema.map((item) => {
// switch (item.field) {
// case 'stationUserName':
// item.componentProps.onClick = () => c('7', '驻场人员');
// break;
// case 'operatorName':
// item.componentProps.onClick = () => c('6', '操作人员');
// break;
// }
// });
//表单配置
const [registerForm, { setProps, resetFields, setFieldsValue, validate, clearValidate, updateSchema }] = useForm({
//labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { span: 24 },
});
//表单赋值
const [registerModal, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
//重置表单
await resetFields();
setDrawerProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter });
isUpdate.value = !!data?.isUpdate;
showFooter.value = data.showFooter;
title.value = data.title;
if (unref(isUpdate)) {
await updateSchema([{ field: 'userDepart', ifShow: true }]);
//表单赋值
await setFieldsValue({
...data.record,
});
if (!!data?.showFooter) {
await updateSchema([
{ field: 'age', ifShow: false },
{ field: 'sex', ifShow: false },
{ field: 'userDepart', ifShow: false },
{ field: 'telPhone', ifShow: false },
{ field: 'idNo', ifShow: false },
{ field: 'stationUserId', ifShow: true },
{ field: 'sendOrderTime', ifShow: true },
{ field: 'operatorId', ifShow: true },
{ field: 'rejectionTime', ifShow: true },
{ field: 'rejectionReason', ifShow: true },
]);
} else {
await updateSchema([
{ field: 'age', ifShow: true },
{ field: 'sex', ifShow: true },
{ field: 'userDepart', ifShow: true },
{ field: 'telPhone', ifShow: true },
{ field: 'idNo', ifShow: true },
{ field: 'stationUserId', ifShow: !!data.record.stationUserName },
{ field: 'sendOrderTime', ifShow: !!data.record.sendOrderTime },
{ field: 'operatorId', ifShow: !!data.record.operatorId },
{ field: 'rejectionTime', ifShow: !!data.record.rejectionTime },
{ field: 'rejectionReason', ifShow: !!data.record.rejectionReason },
]);
}
} else {
await updateSchema([
{ field: 'age', ifShow: false },
{ field: 'sex', ifShow: false },
{ field: 'userDepart', ifShow: false },
{ field: 'telPhone', ifShow: false },
{ field: 'idNo', ifShow: false },
{ field: 'stationUserId', ifShow: true },
{ field: 'sendOrderTime', ifShow: true },
{ field: 'operatorId', ifShow: true },
{ field: 'rejectionTime', ifShow: true },
{ field: 'rejectionReason', ifShow: true },
]);
}
await clearValidate();
// 隐藏底部时禁用整个表单
await setProps({ disabled: !data?.showFooter });
});
//表单提交事件
async function handleSubmit() {
try {
let values = await validate();
setDrawerProps({ confirmLoading: true });
//提交表单
await saveOrUpdate(values, isUpdate.value);
//关闭弹窗
closeDrawer();
//刷新列表
emit('success');
} finally {
setDrawerProps({ confirmLoading: false });
}
}
// 选择用户成功
async function onSelectUserOk(e) {
let json = JSON.parse(e);
await setFieldsValue({
realname: json.realname,
userId: json.id,
});
}
// 选择医院名称
async function onSelectHospital(options) {
await setFieldsValue({
hospitalName: options[0]['label'],
hospitalId: options[0]['value'],
});
}
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>
@@ -0,0 +1,16 @@
import { BasicColumn, FormSchema } from '/@/components/Table';
export const columns: BasicColumn[] = [
{
title: '名称',
align: 'center',
dataIndex: 'realname',
},
{
title: '性别',
align: 'center',
dataIndex: 'sex_dictText',
},
];
export const searchFormPersonType: FormSchema[] = [];
@@ -0,0 +1,55 @@
<template>
<!-- <BasicDrawer v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="600" @ok="handleSubmit">-->
<BasicDrawer
:title="title"
width="70%"
:showFooter="false"
destroyOnClose
v-bind="$attrs"
@ok="handleSubmit"
@register="registerModal"
:maskClosable="false"
>
<BasicTable :rowSelection="{ type: 'radio' }" @register="registerTable" />
</BasicDrawer>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import { personType } from '/@/views/emergency/outburst/ScheduleCustom/ScheduleDefault.api';
import { columns } from '/@/views/emergency/EmergencySeriousDisease/components/listUserByPersonType.data';
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
const personTypes = ref<String>('5');
const title = ref<String>('5');
const emit = defineEmits(['choosePerson']);
const [registerModal] = useDrawerInner(async (data) => {
personTypes.value = data.personType;
title.value = data.title;
});
const { tableContext } = useListPage({
tableProps: {
api: personType,
columns,
canResize: false,
clearSelectOnPageChange: true,
clickToRowSelect: true,
beforeFetch: (params) => {
params['personType'] = personTypes.value;
return params;
},
useSearchForm: false,
showActionColumn: false,
},
});
const [registerTable, {}, { rowSelection, selectedRowKeys }] = tableContext;
const handleSubmit = () => {
emit('choosePerson', {});
};
</script>
<style scoped lang="less">
:deep(.ant-table-title) {
display: none;
}
</style>
@@ -0,0 +1,11 @@
import { defHttp } from '/@/utils/http/axios';
enum Api {
list = '/health-emergency/api/aed/nearbyAed',
}
/**
* 列表接口
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
@@ -0,0 +1,322 @@
<template>
<div class="devive-map">
<div class="map-search-box">
<a-select
v-model:value="intValue"
allow-clear
show-search
label-in-value
placeholder="请输入地点"
style="width: 400px"
:default-active-first-option="false"
:show-arrow="true"
:filter-option="false"
:not-found-content="null"
@search="onSearch"
:options="panelList"
@change="handleChange"
/>
<!-- <a-button type="primary" @click="onButtonSearch"> 搜索 </a-button>-->
</div>
<div id="panel" style="display: none"></div>
<div class="list" id="list"> </div>
<div class="map" id="container"></div>
</div>
</template>
<script setup name="aed-map" lang="ts">
import { onMounted, reactive, ref } from 'vue';
import AMapLoader from '@amap/amap-jsapi-loader';
import { debounce } from 'lodash-es';
import positionIcon from '/@/assets/images/position.png';
import MarkersIcon from '/@/assets/images/markerCricle.png';
import { list } from './DeviceMap.api';
import { message } from 'ant-design-vue';
let SelfMap = null;
let BasicMap = null;
let overlayGroup = null;
const intValue = ref('');
let placeSearch = ref();
let panelList = ref([]);
let pointerArray = ref([]);
let positionRef = ref({
lng: '',
lat: '',
handleItem: {
pname: '',
},
});
let mapState = [];
let defaultMarker = null;
onMounted(() => {
initMap();
});
function initMap() {
AMapLoader.load({
key: '4bbcb216b889f2d612cbed05ae6979c8',
version: '2.0',
plugins: ['AMap.Geocoder'], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
})
.then((AMap) => {
SelfMap = AMap;
//设置地图容器id
BasicMap = new AMap.Map('container', {
viewMode: '3D', //是否为3D地图模式
// zoom: 11, //初始化地图级别
// center: [108.95, 34.33], //初始化地图中心点位置
resizeEnable: true,
});
// 注册搜索插件
bindSearch(AMap);
handleMarker({});
})
.catch((e) => {
console.log(e);
});
}
/*
** 获取区域对角线的两点坐标,即这个区域内的最小坐标值和最大坐标值
* @param pointerArray [[a,b],[c,d]]* @return Array {min:number[a,b], max:number[c,d]}
* */
function getMaxBoundsPointer(pointerArray) {
let lngArray = pointerArray.map((item) => item[0]);
let latArray = pointerArray.map((item) => item[1]);
return { min: [Math.min(...lngArray), Math.min(...latArray)], max: [Math.max(...lngArray), Math.max(...latArray)] };
}
/**
* @Description:输入框查询位置
* @date 2023/7/8
*/
function onSearch(value: string) {
//关键字查询
if (value) {
intValue.value = value;
searchRes(value);
}
}
const searchRes = debounce((value) => {
placeSearch.value.search(value, (status: string, result: any) => {
if (status === 'complete') {
panelList.value = result.poiList.pois.map((item) => ({ label: item.name, value: item.name, ...item }));
}
});
}, 500);
function onButtonSearch() {
onSearch(intValue.value);
}
/**
* @Description下拉框选择事件
* @date 2023/8/30
*/
function handleChange(value: any, option: any) {
if (option) {
setMapZoom(16);
let params = {
longitude: option.location.lng, // 经度
latitude: option.location.lat, // 纬度
radiusRange: '50', // 半径范围
};
addDefault(option.location.lng, option.location.lat);
handleMarker(params);
} else {
handleMarker({});
setMapZoom(12);
removeDefault();
}
}
function handleMarker(params) {
list(params).then((res) => {
if (res.length > 0) {
pointerArray.value = res;
let maxLocations = getMaxBoundsPointer(res.map((item) => [item.longitude, item.latitude]));
hanleBounds(maxLocations);
addMarker(res);
} else {
removeMarker();
// message.warn('该位置附近暂无设备!');
}
});
}
function hanleBounds(maxLocations) {
let lngGap = (maxLocations.max[0] - maxLocations.min[0]) / 4;
let latGap = (maxLocations.max[1] - maxLocations.min[1]) / 4;
let min = new SelfMap.LngLat(maxLocations.min[0] - lngGap, maxLocations.min[1] - latGap);
let max = new SelfMap.LngLat(maxLocations.max[0] + lngGap, maxLocations.max[1] + latGap);
if (pointerArray.value.length > 1) {
let bounds = new SelfMap.Bounds(min, max);
BasicMap.setBounds(bounds);
}
// 2. 一个点时,将其作为中心点
else if (pointerArray.value.length === 1) {
let pointValue = pointerArray.value;
let centerLngLat = new SelfMap.LngLat(pointValue[0].longitude, pointValue[0].latitude);
BasicMap.setCenter(centerLngLat); // 设置地图中心点坐标
}
}
// 加载默认图标
function addDefault(longitude, latitude) {
removeDefault();
let defaultIcon = new SelfMap.Icon({
image: MarkersIcon,
size: new SelfMap.Size(50, 58), //图标大小
imageSize: new SelfMap.Size(50, 58),
});
defaultMarker = new SelfMap.Marker({
icon: defaultIcon,
position: [longitude, latitude],
offset: [-18, -32],
maxZoom: 14,
});
defaultMarker.setMap(BasicMap);
BasicMap.setCenter([longitude, latitude], true);
}
function addMarker(position) {
removeMarker();
if (position.length === 0) {
return;
}
overlayGroup = new SelfMap.OverlayGroup();
position.map((item) => {
let marker = new SelfMap.Marker({
icon: positionIcon,
position: [item.longitude, item.latitude],
offset: [-18, -32],
maxZoom: 14,
});
marker.on('click', () => {
infoWindow(item);
});
overlayGroup.setMap(BasicMap);
overlayGroup.addOverlay(marker);
});
}
function removeDefault() {
defaultMarker && BasicMap.remove(defaultMarker);
}
function removeMarker() {
if (overlayGroup) {
BasicMap.remove(overlayGroup);
overlayGroup.setMap(null);
overlayGroup = null;
}
}
function infoWindow(position) {
let startDiv = `<div class="dialog-conMap">
<div class="item">
<span> 设备型号:</span>
<span>${position.hostModel}</span>
</div>
<div class="item">
<span>设备编号:</span>
<span>${position.hostSerialNum}</span>
</div>
`;
if (position.installAddress) {
startDiv += `<div class="item">
<span>布点位置:</span>
<span>${position.installAddress}</span>
</div>`;
}
if (position.mfrsMobile) {
startDiv += ` <div class="item">
<span>售后电话:</span>
<span>${position.mfrsMobile}</span>
</div>`;
}
if (position.manageUserMobile) {
startDiv += ` <div class="item">
<span>管理人电话:</span>
<span>${position.manageUserMobile}</span>
</div>`;
}
if (position?.chargeFirstMobile) {
startDiv += ` <div class="item">
<span>负责人1电话:</span>
<span>${position?.chargeFirstMobile}</span>
</div>`;
}
if (position.chargeSecondMobile) {
startDiv += ` <div class="item">
<span>负责人2电话:</span>
<span>${position?.chargeSecondMobile}</span>
</div>`;
}
let endDiv = `</div>`;
let infoWindow = new SelfMap.InfoWindow({
position: [position.longitude, position.latitude],
offset: new SelfMap.Pixel(0, -30),
content: startDiv + endDiv,
});
infoWindow.open(BasicMap);
}
function setMapZoom(zoom: number) {
if (zoom) BasicMap && (BasicMap as any).setZoom(zoom);
}
// 搜索插件
function bindSearch(AMap) {
AMap.plugin(['AMap.PlaceSearch'], function () {
//构造地点查询类
placeSearch.value = new AMap.PlaceSearch({
pageSize: 20, // 单页显示结果条数
pageIndex: 1, // 页码
panel: 'panel', // 结果列表将在此容器中进行展示。
autoFitView: false, // 是否自动调整地图视野使绘制的 Marker点都处于视口的可见范围
});
});
}
</script>
<style scoped lang="less">
.devive-map {
width: 100%;
height: calc(100vh - 130px);
.map {
width: 100%;
height: 100%;
}
.map-search-box {
position: absolute;
top: 20px;
left: 20px;
z-index: 10;
box-shadow: 1px 2px 1px rgba(0, 0, 0, 0.15);
}
.panel-list {
position: absolute;
background-color: white;
max-height: 90%;
overflow-y: auto;
top: 70px;
left: 13px;
width: 280px;
z-index: 9;
.panel-item {
padding: 10px 5px;
color: #999;
line-height: 20px;
}
}
}
</style>
<style lang="less">
.dialog-conMap {
padding: 10px;
width: 380px;
.item {
padding: 8px 0;
display: flex;
span:nth-child(1) {
display: inline-block;
width: 30%;
text-align: right;
}
span:nth-child(2) {
display: inline-block;
width: 70%;
text-align: left;
}
}
}
</style>
@@ -0,0 +1,78 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
enum Api {
list = '/health-emergency/emergency/aed/list',
save = '/health-emergency/emergency/aed/add',
edit = '/health-emergency/emergency/aed/edit',
deleteOne = '/health-emergency/emergency/aed/delete',
deleteBatch = '/health-emergency/emergency/aed/deleteBatch',
importExcel = '/health-emergency/emergency/aed/importExcel',
exportXls = '/health-emergency/emergency/aed/exportXls',
queryById = '/health-emergency/emergency/aed/queryById',
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
export const queryByIdUrl = Api.queryById;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
* 删除单个
*/
export const deleteOne = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () =>
defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
}),
});
};
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true });
handleSuccess();
},
});
};
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
const url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
@@ -0,0 +1,510 @@
import { BasicColumn, FormSchema } from '/@/components/Table';
import { render } from '/@/utils/common/renderUtils';
import { RendererElement, RendererNode, VNode } from 'vue';
import { getSecondaryDepartmentList, getThirdDepartListByOrgCode } from '/@/views/system/user/user.api';
import { BODY_CONTAINER } from '/@/utils/domUtils';
import { rules } from '/@/utils/helper/validator';
import { useMessage } from '/@/hooks/web/useMessage';
const { createMessage } = useMessage();
const renderStatusTag = (span: VNode<RendererNode, RendererElement, { [p: string]: any }>) => {
const text = span.children;
switch (text) {
case '正常':
return render.renderTag(text, '#31d731');
case '快过期':
case '需检查':
case '电量低':
return render.renderTag(text, '#FFA440');
case '已过期':
case '需更换':
case '未找到':
case '无连接':
return render.renderTag(text, '#f04141');
case '待确认':
return render.renderTag(text, '#999999');
default:
return text;
}
};
//列表数据
export const columns: BasicColumn[] = [
{
title: '所属单位',
align: 'center',
dataIndex: 'secondDepartName',
},
{
title: '所属部门',
align: 'center',
dataIndex: 'departName',
},
{
title: '设备名称',
align: 'center',
dataIndex: 'name',
},
{
title: '设备厂商',
align: 'center',
dataIndex: 'mfrsName',
},
{
title: '设备型号',
align: 'center',
dataIndex: 'hostModel',
},
{
title: '设备编号',
align: 'center',
dataIndex: 'hostSerialNum',
},
{
title: '入库时间',
align: 'center',
dataIndex: 'createTime',
},
{
title: '管理部门',
align: 'center',
dataIndex: 'manageDepartName',
},
{
title: '管理电话',
align: 'center',
dataIndex: 'manageUserMobile',
},
{
title: '厂商电话',
align: 'center',
dataIndex: 'mfrsMobile',
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
{
label: '所属单位',
field: 'second',
component: 'ApiSelect',
componentProps: () => {
return {
api: getSecondaryDepartmentList,
resultField: 'result',
labelField: 'departName',
valueField: 'orgCode',
};
},
},
{
label: '所属部门',
field: 'three',
component: 'ApiSelect',
componentProps: ({ formModel }) => {
return {
api: getThirdDepartListByOrgCode,
resultField: 'list',
labelField: 'departName',
valueField: 'orgCode',
params: {
orgCode: formModel?.second || 'asd(*',
},
onFocus: () => {
if (!formModel.second) {
return createMessage.warn('请先选择所属单位!');
}
},
};
},
},
{
label: '管理部门',
field: 'manageDepartCode',
component: 'ApiSelect',
componentProps: ({ formModel }) => {
return {
api: getThirdDepartListByOrgCode,
resultField: 'result',
labelField: 'departName',
valueField: 'orgCode',
params: {
orgCode: formModel?.second || 'asd(*',
},
onFocus: () => {
if (!formModel.second) {
return createMessage.warn('请先选择所属单位!');
}
},
};
},
},
{
label: '设备名称',
field: 'name',
component: 'Input',
},
{
label: '设备型号',
field: 'hostModel',
component: 'Input',
},
{
label: '设备编号',
field: 'hostSerialNum',
component: 'Input',
},
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '详情字段',
field: 'infoFlag',
component: 'Input',
ifShow: false,
},
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
{
label: '设备信息',
field: 'deviceInfoLine',
component: 'Divider',
componentProps: {
//文字是否显示为普通正文样式
plain: false,
},
},
{
label: '设备名称',
field: 'name',
component: 'Input',
required: true,
},
{
label: '所属单位',
field: 'second',
component: 'ApiSelect',
required: true,
componentProps: () => {
return {
api: getSecondaryDepartmentList,
resultField: 'result',
labelField: 'departName',
valueField: 'orgCode',
showSearch: true,
filterOption: (input: string, option: any): boolean => {
const str: string = input.toLowerCase();
return option.label.toLowerCase().indexOf(str) >= 0;
},
};
},
},
{
label: '所属部门',
field: 'departCode',
component: 'ApiSelect',
required: true,
componentProps: ({ formModel }) => {
return {
api: getThirdDepartListByOrgCode,
resultField: 'list',
labelField: 'departName',
valueField: 'orgCode',
params: {
orgCode: formModel?.second || 'asd(*',
},
showSearch: true,
filterOption: (input: string, option: any): boolean => {
const str: string = input.toLowerCase();
return option.label.toLowerCase().indexOf(str) >= 0;
},
onFocus: () => {
if (!formModel.second) {
return createMessage.warn('请先选择所属单位!');
}
},
};
},
},
{
label: '自检状态',
field: 'checkStatus',
component: 'Input',
render: ({ values, field }) => {
return renderStatusTag(render.renderDict(values[field], 'aed_check_status'));
},
ifShow: ({ values }) => {
return values.infoFlag == true;
},
},
{
label: '电极片状态',
field: 'electrodeSheetStatus',
component: 'Input',
render: ({ values, field }) => {
return renderStatusTag(render.renderDict(values[field], 'aed_electrode_sheet_status'));
},
ifShow: ({ values }) => {
return values.infoFlag == true;
},
},
{
label: '电池状态',
field: 'batteryStatus',
component: 'Input',
render: ({ values, field }) => {
return renderStatusTag(render.renderDict(values[field], 'aed_battery_status'));
},
ifShow: ({ values }) => {
return values.infoFlag == true;
},
},
{
label: '路由状态',
field: 'routerStatus',
component: 'Input',
render: ({ values, field }) => {
return renderStatusTag(render.renderDict(values[field], 'aed_router_status'));
},
ifShow: ({ values }) => {
return values.infoFlag == true;
},
},
{
label: '设备型号',
field: 'hostModel',
component: 'Input',
required: true,
},
{
label: '设备编号',
field: 'hostSerialNum',
component: 'Input',
required: true,
},
{
label: '电极片有效期',
field: 'electrodeSheetValidTime',
component: 'DatePicker',
componentProps: {
showTime: false,
valueFormat: 'YYYY-MM',
picker: 'month',
},
},
{
label: '路由器型号',
field: 'routerModel',
component: 'Input',
},
{
label: '路由器序列号',
field: 'routerSerialNum',
component: 'Input',
},
{
label: '电池型号',
field: 'batteryModel',
component: 'Input',
},
{
label: '电池电压',
field: 'batteryVoltage',
component: 'InputNumber',
componentProps: {
min: 0,
controls: false,
addonAfter: 'V',
},
},
{
label: '质保时间',
field: 'warrantyDate',
component: 'RangePicker',
componentProps: ({ formModel }) => {
return {
showTime: false,
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD',
getPopupContainer: () => BODY_CONTAINER,
// onChange: ([start, end]) => {
// formModel.warrantyStartDate = start;
// formModel.warrantyEndDate = end;
// },
'onUpdate:value': (value) => {
if (value) {
formModel.warrantyStartDate = value[0];
formModel.warrantyEndDate = value[1];
} else {
formModel.warrantyStartDate = null;
formModel.warrantyEndDate = null;
}
},
};
},
},
{
label: '质保开始时间',
field: 'warrantyStartDate',
component: 'Input',
show: false,
},
{
label: '质保结束时间',
field: 'warrantyEndDate',
component: 'Input',
show: false,
},
{
label: '设备图片',
field: 'aedImg',
component: 'JImageUpload',
componentProps: {
fileMax: 5,
},
},
{
label: '管理信息',
field: 'manageInfoLine',
component: 'Divider',
componentProps: {
//文字是否显示为普通正文样式
plain: false,
},
},
{
label: '负责人id',
field: 'manageUserId',
component: 'Input',
show: false,
},
{
label: '管理部门',
field: 'manageDepartCode',
component: 'ApiSelect',
required: true,
componentProps: ({ formModel }) => {
return {
api: getThirdDepartListByOrgCode,
resultField: 'list',
labelField: 'departName',
valueField: 'orgCode',
params: {
orgCode: formModel?.second || 'asd(*',
},
showSearch: true,
filterOption: (input: string, option: any): boolean => {
const str: string = input.toLowerCase();
return option.label.toLowerCase().indexOf(str) >= 0;
},
onFocus: () => {
if (!formModel.second) {
return createMessage.warn('请先选择所属单位!');
}
},
};
},
},
{
label: '管理人员',
field: 'manageUserName',
component: 'Input',
required: true,
},
{
label: '管理电话',
field: 'manageUserMobile',
component: 'Input',
required: true,
rules: rules.rule('phone', true),
},
{
label: '负责人员1',
field: 'chargeFirst',
component: 'Input',
},
{
label: '负责电话1',
field: 'chargeFirstMobile',
component: 'Input',
rules: rules.rule('phone', false),
},
{
label: '负责人员2',
field: 'chargeSecond',
component: 'Input',
},
{
label: '负责电话2',
field: 'chargeSecondMobile',
component: 'Input',
rules: rules.rule('phone', false),
},
{
label: '安装信息',
field: 'installInfoLine',
component: 'Divider',
componentProps: {
//文字是否显示为普通正文样式
plain: false,
},
},
{
label: '厂商名称',
field: 'mfrsName',
component: 'Input',
},
{
label: '联系电话',
field: 'mfrsMobile',
component: 'Input',
rules: rules.rule('phone', false),
},
{
label: '覆盖人数',
field: 'coverUserNum',
component: 'InputNumber',
},
{
label: '安装位置',
field: 'installAddress',
component: 'Input',
required: true,
slot: 'address',
},
{
label: '经度',
field: 'longitude',
required: true,
component: 'InputNumber',
},
{
label: '纬度',
field: 'latitude',
required: true,
component: 'InputNumber',
},
{
label: '位置照片',
field: 'installAddressImg',
component: 'JImageUpload',
componentProps: {
fileMax: 5,
},
},
];
/**
* 流程表单调用这个方法获取formSchema
* @param param
*/
export function getBpmFormSchema(_formData): FormSchema[] {
// 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
return formSchema;
}
@@ -0,0 +1,185 @@
<template>
<div>
<!--引用表格-->
<BasicTable :rowSelection="rowSelection" @register="registerTable">
<!--插槽:table标题-->
<template #tableTitle>
<a-button v-auth="'emergency:emergency_resource:add'" preIcon="ant-design:plus-outlined" type="primary" @click="handleAdd">
新增
</a-button>
<a-button
v-auth="'emergency:emergency_resource:delete'"
preIcon="ant-design:delete-outlined"
type="primary"
@click="batchHandleDelete"
>
批量删除
</a-button>
<!-- <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> -->
<!-- <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> -->
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
<!--字段回显插槽-->
<template #htmlSlot="{ text }">
<div v-html="text"></div>
</template>
</BasicTable>
<!-- 表单区域 -->
<DeviceDrawer @register="registerDrawer" @success="handleSuccess" />
</div>
</template>
<script lang="ts" name="aed-device" setup>
import { ref } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import DeviceDrawer from './components/DeviceDrawer.vue';
import { columns, searchFormSchema } from './Device.data';
import { batchDelete, deleteOne, getExportUrl, getImportUrl, list } from './Device.api';
import { message } from 'ant-design-vue';
import { useDrawer } from '/@/components/Drawer';
const checkedKeys = ref<Array<string | number>>([]);
//注册model
const [registerDrawer, { openDrawer }] = useDrawer();
//注册table数据
const { prefixCls, tableContext } = useListPage({
tableProps: {
title: '设备管理',
api: list,
columns,
canResize: false,
formConfig: {
//labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter: true,
showAdvancedButton: false,
fieldMapToNumber: [],
fieldMapToTime: [],
},
actionColumn: {
width: 160,
fixed: 'right',
},
beforeFetch: (info) => {
info['name'] = info?.name && `*${info.name}*`;
info['hostModel'] = info?.hostModel && `*${info.hostModel}*`;
if (info.second) {
info['departCode'] = `${info.second}*`;
}
if (info.three) {
info['departCode'] = `${info.three}`;
}
info['departCode'] = info?.departCode && `${info.departCode}`;
info['hostSerialNum'] = info?.hostSerialNum && `*${info.hostSerialNum}*`;
info['aidrange'] = info?.aidrange && `*${info.aidrange}*`;
return info;
},
},
exportConfig: {
name: '应急资源',
url: getExportUrl,
},
importConfig: {
url: getImportUrl,
success: handleSuccess,
},
});
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
/**
* 新增事件
*/
function handleAdd() {
openDrawer(true, {
isUpdate: false,
showFooter: true,
title: '新增',
});
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
record.infoFlag = false;
record.warrantyDate = [record.warrantyStartDate, record.warrantyEndDate];
openDrawer(true, {
record,
isUpdate: true,
showFooter: true,
title: '编辑',
});
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
record.infoFlag = true;
record.warrantyDate = [record.warrantyStartDate, record.warrantyEndDate];
openDrawer(true, {
record,
isUpdate: true,
showFooter: false,
title: '详情',
});
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({ id: record.id }, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
if (selectedRowKeys.value.length === 0) {
return message.warning('未选中任何数据');
}
await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
console.log(111111111111);
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
auth: 'emergency:emergency_resource:edit',
},
{
label: '详情',
onClick: handleDetail.bind(null, record),
},
{
label: '删除',
onClick: handleDelete.bind(null, record),
auth: 'emergency:emergency_resource:delete',
},
];
}
</script>
<style lang="less" scoped>
:deep(.ant-popover-buttons) {
display: flex !important;
}
</style>
@@ -0,0 +1,125 @@
<template>
<BasicDrawer :showFooter="showFooter" :title="title" :width="800" destroyOnClose v-bind="$attrs" @ok="handleSubmit" @register="registerModal">
<BasicForm @register="registerForm">
<template #address="{ model }">
<a-input v-model:value="model['installAddress']" placeholder="请输入安装位置或地图选点" :disabled="!showFooter" style="width: 82%" />
<a-button :disabled="!showFooter" style="margin-left: 10px" @click="viewMap"> 查看地图 </a-button>
</template>
</BasicForm>
<Map ref="map" :state="state" @register="registerMap" @get-position="getPosition" />
</BasicDrawer>
</template>
<script lang="ts" setup>
import { ref, unref } from 'vue';
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from '../Device.data';
import { saveOrUpdate } from '../Device.api';
import Map from '/@/views/consult/resource/components/Map.vue';
import { useModal } from '/@/components/Modal';
// Emits声明
const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true);
const showFooter = ref<boolean>(true);
const state = ref();
//设置标题
const title = ref<string>('');
//表单配置
const [registerForm, { setProps, resetFields, setFieldsValue, validate, getFieldsValue, clearValidate }] = useForm({
//labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { span: 24 },
});
const [registerMap, { openModal }] = useModal();
//表单赋值
const [registerModal, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
//重置表单
await resetFields();
setDrawerProps({
confirmLoading: false,
showCancelBtn: !!data?.showFooter,
showOkBtn: !!data?.showFooter,
});
isUpdate.value = !!data?.isUpdate;
showFooter.value = data.showFooter;
title.value = data.title;
let customAddress = '';
if (unref(isUpdate)) {
customAddress = `${data.record?.longitude}${data.record?.latitude}`;
//表单赋值
await setFieldsValue({
...data.record,
customAddress,
second: data.record?.departCode.slice(0, 6),
});
state.value = data.record;
} else {
state.value = {};
}
await clearValidate();
// 隐藏底部时禁用整个表单
await setProps({ disabled: !data?.showFooter });
});
function viewMap() {
openModal(true, {
record: { ...getFieldsValue() },
});
}
async function getPosition(val) {
let { pname, cityname, adname, address, name } = val.handleItem || '';
let nameList = [pname, cityname, adname, address, name];
let str = '';
nameList.map((item) => {
if (item !== undefined) {
str += item;
}
});
await setFieldsValue({
latitude: val.lat,
longitude: val.lng,
customAddress: `${val.lng}${val.lat}`,
installAddress: str,
});
state.value = {
...state.value,
latitude: val.lat,
longitude: val.lng,
};
}
//表单提交事件
async function handleSubmit() {
try {
let values = await validate();
setDrawerProps({ confirmLoading: true });
const params = {
...state.value,
...values,
};
//提交表单
await saveOrUpdate(params, isUpdate.value);
//关闭弹窗
closeDrawer();
//刷新列表
emit('success');
} finally {
setDrawerProps({ confirmLoading: false });
}
}
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>
@@ -0,0 +1,78 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
enum Api {
list = '/health-emergency/emergency/aed/list',
save = '/health-emergency/emergency/aed/add',
edit = '/health-emergency/emergency/aed/edit',
deleteOne = '/health-emergency/emergency/aed/delete',
deleteBatch = '/health-emergency/emergency/aed/deleteBatch',
importExcel = '/health-emergency/emergency/aed/importExcel',
exportXls = '/health-emergency/emergency/aed/exportXls',
queryById = '/health-emergency/emergency/aed/queryById',
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
export const queryByIdUrl = Api.queryById;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
* 删除单个
*/
export const deleteOne = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () =>
defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
}),
});
};
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true });
handleSuccess();
},
});
};
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
const url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
@@ -0,0 +1,566 @@
import { BasicColumn, FormSchema } from '/@/components/Table';
import { render } from '/@/utils/common/renderUtils';
import { RendererElement, RendererNode, VNode } from 'vue';
import { getSecondaryDepartmentList, getThirdDepartListByOrgCode } from '/@/views/system/user/user.api';
import { BODY_CONTAINER } from '/@/utils/domUtils';
import { rules } from '/@/utils/helper/validator';
import { useMessage } from '/@/hooks/web/useMessage';
const { createMessage } = useMessage();
const renderStatusTag = (span: VNode<RendererNode, RendererElement, { [p: string]: any }>) => {
const text = span.children;
switch (text) {
case '正常':
return render.renderTag(text, '#31d731');
case '快过期':
case '需检查':
case '电量低':
return render.renderTag(text, '#FFA440');
case '已过期':
case '需更换':
case '未找到':
case '无连接':
return render.renderTag(text, '#f04141');
case '待确认':
return render.renderTag(text, '#999999');
default:
return text;
}
};
//列表数据
export const columns: BasicColumn[] = [
{
title: '所属单位',
align: 'center',
dataIndex: 'secondDepartName',
},
{
title: '所属部门',
align: 'center',
dataIndex: 'departName',
},
{
title: '所属单位',
align: 'center',
dataIndex: 'manageDepartName',
},
{
title: '设备编号',
align: 'center',
dataIndex: 'hostSerialNum',
},
{
title: '布点位置',
align: 'center',
dataIndex: 'installAddress',
},
{
title: '布点坐标',
align: 'center',
dataIndex: 'longitude',
customRender: ({ record }) => {
const { longitude, latitude} = record;
const val = longitude !== null && latitude !== null ? `${longitude},${latitude}` : '';
return val;
},
},
{
title: '覆盖人数',
align: 'center',
dataIndex: 'coverUserNum',
},
{
title: '自检状态',
align: 'center',
dataIndex: 'checkStatus',
customRender: ({ text }) => {
return renderStatusTag(render.renderDict(text, 'aed_check_status'));
},
},
{
title: '电极片监控',
align: 'center',
dataIndex: 'electrodeSheetStatus',
customRender: ({ text }) => {
return renderStatusTag(render.renderDict(text, 'aed_electrode_sheet_status'));
},
},
{
title: '电池监控',
align: 'center',
dataIndex: 'batteryStatus',
customRender: ({ text }) => {
return renderStatusTag(render.renderDict(text, 'aed_battery_status'));
},
},
{
title: '路由监控',
align: 'center',
dataIndex: 'routerStatus',
customRender: ({ text }) => {
return renderStatusTag(render.renderDict(text, 'aed_router_status'));
},
},
{
title: '布防时间',
align: 'center',
dataIndex: 'createTime',
},
{
title: '管理单位',
align: 'center',
dataIndex: 'manageDepartName',
},
{
title: '管理人',
align: 'center',
dataIndex: 'manageUserName',
},
{
title: '管理人电话',
align: 'center',
dataIndex: 'manageUserMobile',
},
{
title: '负责人1',
align: 'center',
dataIndex: 'chargeFirst',
},
{
title: '负责人1电话',
align: 'center',
dataIndex: 'chargeFirstMobile',
},
{
title: '负责人2',
align: 'center',
dataIndex: 'chargeSecond',
},
{
title: '负责人2电话',
align: 'center',
dataIndex: 'chargeSecondMobile',
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
{
label: '所属单位',
field: 'second',
component: 'ApiSelect',
componentProps: () => {
return {
api: getSecondaryDepartmentList,
resultField: 'result',
labelField: 'departName',
valueField: 'orgCode',
};
},
},
{
label: '所属部门',
field: 'three',
component: 'ApiSelect',
componentProps: ({ formModel }) => {
return {
api: getThirdDepartListByOrgCode,
resultField: 'list',
labelField: 'departName',
valueField: 'orgCode',
params: {
orgCode: formModel?.second || 'asd(*',
},
onFocus: () => {
if (!formModel.second) {
return createMessage.warn('请先选择所属单位!');
}
},
};
},
},
// {
// label: 'AED型号',
// field: 'hostModel',
// component: 'Input',
// },
{
label: '设备编号',
field: 'hostSerialNum',
component: 'Input',
},
{
label: '自检状态',
field: 'checkStatus',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'aed_check_status',
},
},
{
label: '电极片监控',
field: 'electrodeSheetStatus',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'aed_electrode_sheet_status',
},
},
{
label: '电池监控',
field: 'batteryStatus',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'aed_battery_status',
},
},
{
label: '路由监控',
field: 'routerStatus',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'aed_router_status',
},
},
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '详情字段',
field: 'infoFlag',
component: 'Input',
ifShow: false,
},
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
{
label: '设备信息',
field: 'deviceInfoLine',
component: 'Divider',
componentProps: {
//文字是否显示为普通正文样式
plain: false,
},
},
{
label: '设备名称',
field: 'name',
component: 'Input',
required: true,
},
{
label: '所属单位',
field: 'second',
component: 'ApiSelect',
required: true,
componentProps: () => {
return {
api: getSecondaryDepartmentList,
resultField: 'result',
labelField: 'departName',
valueField: 'orgCode',
showSearch: true,
filterOption: (input: string, option: any): boolean => {
const str: string = input.toLowerCase();
return option.label.toLowerCase().indexOf(str) >= 0;
},
};
},
},
{
label: '所属部门',
field: 'departCode',
component: 'ApiSelect',
required: true,
componentProps: ({ formModel }) => {
return {
api: getThirdDepartListByOrgCode,
resultField: 'list',
labelField: 'departName',
valueField: 'orgCode',
params: {
orgCode: formModel?.second || 'asd(*',
},
showSearch: true,
filterOption: (input: string, option: any): boolean => {
const str: string = input.toLowerCase();
return option.label.toLowerCase().indexOf(str) >= 0;
},
onFocus: () => {
if (!formModel.second) {
return createMessage.warn('请先选择所属单位!');
}
},
};
},
},
{
label: '自检状态',
field: 'checkStatus',
component: 'Input',
render: ({ values, field }) => {
return renderStatusTag(render.renderDict(values[field], 'aed_check_status'));
},
ifShow: ({ values }) => {
return values.infoFlag == true;
},
},
{
label: '电极片监控',
field: 'electrodeSheetStatus',
component: 'Input',
render: ({ values, field }) => {
return renderStatusTag(render.renderDict(values[field], 'aed_electrode_sheet_status'));
},
ifShow: ({ values }) => {
return values.infoFlag == true;
},
},
{
label: '电池监控',
field: 'batteryStatus',
component: 'Input',
render: ({ values, field }) => {
return renderStatusTag(render.renderDict(values[field], 'aed_battery_status'));
},
ifShow: ({ values }) => {
return values.infoFlag == true;
},
},
{
label: '路由监控',
field: 'routerStatus',
component: 'Input',
render: ({ values, field }) => {
return renderStatusTag(render.renderDict(values[field], 'aed_router_status'));
},
ifShow: ({ values }) => {
return values.infoFlag == true;
},
},
{
label: '设备型号',
field: 'hostModel',
component: 'Input',
required: true,
},
{
label: '设备编号',
field: 'hostSerialNum',
component: 'Input',
required: true,
},
{
label: '电极片有效期',
field: 'electrodeSheetValidTime',
component: 'DatePicker',
componentProps: {
showTime: false,
valueFormat: 'YYYY-MM',
picker: 'month',
},
},
{
label: '路由器型号',
field: 'routerModel',
component: 'Input',
},
{
label: '路由器序列号',
field: 'routerSerialNum',
component: 'Input',
},
{
label: '电池型号',
field: 'batteryModel',
component: 'Input',
},
{
label: '电池电压',
field: 'batteryVoltage',
component: 'InputNumber',
componentProps: {
min: 0,
controls: false,
addonAfter: 'V',
},
},
{
label: '质保时间',
field: 'warrantyDate',
component: 'RangePicker',
componentProps: ({ formModel }) => {
return {
showTime: false,
format: 'YYYY-MM-DD',
getPopupContainer: () => BODY_CONTAINER,
onChange: ([start, end]) => {
formModel.warrantyStartDate = start;
formModel.warrantyEndDate = end;
},
};
},
},
{
label: '质保开始时间',
field: 'warrantyStartDate',
component: 'Input',
show: false,
},
{
label: '质保结束时间',
field: 'warrantyEndDate',
component: 'Input',
show: false,
},
{
label: '设备图片',
field: 'aedImg',
component: 'JImageUpload',
componentProps: {
fileMax: 5,
},
},
{
label: '管理信息',
field: 'manageInfoLine',
component: 'Divider',
componentProps: {
//文字是否显示为普通正文样式
plain: false,
},
},
{
label: '负责人id',
field: 'manageUserId',
component: 'Input',
show: false,
},
{
label: '管理部门',
field: 'manageDepartCode',
component: 'ApiSelect',
required: true,
componentProps: ({ formModel }) => {
return {
api: getThirdDepartListByOrgCode,
resultField: 'list',
labelField: 'departName',
valueField: 'orgCode',
params: {
orgCode: formModel?.second || 'asd(*',
},
showSearch: true,
filterOption: (input: string, option: any): boolean => {
const str: string = input.toLowerCase();
return option.label.toLowerCase().indexOf(str) >= 0;
},
onFocus: () => {
if (!formModel.second) {
return createMessage.warn('请先选择所属单位!');
}
},
};
},
},
{
label: '管理人员',
field: 'manageUserName',
component: 'Input',
required: true,
},
{
label: '管理电话',
field: 'manageUserMobile',
component: 'Input',
required: true,
rules: rules.rule('phone', true),
},
{
label: '负责人员1',
field: 'chargeFirst',
component: 'Input',
},
{
label: '负责电话1',
field: 'chargeFirstMobile',
component: 'Input',
rules: rules.rule('phone', false),
},
{
label: '负责人员2',
field: 'chargeSecond',
component: 'Input',
},
{
label: '负责电话2',
field: 'chargeSecondMobile',
component: 'Input',
rules: rules.rule('phone', false),
},
{
label: '安装信息',
field: 'installInfoLine',
component: 'Divider',
componentProps: {
//文字是否显示为普通正文样式
plain: false,
},
},
{
label: '厂商名称',
field: 'mfrsName',
component: 'Input',
},
{
label: '联系电话',
field: 'mfrsMobile',
component: 'Input',
rules: rules.rule('phone', false),
},
{
label: '覆盖人数',
field: 'coverUserNum',
component: 'InputNumber',
},
{
label: '安装位置',
field: 'installAddress',
component: 'Input',
required: true,
slot: 'address',
},
{
label: '经度',
field: 'longitude',
required: true,
component: 'InputNumber',
},
{
label: '纬度',
field: 'latitude',
required: true,
component: 'InputNumber',
},
{
label: '位置照片',
field: 'installAddressImg',
component: 'JImageUpload',
componentProps: {
fileMax: 5,
},
},
];
/**
* 流程表单调用这个方法获取formSchema
* @param param
*/
export function getBpmFormSchema(_formData): FormSchema[] {
// 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
return formSchema;
}
@@ -0,0 +1,143 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable">
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
<!--字段回显插槽-->
<template #htmlSlot="{ text }">
<div v-html="text"></div>
</template>
</BasicTable>
<!-- 表单区域 -->
<LocationManageDrawer @register="registerDrawer" @success="handleSuccess" />
</div>
</template>
<script lang="ts" name="aed-locationManage" setup>
import { ref } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import LocationManageDrawer from './components/LocationManageDrawer.vue';
import { columns, searchFormSchema } from './LocationManage.data';
import { batchDelete, deleteOne, getExportUrl, getImportUrl, list } from './LocationManage.api';
import { message } from 'ant-design-vue';
import { useDrawer } from '/@/components/Drawer';
const checkedKeys = ref<Array<string | number>>([]);
//注册model
const [registerDrawer, { openDrawer }] = useDrawer();
//注册table数据
const { prefixCls, tableContext } = useListPage({
tableProps: {
title: '布点管理',
api: list,
columns,
canResize: false,
formConfig: {
//labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter: true,
showAdvancedButton: false,
fieldMapToNumber: [],
fieldMapToTime: [],
},
actionColumn: {
width: 110,
fixed: 'right',
},
beforeFetch: (info) => {
info['name'] = info?.name && `*${info.name}*`;
if (info.second !== undefined) {
info['departCode'] = `${info.second}*`;
}
if (info.three !== undefined) {
info['departCode'] = `${info.three}`;
}
info['hostSerialNum'] = info?.hostSerialNum && `*${info.hostSerialNum}*`;
info['aidrange'] = info?.aidrange && `*${info.aidrange}*`;
return info;
},
},
exportConfig: {
name: '应急资源',
url: getExportUrl,
},
importConfig: {
url: getImportUrl,
success: handleSuccess,
},
});
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
/**
* 新增事件
*/
function handleAdd() {
openDrawer(true, {
isUpdate: false,
showFooter: true,
title: '新增',
});
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
record.infoFlag = false;
record.warrantyDate = [record.warrantyStartDate, record.warrantyEndDate];
openDrawer(true, {
record,
isUpdate: true,
showFooter: true,
title: '编辑',
});
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
record.infoFlag = true;
record.warrantyDate = [record.warrantyStartDate, record.warrantyEndDate];
openDrawer(true, {
record,
isUpdate: true,
showFooter: false,
title: '详情',
});
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
auth: 'emergency:emergency_resource:edit',
},
{
label: '详情',
onClick: handleDetail.bind(null, record),
},
];
}
</script>
<style lang="less" scoped>
:deep(.ant-popover-buttons) {
display: flex !important;
}
</style>
@@ -0,0 +1,126 @@
<template>
<BasicDrawer :showFooter="showFooter" :title="title" :width="800" destroyOnClose v-bind="$attrs" @ok="handleSubmit" @register="registerModal">
<BasicForm @register="registerForm">
<template #address="{ model }">
<a-input v-model:value="model['installAddress']" placeholder="请输入安装位置或地图选点" :disabled="!showFooter" style="width: 82%" />
<a-button :disabled="!showFooter" style="margin-left: 10px" @click="viewMap"> 查看地图 </a-button>
</template>
</BasicForm>
<Map ref="map" :state="state" @register="registerMap" @get-position="getPosition" />
</BasicDrawer>
</template>
<script lang="ts" setup>
import { ref, unref } from 'vue';
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from '../LocationManage.data';
import { saveOrUpdate } from '../LocationManage.api';
import Map from '/@/views/consult/resource/components/Map.vue';
import { useModal } from '/@/components/Modal';
// Emits声明
const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true);
const showFooter = ref<boolean>(true);
const state = ref();
//设置标题
const title = ref<string>('');
//表单配置
const [registerForm, { setProps, resetFields, setFieldsValue, validate, getFieldsValue, clearValidate }] = useForm({
//labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { span: 24 },
});
const [registerMap, { openModal }] = useModal();
//表单赋值
const [registerModal, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
//重置表单
await resetFields();
setDrawerProps({
confirmLoading: false,
showCancelBtn: !!data?.showFooter,
showOkBtn: !!data?.showFooter,
});
isUpdate.value = !!data?.isUpdate;
showFooter.value = data.showFooter;
title.value = data.title;
let customAddress = '';
if (unref(isUpdate)) {
customAddress = `${data.record?.longitude}${data.record?.latitude}`;
//表单赋值
await setFieldsValue({
...data.record,
customAddress,
second: data.record?.departCode.slice(0, 6),
});
state.value = data.record;
} else {
state.value = {};
}
await clearValidate();
// 隐藏底部时禁用整个表单
await setProps({ disabled: !data?.showFooter });
});
function viewMap() {
openModal(true, {
record: { ...getFieldsValue() },
});
}
async function getPosition(val) {
let { pname, cityname, adname, address, name } = val.handleItem || '';
let nameList = [pname, cityname, adname, address, name];
let str = '';
nameList.map((item) => {
if (item !== undefined) {
str += item;
}
});
await setFieldsValue({
latitude: val.lat,
longitude: val.lng,
customAddress: `${val.lng}${val.lat}`,
installAddress: str,
});
state.value = {
...state.value,
latitude: val.lat,
longitude: val.lng,
};
}
//表单提交事件
async function handleSubmit() {
try {
let values = await validate();
setDrawerProps({ confirmLoading: true });
const params = {
...state.value,
...values,
};
console.log(values);
//提交表单
await saveOrUpdate(params, isUpdate.value);
//关闭弹窗
closeDrawer();
//刷新列表
emit('success');
} finally {
setDrawerProps({ confirmLoading: false });
}
}
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>
@@ -0,0 +1,154 @@
import { BasicColumn, FormSchema } from '/@/components/Table';
import { render } from '/@/utils/common/renderUtils';
import { RendererElement, RendererNode, VNode } from 'vue';
import { getSecondaryDepartmentList } from '/@/views/system/user/user.api';
import { BODY_CONTAINER } from '/@/utils/domUtils';
import { rules } from '/@/utils/helper/validator';
const renderStatusTag = (span: VNode<RendererNode, RendererElement, { [p: string]: any }>) => {
const text = span.children;
switch (text) {
case '正常':
return render.renderTag(text, '#31d731');
case '快过期':
case '需检查':
case '电量低':
return render.renderTag(text, '#f4e034');
case '已过期':
case '需更换':
case '未找到':
case '无连接':
return render.renderTag(text, '#f04141');
default:
return text;
}
};
//列表数据
export const columns: BasicColumn[] = [
{
title: '报告日期',
align: 'center',
dataIndex: 'createTime',
},
{
title: 'AED型号',
align: 'center',
dataIndex: 'aedModel',
},
{
title: 'AED序列号',
align: 'center',
dataIndex: 'aedNo',
},
{
title: '自检状态',
align: 'center',
dataIndex: 'aedStatus_dictText',
},
{
title: '电池状态',
align: 'center',
dataIndex: 'batteryPowerStatus_dictText',
},
{
title: '电极片状态',
align: 'center',
dataIndex: 'batteryPowerStatus_dictText',
},
{
title: '路由状态',
align: 'center',
dataIndex: 'routerVoltageStatus_dictText',
},
{
title: '电池电量',
align: 'center',
dataIndex: 'batteryPower',
},
{
title: '电压',
align: 'center',
dataIndex: 'routerVoltage',
},
{
title: '过期时间',
align: 'center',
dataIndex: 'padExpiration',
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
{
label: 'AED型号',
field: 'aedModel',
component: 'Input',
},
{
label: 'AED序列号',
field: 'aedNo',
component: 'Input',
},
{
label: '报告日期',
field: 'date',
component: 'RangePicker',
componentProps: {
valueFormat: 'YYYY-MM-DD',
},
},
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '专用路由器型号',
field: 'routerModel',
component: 'Input',
},
{
label: '专用路由器序列号',
field: 'routerSerialNo',
component: 'Input',
},
{
label: '物联卡号',
field: 'routerIccid',
component: 'Input',
},
{
label: '蓝牙自检结果',
field: 'routerBt',
component: 'Input',
},
{
label: '专用路由器通讯自检结果',
field: 'routerSelfModel',
component: 'Input',
},
{
label: '专用路由器文件系统自检结果',
field: 'routerFileSystem',
component: 'Input',
},
{
label: '专用路由器RTC自检结果',
field: 'routerSelfRtc',
component: 'Input',
},
{
label: '自检报告',
field: 'aedSelfReport',
component: 'InputTextArea',
},
];
/**
* 流程表单调用这个方法获取formSchema
* @param param
*/
export function getBpmFormSchema(_formData): FormSchema[] {
// 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
return formSchema;
}
@@ -0,0 +1,100 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable">
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
<!--字段回显插槽-->
<template #htmlSlot="{ text }">
<div v-html="text"></div>
</template>
</BasicTable>
<SelfRecordDrawer @register="registerDrawer" @success="handleSuccess" />
</div>
</template>
<script lang="ts" name="aed-selfRecord" setup>
import { ref } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import SelfRecordDrawer from './components/SelfRecordDrawer.vue';
import { columns, searchFormSchema } from './SelfRecord.data';
import { getExportUrl, getImportUrl, list } from './selfRecord.api';
import { useDrawer } from '/@/components/Drawer';
const checkedKeys = ref<Array<string | number>>([]);
//注册model
const [registerDrawer, { openDrawer }] = useDrawer();
//注册table数据
const { prefixCls, tableContext } = useListPage({
tableProps: {
title: '设备自检记录',
api: list,
columns,
canResize: false,
formConfig: {
//labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter: true,
showAdvancedButton: false,
fieldMapToNumber: [],
fieldMapToTime: [['date', ['timeStart', 'timeEnd'], 'YYYY-MM-DD']],
},
actionColumn: {
width: 90,
fixed: 'right',
},
},
exportConfig: {
name: '应急资源',
url: getExportUrl,
},
importConfig: {
url: getImportUrl,
success: handleSuccess,
},
});
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
/**
* 详情
*/
function handleDetail(record: Recordable) {
record.infoFlag = true;
record.warrantyDate = [record.warrantyStartDate, record.warrantyEndDate];
openDrawer(true, {
record,
isUpdate: true,
showFooter: false,
title: '详情',
});
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
},
];
}
</script>
<style lang="less" scoped>
:deep(.ant-popover-buttons) {
display: flex !important;
}
</style>
@@ -0,0 +1,125 @@
<template>
<BasicDrawer :showFooter="showFooter" :title="title" :width="800" destroyOnClose v-bind="$attrs" @ok="handleSubmit" @register="registerModal">
<BasicForm @register="registerForm">
<template #address="{ model }">
<a-input v-model:value="model['installAddress']" :disabled="!showFooter" style="width: 82%" />
<a-button :disabled="!showFooter" style="margin-left: 10px" @click="viewMap"> 查看地图 </a-button>
</template>
</BasicForm>
<Map ref="map" :state="state" @register="registerMap" @get-position="getPosition" />
</BasicDrawer>
</template>
<script lang="ts" setup>
import { ref, unref } from 'vue';
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from '../SelfRecord.data';
import { saveOrUpdate } from '../selfRecord.api';
import Map from '/@/views/consult/resource/components/Map.vue';
import { useModal } from '/@/components/Modal';
// Emits声明
const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true);
const showFooter = ref<boolean>(true);
const state = ref();
//设置标题
const title = ref<string>('');
//表单配置
const [registerForm, { setProps, resetFields, setFieldsValue, validate, getFieldsValue, clearValidate }] = useForm({
labelWidth: 180,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { span: 24 },
});
const [registerMap, { openModal }] = useModal();
//表单赋值
const [registerModal, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
//重置表单
await resetFields();
setDrawerProps({
confirmLoading: false,
showCancelBtn: !!data?.showFooter,
showOkBtn: !!data?.showFooter,
});
isUpdate.value = !!data?.isUpdate;
showFooter.value = data.showFooter;
title.value = data.title;
let customAddress = '';
if (unref(isUpdate)) {
customAddress = `${data.record?.longitude}${data.record?.latitude}`;
//表单赋值
await setFieldsValue({
...data.record,
customAddress,
});
state.value = data.record;
} else {
state.value = {};
}
await clearValidate();
// 隐藏底部时禁用整个表单
await setProps({ disabled: !data?.showFooter });
});
function viewMap() {
openModal(true, {
record: { ...getFieldsValue() },
});
}
async function getPosition(val) {
let { pname, cityname, adname, address, name } = val.handleItem || '';
let nameList = [pname, cityname, adname, address, name];
let str = '';
nameList.map((item) => {
if (item !== undefined) {
str += item;
}
});
await setFieldsValue({
latitude: val.lat,
longitude: val.lng,
customAddress: `${val.lng}${val.lat}`,
address: str,
});
state.value = {
...state.value,
latitude: val.lat,
longitude: val.lng,
};
}
//表单提交事件
async function handleSubmit() {
try {
let values = await validate();
setDrawerProps({ confirmLoading: true });
const params = {
...state.value,
...values,
};
console.log(values);
//提交表单
await saveOrUpdate(params, isUpdate.value);
//关闭弹窗
closeDrawer();
//刷新列表
emit('success');
} finally {
setDrawerProps({ confirmLoading: false });
}
}
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>
@@ -0,0 +1,78 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
enum Api {
list = '/health-emergency/emergency/aedLatest/list',
save = '/health-emergency/emergency/aed/add',
edit = '/health-emergency/emergency/aed/edit',
deleteOne = '/health-emergency/emergency/aed/delete',
deleteBatch = '/health-emergency/emergency/aed/deleteBatch',
importExcel = '/health-emergency/emergency/aed/importExcel',
exportXls = '/health-emergency/emergency/aed/exportXls',
queryById = '/health-emergency/emergency/aed/queryById',
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
export const queryByIdUrl = Api.queryById;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
* 删除单个
*/
export const deleteOne = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () =>
defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
}),
});
};
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true });
handleSuccess();
},
});
};
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
const url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
@@ -0,0 +1,16 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
enum Api {
list = '/health-emergency/emergency/aedWarnInfo/listCustom',
update = '/health-emergency/emergency/aedWarnInfo/updateHandleInfo',
}
/**
* 列表接口
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
export const saveOrUpdate = (params) => defHttp.get({ url: Api.update, params });
@@ -0,0 +1,109 @@
import { BasicColumn, FormSchema } from '/@/components/Table';
import { render } from '/@/utils/common/renderUtils';
import { RendererElement, RendererNode, VNode } from 'vue';
import { getSecondaryDepartmentList } from '/@/views/system/user/user.api';
import { BODY_CONTAINER } from '/@/utils/domUtils';
import { rules } from '/@/utils/helper/validator';
const renderStatusTag = (span: VNode<RendererNode, RendererElement, { [p: string]: any }>) => {
const text = span.children;
switch (text) {
case '正常':
return render.renderTag(text, '#31d731');
case '快过期':
case '需检查':
case '电量低':
return render.renderTag(text, '#f4e034');
case '已过期':
case '需更换':
case '未找到':
case '无连接':
return render.renderTag(text, '#f04141');
default:
return text;
}
};
//列表数据
export const columns: BasicColumn[] = [
{
title: '告警时间',
align: 'center',
dataIndex: 'createTime',
},
{
title: 'AED型号',
align: 'center',
dataIndex: 'aedModel',
},
{
title: 'AED编号',
align: 'center',
dataIndex: 'aedNo',
},
{
title: '告警类型',
align: 'center',
dataIndex: 'module',
customRender: ({ text }) => {
return renderStatusTag(render.renderDict(text, 'aed_module'));
},
},
{
title: '告警内容',
align: 'center',
dataIndex: 'type',
},
{
title: '告警值',
align: 'center',
dataIndex: 'value',
},
{
title: '处理状态',
align: 'center',
dataIndex: 'warnStatus_dictText',
},
{
title: '处理详情',
align: 'center',
dataIndex: 'warnHandleInfo',
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
{
label: '告警类型',
field: 'module',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'aed_module',
},
},
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '报警信息',
field: 'warnInfo',
component: 'InputTextArea',
required: true,
},
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
];
/**
* 流程表单调用这个方法获取formSchema
* @param param
*/
export function getBpmFormSchema(_formData): FormSchema[] {
// 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
return formSchema;
}
@@ -0,0 +1,89 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable">
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
<!--字段回显插槽-->
<template #htmlSlot="{ text }">
<div v-html="text"></div>
</template>
</BasicTable>
<WarnRecordDrawer @register="registerDrawer" @success="handleSuccess" />
</div>
</template>
<script lang="ts" name="aed-warn" setup>
import { ref } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import { columns, searchFormSchema } from './WarnRecord.data';
import { list } from './WarnRecord.api';
import WarnRecordDrawer from './components/WarnRecordDrawer.vue';;
import { useModal } from '/@/components/Modal';
const checkedKeys = ref<Array<string | number>>([]);
//注册model
const [registerDrawer, { openModal }] = useModal();
//注册table数据
const { prefixCls, tableContext } = useListPage({
tableProps: {
title: '告警管理',
api: list,
columns,
canResize: false,
formConfig: {
//labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter: true,
showAdvancedButton: false,
fieldMapToNumber: [],
fieldMapToTime: [],
},
actionColumn: {
width: 80,
fixed: 'right',
},
},
});
const [registerTable, { reload }, { selectedRowKeys }] = tableContext;
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
openModal(true, {
record,
title: record.warnStatus === '0' ? '处理' : '修改',
});
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: `${record.warnStatus === '0' ? '处理' : '修改'}`,
onClick: handleEdit.bind(null, record),
// auth: 'emergency:emergency_resource:edit',
},
];
}
</script>
<style lang="less" scoped>
:deep(.ant-popover-buttons) {
display: flex !important;
}
</style>
@@ -0,0 +1,60 @@
<template>
<BasicModal :showFooter="showFooter" :title="title" width="30%" destroyOnClose v-bind="$attrs" @ok="handleSubmit" @register="registerModal">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from '../WarnRecord.data';
import { saveOrUpdate } from '../WarnRecord.api';
// Emits声明
const emit = defineEmits(['register', 'success']);
const showFooter = ref<boolean>(true);
//设置标题
const title = ref<string>('');
//表单配置
const [registerForm, { validate, setFieldsValue }] = useForm({
//labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { span: 24 },
});
//表单赋值
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
title.value = data.title;
await setFieldsValue({
...data.record,
});
});
//表单提交事件
async function handleSubmit() {
try {
let values = await validate();
setModalProps({ confirmLoading: true });
//提交表单
await saveOrUpdate(values);
//关闭弹窗
closeModal();
//刷新列表
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>
@@ -0,0 +1,14 @@
import { defHttp } from '/@/utils/http/axios';
enum Api {
list = '/health-archives/housenew/fakerData/getFakerData',
save = '/health-archives/housenew/fakerData/createServiceFakerData,' +
'/health-archives/housenew/fakerData/createMedicalFakerData,' +
'/health-archives/housenew/fakerData/createBigIllFakerData', // 查询: 1: 服务详情数据 2:体检数据 3:大病人数
status = '/health-archives/housenew/fakerData/getFakerDataEnable',
changeStatus = '/health-archives/housenew/fakerData/fakerDataEnable',
}
export const listApi = (params: any) => defHttp.post({ url: Api.list, params }, { joinParamsToUrl: true, isTransformResponse: false });
export const saveApi = (params: any) => defHttp.post({ url: Api.save.split(',')[params['module'] - 6], params });
export const statusApi = (params: any) => defHttp.post({ url: Api.status, params });
export const changeStatusApi = (params: any) => defHttp.post({ url: Api.changeStatus, params });
@@ -0,0 +1,141 @@
import { BasicColumn } from '/@/components/Table';
const serviceColumns: BasicColumn[] = [
{
title: '最新呼入电话',
dataIndex: 'latestCall',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '最新受理电话',
dataIndex: 'latestAcceptCall',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '突发重大伤病应急',
dataIndex: 'illNum',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '重大伤病应急就医',
dataIndex: 'emergencyNum',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '累计受理',
dataIndex: 'totalAccept',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '累计处置',
dataIndex: 'totalDisposal',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '状态',
dataIndex: 'status',
},
];
const archiveColumns: BasicColumn[] = [
{
title: '兴隆医院',
dataIndex: 'xl',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '高陵医院',
dataIndex: 'jh',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '宁夏宝石花医院',
dataIndex: 'nx',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '庆阳医院',
dataIndex: 'qy',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '延安市人民医院',
dataIndex: 'ya',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '西京医院',
dataIndex: 'xj',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '状态',
dataIndex: 'status',
},
];
const bigColumns: BasicColumn[] = [
{
title: '高',
dataIndex: 'highRisk',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '中',
dataIndex: 'centerRisk',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '低',
dataIndex: 'lowRisk',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '状态',
dataIndex: 'status',
},
];
export const columns: Array<BasicColumn[]> = [serviceColumns, archiveColumns, bigColumns];
+155
View File
@@ -0,0 +1,155 @@
<template>
<div style="padding: 10px">
<BasicTable @register="registerTable">
<template #tableTitle>
<div style="width: 100%">
<div>
<a-tabs v-model:activeKey="activeKey" @change="handleChange" style="padding-left: 5px">
<a-tab-pane v-for="item in tabList" :key="item.id" :tab="item.name" />
</a-tabs>
</div>
<div>
<a-button type="primary" @click="changeCalculateStatus" :loading="saveLoading">{{ isCalculate ? `保存` : `录入` }}</a-button>
<a-button style="margin-left: 5px" v-if="isCalculate" @click="changeCalculateStatusFalse">取消</a-button>
</div>
</div>
</template>
<template v-if="isCalculate" #bodyCell="{ column, record }">
<div v-if="column?.rewriting">
<a-input-number v-model:value="record[column.dataIndex]" />
</div>
<div v-if="column.dataIndex == 'status'">
<a-switch
v-model:checked="checked1"
checked-children=""
un-checked-children=""
@change="changeSwitch"
:loading="switchLoading"
/>
</div>
</template>
<template v-else #bodyCell="{ column, record }">
<div v-if="column.dataIndex == 'status'">
<a-switch
v-model:checked="checked1"
checked-children=""
un-checked-children=""
@change="changeSwitch"
:loading="switchLoading"
/>
</div>
</template>
</BasicTable>
</div>
</template>
<script setup lang="ts">
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import { onMounted, ref } from 'vue';
import { listApi, saveApi, statusApi, changeStatusApi } from '/@/views/emergency/bigScreen/currency.api';
import { columns } from '/@/views/emergency/bigScreen/currency.data';
import { message } from 'ant-design-vue';
const activeKey = ref(6);
const checked1 = ref(false);
const isCalculate = ref(false);
const saveLoading = ref(false);
const switchLoading = ref(false);
const tabList = ref([
{
id: 6,
name: '服务详情数据',
},
{
id: 7,
name: '体检数据',
},
{
id: 8,
name: '大病人数',
},
]);
const { tableContext } = useListPage({
tableProps: {
api: listApi,
// columns: props.columns,
beforeFetch: (params) => {
const redisKey = ['house:fakerData:groupUser'];
params['module'] = activeKey.value;
params['redisKey'] = redisKey[activeKey.value - 6];
return params;
},
afterFetch: async () => {
let { code, result, message: msg } = getRawDataSource();
const res = await statusApi({});
checked1.value = res[activeKey.value] ? res[activeKey.value] : false;
if (code == 200) {
return [result];
} else {
message.warn(msg);
}
},
showTableSetting: false,
tableSetting: {
setting: false,
},
pagination: false,
canResize: false,
immediate: false,
useSearchForm: false,
showActionColumn: false,
},
});
async function changeCalculateStatus() {
if (!isCalculate.value) return (isCalculate.value = true);
try {
saveLoading.value = true;
switchLoading.value = false;
await saveApi({ ...getDataSource()[0], module: activeKey.value });
saveLoading.value = false;
await reload();
} catch (e) {
saveLoading.value = false;
switchLoading.value = false;
}
}
function changeCalculateStatusFalse() {
isCalculate.value = false;
saveLoading.value = false;
switchLoading.value = false;
reload();
}
async function changeSwitch() {
try {
switchLoading.value = true;
checked1.value = !checked1.value;
await changeStatusApi({ module: activeKey.value, enable: !checked1.value });
checked1.value = !checked1.value;
switchLoading.value = false;
} catch (e) {
switchLoading.value = false;
}
}
function handleChange() {
saveLoading.value = false;
switchLoading.value = false;
isCalculate.value = false;
setProps({
columns: columns[activeKey.value - 6],
});
reload();
}
onMounted(() => {
setProps({
columns: columns[activeKey.value - 6],
});
reload();
});
const [registerTable, { reload, setProps, getRawDataSource, getDataSource }, {}] = tableContext;
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,16 @@
import { defHttp } from '/@/utils/http/axios';
enum Api {
list = '/health-archives/housenew/fakerData/getFakerData',
save = '/health-archives/housenew/fakerData/createYcServiceFakerData,' +
'/health-archives/housenew/fakerData/createYcMedicalFakerData,' +
'/health-archives/housenew/fakerData/createYcMedicalCenterFakerData,' +
'/health-archives/housenew/fakerData/createYcUserHealthFakerData', // 查询: 9:银川服务 10:银川医院 11:银川一线医疗点 12:银川员工健康
status = '/health-archives/housenew/fakerData/getFakerDataEnable',
changeStatus = '/health-archives/housenew/fakerData/fakerDataEnable',
}
export const listApi = (params: any) => defHttp.post({ url: Api.list, params }, { joinParamsToUrl: true, isTransformResponse: false });
export const saveApi = (params: any) => defHttp.post({ url: Api.save.split(',')[params['module'] - 9], params });
export const saveElApi = (params: any, id: string) => defHttp.post({ url: Api.save.split(',')[2] + '?centerId=' + id, params });
export const statusApi = (params: any, id: string) => defHttp.post({ url: Api.status + '?centerId=' + id, params });
export const changeStatusApi = (params: any) => defHttp.post({ url: Api.changeStatus, params });
@@ -0,0 +1,203 @@
import { BasicColumn } from '/@/components/Table';
const serviceColumns: BasicColumn[] = [
{
title: '最新呼入电话',
dataIndex: 'latestCall',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '最新受理电话',
dataIndex: 'latestAcceptCall',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '突发重大伤病应急',
dataIndex: 'illNum',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '重大伤病应急就医',
dataIndex: 'emergencyNum',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
// {
// title: '累计受理',
// dataIndex: 'totalAccept',
// rewriting: true,
// rewroteCell: {
// type: 'inputNumber',
// },
// },
// {
// title: '累计处置',
// dataIndex: 'totalDisposal',
// rewriting: true,
// rewroteCell: {
// type: 'inputNumber',
// },
// },
{
title: '状态',
dataIndex: 'status',
},
];
const archiveColumns: BasicColumn[] = [
{
title: '兴隆医院',
dataIndex: 'xl',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '泾河医院',
dataIndex: 'jh',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '宁夏宝石花医院',
dataIndex: 'nx',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '庆阳医院',
dataIndex: 'qy',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '延安市人民医院',
dataIndex: 'ya',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '西京医院',
dataIndex: 'xj',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '状态',
dataIndex: 'status',
},
];
const bigColumns: BasicColumn[] = [
{
title: '医疗点名称',
dataIndex: 'name',
rewriting: true,
rewroteCell: {
type: 'input',
},
},
{
title: '高风险干预',
dataIndex: 'high',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '慢病',
dataIndex: 'slow',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '巡诊',
dataIndex: 'tour',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '排序',
dataIndex: 'order',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '删除',
dataIndex: 'del',
},
];
const healthColumns: BasicColumn[] = [
{
title: '重大疾病',
dataIndex: 'bigIll',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '健康高风险',
dataIndex: 'highRisk',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '慢病人数',
dataIndex: 'slowIll',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '重点指标异常',
dataIndex: 'focusErr',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '健康人数',
dataIndex: 'health',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '状态',
dataIndex: 'status',
},
];
export const columns: Array<BasicColumn[]> = [serviceColumns, archiveColumns, bigColumns, healthColumns];
@@ -0,0 +1,259 @@
<template>
<div style="padding: 10px">
<div style="display: flex; justify-content: flex-end; align-items: center; padding: 5px 0">
<span> 应急分中心 </span>
<ApiSelect
style="width: 300px"
:value="centerId"
:api="allCenterApi"
:after-fetch="
(data) => {
if (data && data.length > 0) {
centerId = data[0].id;
}
}
"
:showDefaultValue="false"
@change="changeCenter"
resultField="result"
labelField="centerName"
valueField="id"
:immediate="true"
/>
</div>
<BasicTable @register="registerTable">
<template #tableTitle>
<div style="width: 100%">
<div>
<a-tabs v-model:activeKey="activeKey" @change="handleChange" style="padding-left: 5px">
<a-tab-pane v-for="item in tabList" :key="item.id" :tab="item.name" />
</a-tabs>
</div>
<div>
<a-button type="primary" @click="changeCalculateStatus" :loading="saveLoading">{{ isCalculate ? `保存` : `录入` }}</a-button>
<a-button style="margin-left: 5px" v-if="isCalculate" @click="changeCalculateStatusFalse">取消</a-button>
<a-button style="margin-left: 5px" type="primary" @click="addListItem" v-if="isCalculate && activeKey == 11">添加</a-button>
<span style="margin-left: 5px" v-if="activeKey == 11">
状态:
<a-switch
v-model:checked="checked1"
checked-children=""
un-checked-children=""
@change="changeSwitch"
:loading="switchLoading"
/>
</span>
</div>
</div>
</template>
<template v-if="isCalculate" #bodyCell="{ column, record, index }">
<div v-if="column?.rewriting">
<a-input-number v-if="column?.rewroteCell.type === 'inputNumber'" v-model:value="record[column.dataIndex]" />
<a-input v-if="column?.rewroteCell.type === 'input'" v-model:value="record[column.dataIndex]" />
</div>
<div v-if="column.dataIndex == 'status'">
<a-switch
v-model:checked="checked1"
checked-children=""
un-checked-children=""
@change="changeSwitch"
:loading="switchLoading"
/>
</div>
<div v-if="column.dataIndex == 'del'">
<a-button type="text" style="color: #1890ff" @click="delData(index)">删除</a-button>
</div>
</template>
<template v-else #bodyCell="{ column }">
<div v-if="column.dataIndex == 'status'">
<a-switch
v-model:checked="checked1"
checked-children=""
un-checked-children=""
@change="changeSwitch"
:loading="switchLoading"
/>
</div>
<div v-if="column.dataIndex == 'del'">
<a-button type="text" style="color: #1890ff" :disabled="!isCalculate">删除</a-button>
</div>
</template>
</BasicTable>
</div>
</template>
<script setup lang="ts">
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import { onMounted, ref, watch } from 'vue';
import { listApi, saveApi, statusApi, changeStatusApi, saveElApi } from '/@/views/emergency/bigScreenOther/currencyOther.api';
import { columns } from '/@/views/emergency/bigScreenOther/currencyOther.data';
import { message } from 'ant-design-vue';
import { allCenterApi } from '/@/views/emergency/scheduling/scheduling.api';
import ApiSelect from '/@/components/Form/src/components/ApiSelect.vue';
const centerId = ref('');
const activeKey = ref(9);
const checked1 = ref(false);
const isCalculate = ref(false);
const saveLoading = ref(false);
const switchLoading = ref(false);
watch(
() => centerId.value,
(v) => {
if (v) {
reload();
}
}
);
function changeCenter(v) {
if (v) {
centerId.value = v;
}
}
const tabList = ref([
{
id: 9,
name: '服务详情',
},
{
id: 10,
name: '体检数据',
},
{
id: 11,
name: '一线医疗点数据',
},
{
id: 12,
name: '员工健康状况',
},
]);
const { tableContext } = useListPage({
tableProps: {
api: listApi,
// columns: props.columns,
beforeFetch: (params) => {
const redisKey = ['house:fakerData:groupUser'];
params['module'] = activeKey.value;
params['redisKey'] = redisKey[activeKey.value - 9];
params['centerId'] = centerId.value;
return params;
},
afterFetch: async () => {
let { code, result, message: msg } = getRawDataSource();
const res = await statusApi({ centerId: centerId.value }, centerId.value);
checked1.value = res[activeKey.value] ? res[activeKey.value] : false;
if (code == 200) {
return activeKey.value == 11 ? result : [result];
} else {
message.warn(msg);
}
},
tableSetting: {
redo: true,
setting: false,
},
pagination: false,
canResize: false,
immediate: false,
useSearchForm: false,
showActionColumn: false,
showIndexColumn: true,
},
});
function addListItem() {
let data = JSON.parse(JSON.stringify(getDataSource()));
data.push({});
setTableData(data);
}
function delData(index: number) {
let data = JSON.parse(JSON.stringify(getDataSource()));
data.splice(index, 1);
setTableData(data);
}
async function changeCalculateStatus() {
if (!centerId.value) return message.info('请先选择应急分中心');
if (!isCalculate.value) return (isCalculate.value = true);
try {
if (activeKey.value == 11) {
let d = getDataSource();
for (let i = 0; i < d.length; i++) {
if (!d[i].name) {
return message.info(`第${i + 1}条的医疗点名称不能为空`);
}
if (!d[i].high) {
return message.info(`第${i + 1}条的高风险干预不能为空`);
}
if (!d[i].slow) {
return message.info(`第${i + 1}条的慢病不能为空`);
}
if (!d[i].tour) {
return message.info(`第${i + 1}条的巡诊不能为空`);
}
if (!d[i].order) {
return message.info(`第${i + 1}条的排序不能为空`);
}
d[i]['centerId'] = centerId.value;
}
saveLoading.value = true;
switchLoading.value = false;
await saveElApi(d, centerId.value);
} else {
saveLoading.value = true;
switchLoading.value = false;
await saveApi({
...(activeKey.value == 9 ? { ...getDataSource()[0], totalAccept: 0, totalDisposal: 0 } : getDataSource()[0]),
module: activeKey.value,
centerId: centerId.value,
});
}
saveLoading.value = false;
await reload();
} catch (e) {
saveLoading.value = false;
switchLoading.value = false;
}
}
function changeCalculateStatusFalse() {
isCalculate.value = false;
saveLoading.value = false;
switchLoading.value = false;
reload();
}
async function changeSwitch() {
try {
switchLoading.value = true;
checked1.value = !checked1.value;
await changeStatusApi({ module: activeKey.value, enable: !checked1.value, centerId: centerId.value });
checked1.value = !checked1.value;
switchLoading.value = false;
} catch (e) {
switchLoading.value = false;
}
}
function handleChange() {
saveLoading.value = false;
switchLoading.value = false;
isCalculate.value = false;
setProps({
columns: columns[activeKey.value - 9],
});
if (centerId.value) {
reload();
}
}
onMounted(() => {
setProps({
columns: columns[activeKey.value - 9],
});
});
const [registerTable, { reload, setProps, getRawDataSource, getDataSource, setTableData }, {}] = tableContext;
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,16 @@
import { defHttp } from '/@/utils/http/axios';
enum Api {
list = '/health-archives/housenew/fakerData/getFakerData',
save = '/health-archives/housenew/fakerData/createYcServiceFakerData,' +
'/health-archives/housenew/fakerData/createYcMedicalFakerData,' +
'/health-archives/housenew/fakerData/createYcMedicalCenterFakerData,' +
'/health-archives/housenew/fakerData/createYcUserHealthFakerData', // 查询: 9:银川服务 10:银川医院 11:银川一线医疗点 12:银川员工健康
status = '/health-archives/housenew/fakerData/getFakerDataEnable',
changeStatus = '/health-archives/housenew/fakerData/fakerDataEnable',
}
export const listApi = (params: any) => defHttp.post({ url: Api.list, params }, { joinParamsToUrl: true, isTransformResponse: false });
export const saveApi = (params: any) => defHttp.post({ url: Api.save.split(',')[params['module'] - 9], params });
export const saveElApi = (params: any) => defHttp.post({ url: Api.save.split(',')[2], params });
export const statusApi = (params: any) => defHttp.post({ url: Api.status, params });
export const changeStatusApi = (params: any) => defHttp.post({ url: Api.changeStatus, params });
@@ -0,0 +1,211 @@
import { BasicColumn } from '/@/components/Table';
const serviceColumns: BasicColumn[] = [
{
title: '最新呼入电话',
dataIndex: 'latestCall',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '最新受理电话',
dataIndex: 'latestAcceptCall',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '突发重大伤病应急',
dataIndex: 'illNum',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '重大伤病应急就医',
dataIndex: 'emergencyNum',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
// {
// title: '累计受理',
// dataIndex: 'totalAccept',
// rewriting: true,
// rewroteCell: {
// type: 'inputNumber',
// },
// },
// {
// title: '累计处置',
// dataIndex: 'totalDisposal',
// rewriting: true,
// rewroteCell: {
// type: 'inputNumber',
// },
// },
{
title: '状态',
dataIndex: 'status',
},
];
const archiveColumns: BasicColumn[] = [
{
title: '兴隆医院',
dataIndex: 'xl',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '泾河医院',
dataIndex: 'jh',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '宁夏宝石花医院',
dataIndex: 'nx',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '庆阳医院',
dataIndex: 'qy',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '延安市人民医院',
dataIndex: 'ya',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '西京医院',
dataIndex: 'xj',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '状态',
dataIndex: 'status',
},
];
const bigColumns: BasicColumn[] = [
{
title: '医疗点名称',
dataIndex: 'name',
rewriting: true,
rewroteCell: {
type: 'input',
},
},
{
title: '高风险干预',
dataIndex: 'high',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '慢病',
dataIndex: 'slow',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '巡诊',
dataIndex: 'tour',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '排序',
dataIndex: 'order',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '删除',
dataIndex: 'del',
},
];
const healthColumns: BasicColumn[] = [
{
title: '重大疾病',
dataIndex: 'bigIll',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '健康高风险',
dataIndex: 'highRisk',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '慢病人数',
dataIndex: 'slowIll',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '重点指标异常',
dataIndex: 'focusErr',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '健康人数',
dataIndex: 'health',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '慢病人数',
dataIndex: 'slowIll',
rewriting: true,
rewroteCell: {
type: 'inputNumber',
},
},
{
title: '状态',
dataIndex: 'status',
},
];
export const columns: Array<BasicColumn[]> = [serviceColumns, archiveColumns, bigColumns, healthColumns];
@@ -0,0 +1,214 @@
<template>
<div style="padding: 10px">
<BasicTable @register="registerTable">
<template #tableTitle>
<div style="width: 100%">
<div>
<a-tabs v-model:activeKey="activeKey" @change="handleChange" style="padding-left: 5px">
<a-tab-pane v-for="item in tabList" :key="item.id" :tab="item.name" />
</a-tabs>
</div>
<div>
<a-button type="primary" @click="changeCalculateStatus" :loading="saveLoading">{{ isCalculate ? `保存` : `录入` }}</a-button>
<a-button style="margin-left: 5px" v-if="isCalculate" @click="changeCalculateStatusFalse">取消</a-button>
<a-button style="margin-left: 5px" type="primary" @click="addListItem" v-if="isCalculate && activeKey == 11">添加</a-button>
<span style="margin-left: 5px" v-if="activeKey == 11">
状态
<a-switch
v-model:checked="checked1"
checked-children=""
un-checked-children=""
@change="changeSwitch"
:loading="switchLoading"
/>
</span>
</div>
</div>
</template>
<template v-if="isCalculate" #bodyCell="{ column, record, index }">
<div v-if="column?.rewriting">
<a-input-number v-if="column?.rewroteCell.type === 'inputNumber'" v-model:value="record[column.dataIndex]" />
<a-input v-if="column?.rewroteCell.type === 'input'" v-model:value="record[column.dataIndex]" />
</div>
<div v-if="column.dataIndex == 'status'">
<a-switch
v-model:checked="checked1"
checked-children=""
un-checked-children=""
@change="changeSwitch"
:loading="switchLoading"
/>
</div>
<div v-if="column.dataIndex == 'del'">
<a-button type="text" style="color: #1890ff" @click="delData(index)">删除</a-button>
</div>
</template>
<template v-else #bodyCell="{ column }">
<div v-if="column.dataIndex == 'status'">
<a-switch
v-model:checked="checked1"
checked-children=""
un-checked-children=""
@change="changeSwitch"
:loading="switchLoading"
/>
</div>
<div v-if="column.dataIndex == 'del'">
<a-button type="text" style="color: #1890ff" :disabled="!isCalculate">删除</a-button>
</div>
</template>
</BasicTable>
</div>
</template>
<script setup lang="ts">
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import { onMounted, ref } from 'vue';
import { listApi, saveApi, statusApi, changeStatusApi, saveElApi } from '/@/views/emergency/bigScreenY/currency.api';
import { columns } from '/@/views/emergency/bigScreenY/currency.data';
import { message } from 'ant-design-vue';
const activeKey = ref(9);
const checked1 = ref(false);
const isCalculate = ref(false);
const saveLoading = ref(false);
const switchLoading = ref(false);
const tabList = ref([
{
id: 9,
name: '服务详情',
},
{
id: 10,
name: '体检数据',
},
{
id: 11,
name: '一线医疗点数据',
},
{
id: 12,
name: '银川员工健康状况',
},
]);
const { tableContext } = useListPage({
tableProps: {
api: listApi,
// columns: props.columns,
beforeFetch: (params) => {
const redisKey = ['house:fakerData:groupUser'];
params['module'] = activeKey.value;
params['redisKey'] = redisKey[activeKey.value - 9];
return params;
},
afterFetch: async () => {
let { code, result, message: msg } = getRawDataSource();
const res = await statusApi({});
checked1.value = res[activeKey.value] ? res[activeKey.value] : false;
if (code == 200) {
return activeKey.value == 11 ? result : [result];
} else {
message.warn(msg);
}
},
showTableSetting: false,
tableSetting: {
setting: false,
},
pagination: false,
canResize: false,
immediate: false,
useSearchForm: false,
showActionColumn: false,
showIndexColumn: true,
},
});
function addListItem() {
let data = JSON.parse(JSON.stringify(getDataSource()));
data.push({});
setTableData(data);
}
function delData(index: number) {
let data = JSON.parse(JSON.stringify(getDataSource()));
data.splice(index, 1);
setTableData(data);
}
async function changeCalculateStatus() {
if (!isCalculate.value) return (isCalculate.value = true);
try {
if (activeKey.value == 11) {
let d = getDataSource();
for (let i = 0; i < d.length; i++) {
if (!d[i].name) {
return message.info(`${i + 1}条的医疗点名称不能为空`);
}
if (!d[i].high) {
return message.info(`${i + 1}条的高风险干预不能为空`);
}
if (!d[i].slow) {
return message.info(`${i + 1}条的慢病不能为空`);
}
if (!d[i].tour) {
return message.info(`${i + 1}条的巡诊不能为空`);
}
if (!d[i].order) {
return message.info(`${i + 1}条的排序不能为空`);
}
}
saveLoading.value = true;
switchLoading.value = false;
await saveElApi(d);
} else {
saveLoading.value = true;
switchLoading.value = false;
await saveApi({ ...getDataSource()[0], module: activeKey.value });
}
saveLoading.value = false;
await reload();
} catch (e) {
saveLoading.value = false;
switchLoading.value = false;
}
}
function changeCalculateStatusFalse() {
isCalculate.value = false;
saveLoading.value = false;
switchLoading.value = false;
reload();
}
async function changeSwitch() {
try {
switchLoading.value = true;
checked1.value = !checked1.value;
await changeStatusApi({ module: activeKey.value, enable: !checked1.value });
checked1.value = !checked1.value;
switchLoading.value = false;
} catch (e) {
switchLoading.value = false;
}
}
function handleChange() {
saveLoading.value = false;
switchLoading.value = false;
isCalculate.value = false;
setProps({
columns: columns[activeKey.value - 9],
});
reload();
}
onMounted(() => {
setProps({
columns: columns[activeKey.value - 9],
});
reload();
});
const [registerTable, { reload, setProps, getRawDataSource, getDataSource, setTableData }, {}] = tableContext;
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,124 @@
<template>
<a-drawer
v-model:visible="visible"
class="custom-class"
style="color: red; overflow: auto"
title="地图"
width="50%"
placement="right"
@afterVisibleChange="afterVisibleChange"
@close="closeDrawer"
:headerStyle="{ display: 'none' }"
>
<div id="container1" style="height: 100%"></div>
</a-drawer>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import AMapLoader from '@amap/amap-jsapi-loader';
import { mapKey } from '/@/utils/baiduMaopKey';
let BasicMap = null;
const visible = ref<Boolean>();
const emit = defineEmits(['closeDrawerOpenUp']);
const props = defineProps({
lon: {
type: Number,
default: () => 108.947061,
},
lat: {
type: Number,
default: () => 34.259479,
},
});
// const initMap = () => {
// let lat = props.lat;
// let lon = props.lon;
// AMapLoader.load({
// key: mapKey, // 申请好的Web端开发者Key,首次调用 load 时必填
// version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
// plugins: [''], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
// })
// .then((AMap) => {
// aMap.value = AMap;
// console.log('lon, lat===============================');
// console.log(lon, lat);
// //设置地图容器id
// map = new AMap.Map('container', {
// viewMode: '3D', //是否为3D地图模式
// zoom: 12, //初始化地图级别
// center: [108.947061, 34.259479], //初始化地图中心点位置
// resizeEnable: true,
// });
// //
// // const marker = new AMap.Marker({
// // icon: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png',
// // position: [lon, lat],
// // });
// //
// // marker.setMap(map);
// })
// .catch((e) => {
// console.log(e);
// });
// };
function initMap() {
AMapLoader.load({
key: mapKey, // 申请好的Web端开发者Key,首次调用 load 时必填
version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: [''], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
})
.then((AMap) => {
//设置地图容器id
BasicMap = new AMap.Map('container1', {
viewMode: '3D', //是否为3D地图模式
zoom: 12, //初始化地图级别
center: [props.lon, props.lat], //初始化地图中心点位置
resizeEnable: true,
});
console.log(BasicMap);
const marker = new AMap.Marker({
icon: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-red.png',
position: [props.lon, props.lat],
});
console.log(marker);
marker.setMap(BasicMap);
})
.catch((e) => {
console.log(e);
});
}
const showDrawer = () => {
visible.value = true;
};
function afterVisibleChange(flag) {
flag && initMap();
}
onMounted(() => {});
const closeDrawer = () => {
emit('closeDrawerOpenUp');
};
defineExpose({
initMap,
showDrawer,
closeDrawer,
});
</script>
<style scoped lang="less">
#container {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
:deep(.amap-icon) {
width: 15px;
height: 20px;
img {
width: 15px;
height: 20px;
}
}
</style>
@@ -0,0 +1,21 @@
export const information = [
{ labelName: '员工信息', key: 'person', person: '张三-男-22' },
{ labelName: '所属单位', key: 'local', local: '第一油厂', lat: '34.259479', lon: '108.947061' },
{ labelName: '手机号', key: 'phone', phone: '13333333333' },
{ labelName: '身份证号', key: 'idCard', idCard: '123456789012345678' },
];
export const booking = [
{ labelName: '挂号类型', key: 'type', type: '专家号' },
{ labelName: '预约医院', key: 'hospital', hospital: '第一油厂' },
{ labelName: '预约医生', key: 'doctor', doctor: '13333333333' },
{ labelName: '预约科室', key: 'dep', dep: '123456789012345678' },
{ labelName: '就诊卡号', key: 'card', card: '123456789012345678' },
{ labelName: '预约时间', key: 'time', time: '123456789012345678' },
{ labelName: '病情描述', key: 'desc', desc: '123456789012345678', spanNumber: 2 },
];
export const bookingInformation = [
{ labelName: '预约单状态', key: 'status', status: '待派单' },
{ labelName: '创建时间', key: 'createTime', createTime: '2020-11-12' },
{ labelName: '预约单号', key: 'card', card: 'yy82371' },
];
@@ -0,0 +1,209 @@
<template>
<a-drawer v-model:visible="visible" class="custom-class" style="color: red; overflow: auto" title="大病就医预约单" width="50%" placement="right">
<a-descriptions title="员工信息" :column="2">
<a-descriptions-item label="员工信息">
{{ filterEmployInfo() }}
</a-descriptions-item>
<a-descriptions-item label="所属单位">
{{ informationData.userDepart }}
<span @click="getLocal(item.lon, item.lat)">
位置
<svg
t="1684981639908"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2394"
width="10"
height="10"
>
<path
d="M753.536 663.552a337.066667 337.066667 0 0 0 0-478.805333c-133.333333-132.565333-349.738667-132.565333-483.072 0a337.066667 337.066667 0 0 0 0 478.805333L512 903.68l241.536-240.128zM210.304 724.096a422.4 422.4 0 0 1 0-599.893333C376.917333-41.386667 647.082667-41.386667 813.653333 124.245333a422.4 422.4 0 0 1 0 599.893334L512 1024l-301.696-299.946667zM512 512a85.333333 85.333333 0 1 0 0-170.666667 85.333333 85.333333 0 0 0 0 170.666667z m0 85.333333a170.666667 170.666667 0 1 1 0-341.333333 170.666667 170.666667 0 0 1 0 341.333333z"
fill="#f2f2f2"
p-id="2395"
data-spm-anchor-id="a313x.7781069.0.i0"
class="selected"
/>
</svg>
</span>
</a-descriptions-item>
<a-descriptions-item label="手机号">
{{ informationData.telPhone }}
</a-descriptions-item>
<a-descriptions-item label="身份证号">
{{ informationData.idNo }}
</a-descriptions-item>
</a-descriptions>
<a-descriptions title="工单信息" :column="2">
<a-descriptions-item label="挂号类型">
{{ filterAll(informationData.registerCategory, 'category') }}
</a-descriptions-item>
<a-descriptions-item label="预约医院">
{{ informationData.hospitalName }}
</a-descriptions-item>
<a-descriptions-item label="预约医生">
{{ informationData.reservationDoctor }}
</a-descriptions-item>
<a-descriptions-item label="预约科室">
{{ informationData.reservationOffice }}
</a-descriptions-item>
<a-descriptions-item label="就诊卡号">
{{ informationData.medicalCardNo }}
</a-descriptions-item>
<a-descriptions-item label="预约时间">
{{ informationData.reservationTime }}
</a-descriptions-item>
<a-descriptions-item label="病情描述" :span="2">
{{ informationData.diseaseDescribe }}
</a-descriptions-item>
</a-descriptions>
<a-descriptions title="预约单信息" :column="2">
<a-descriptions-item label="预约单状态">
{{ filterState(informationData.satte) }}
</a-descriptions-item>
<a-descriptions-item label="创建时间">
{{ informationData.createTime }}
</a-descriptions-item>
<a-descriptions-item label="预约单号">
{{ informationData.reservationNo }}
</a-descriptions-item>
</a-descriptions>
<a-row class="bottom-button">
<a-button @click="backUp">驳回</a-button>
<a-button type="primary" @click="onSiteB">派单驻场</a-button>
</a-row>
<a-modal :visible="visibleEnd" title="驳回意见" :footer="null">
<div style="padding: 10px 20px">
<a-textarea v-model:value="rejectionReason" placeholder="" :rows="5" />
</div>
<div style="display: flex; justify-content: center; padding: 10px 0">
<a-button @click="cancelReason" style="margin-right: 10px">取消</a-button>
<a-button type="primary" @click="saveB" style="margin-left: 10px">确定</a-button>
</div>
</a-modal>
<onSite :userType="'1'" ref="onSiteRef" />
<aMapDrawer :lat="lat" :lon="lon" ref="aMapDrawerRef" @close-drawer-open-up="closeAmapDrawer" />
</a-drawer>
</template>
<script setup lang="ts">
import { message } from 'ant-design-vue';
import { queryByIdApi, operatorRejectApi } from '/@/views/emergency/communication/components/commApi';
import onSite from './onSite.vue';
import aMapDrawer from './aMapDrawer.vue';
import { ref } from 'vue';
import { render } from '/@/utils/common/renderUtils';
const visible = ref<Boolean>(false);
const visibleEnd = ref<Boolean>(false);
const pId = ref<String>(''); // 父ID
const rejectionReason = ref<String>();
const onSiteRef = ref();
const aMapDrawerRef = ref();
const lon = ref<Number>();
const lat = ref<Number>();
const informationData = ref();
const showDrawer = (id) => {
pId.value = id;
initData();
visible.value = true;
};
const getLocal = (la, lo) => {
lon.value = la;
lat.value = lo;
message.info('经度是' + lo + '纬度是' + la);
visible.value = false;
setTimeout(() => {
aMapDrawerRef.value.showDrawer();
}, 500);
};
const backUp = () => {
visibleEnd.value = true;
};
const cancelReason = () => {
rejectionReason.value = '';
visibleEnd.value = false;
};
const saveB = () => {
const params = {
id: pId.value,
rejectionReason: rejectionReason.value,
};
operatorRejectApi(params)
.then((res) => {
console.log(res);
rejectionReason.value = '';
visibleEnd.value = false;
})
.catch((e) => {
console.log(e);
});
};
const closeAmapDrawer = () => {
setTimeout(() => {
visible.value = true;
}, 500);
};
const onSiteB = () => {
onSiteRef.value.showModal({ id: pId.value, hospitalId: informationData.value.hospitalId });
};
const initData = () => {
informationData.value = [];
const params = { id: pId.value };
queryByIdApi(params)
.then((res) => {
informationData.value = res;
})
.catch((e) => {
console.log(e);
});
};
const filterEmployInfo = () => {
return (
informationData.value.realname + '-' + render.renderDict(informationData.value.sex, 'gender').children + '-' + informationData.value.age
);
};
const filterAll = (item, type) => {
return render.renderDict(item, type).children;
};
const filterState = (type) => {
let result = '';
switch (type) {
case '1':
result = '未派单';
break;
case '2':
result = '已派单';
break;
case '3':
result = '已完成';
break;
case '4':
result = '已驳回';
break;
case '5':
result = '申请转单';
break;
}
return result;
};
defineExpose({
showDrawer,
});
</script>
<style scoped lang="less">
.sepical-des {
padding-left: 5px;
cursor: pointer;
color: #5774c1;
}
.bottom-button {
display: flex;
justify-content: center;
padding: 10px 0;
:nth-child(n) {
margin: 0 10px;
border-radius: 10px;
}
}
</style>
@@ -0,0 +1,496 @@
<template>
<a-row style="width: 100%; min-height: 0; overflow: hidden; position: relative">
<div style="width: 40%; height: 100%; overflow: hidden; position: absolute; left: 0; top: 0">
<a-row class="list-row">
<div class="list-f">应急人</div>
<div class="list-s">发起时间</div>
<div class="list-t">预约医院</div>
<div class="list-fo">状态</div>
</a-row>
<div style="height: calc(100% - 40px); overflow: auto">
<div v-for="(item, index) in ListData" style="padding: 0 10px" :key="'ListData' + index" @click="rowClick(item.id, index)">
<div class="list-row-list" :class="[pId === item.id ? 'back-g-b' : '']">
<div class="list-f">
<img
style="width: 40px; height: 40px; border-radius: 10px"
:src="item.initiatorUserAvatar ? getFileAccessHttpUrl(item.initiatorUserAvatar) : avatar"
alt=""
/>
<div style="margin-left: 5px">
<div>
{{ item.realname }}
</div>
<div>
{{ filterEmployInfoList(item) }}
</div>
</div>
</div>
<div class="list-s">{{ moment(item.createTime).format('YYYY-MM-DD') }}</div>
<div class="list-t">{{ item.hospitalName }}</div>
<div class="list-fo">{{ item.state_dictText }}</div>
</div>
</div>
<div class="onload-more" style="cursor: pointer" @click="onLoadMore()">
<span>
<a-spin v-if="loadMoreStatus === 1" />
{{ onLoadMoreText() }}
</span>
</div>
</div>
</div>
<div
style="
min-height: 0;
height: 100%;
background: #ffffff;
width: 60%;
padding: 10px 0 0 10px;
position: absolute;
overflow: auto;
left: 40%;
top: 0;
"
>
<div v-if="pId">
<div style="text-align: center; position: relative">
<a-button type="text" style="position: absolute; right: 20px; color: #1890ff" @click="backMap"> 返回 </a-button>
<span style="font-weight: bold; font-size: 18px; margin: auto">大病就医预约单</span>
</div>
<a-descriptions title="员工信息" :column="2">
<a-descriptions-item label="员工信息">
{{ filterEmployInfo() }}
</a-descriptions-item>
<a-descriptions-item label="所属单位">
{{ informationData.userDepart }}
<!-- <span v-if="!!informationData.userDepart" @click="getLocal(item.lon, item.lat)">-->
<!-- 位置-->
<!-- <svg-->
<!-- t="1684981639908"-->
<!-- class="icon"-->
<!-- viewBox="0 0 1024 1024"-->
<!-- version="1.1"-->
<!-- xmlns="http://www.w3.org/2000/svg"-->
<!-- p-id="2394"-->
<!-- width="10"-->
<!-- height="10"-->
<!-- >-->
<!-- <path-->
<!-- d="M753.536 663.552a337.066667 337.066667 0 0 0 0-478.805333c-133.333333-132.565333-349.738667-132.565333-483.072 0a337.066667 337.066667 0 0 0 0 478.805333L512 903.68l241.536-240.128zM210.304 724.096a422.4 422.4 0 0 1 0-599.893333C376.917333-41.386667 647.082667-41.386667 813.653333 124.245333a422.4 422.4 0 0 1 0 599.893334L512 1024l-301.696-299.946667zM512 512a85.333333 85.333333 0 1 0 0-170.666667 85.333333 85.333333 0 0 0 0 170.666667z m0 85.333333a170.666667 170.666667 0 1 1 0-341.333333 170.666667 170.666667 0 0 1 0 341.333333z"-->
<!-- fill="#f2f2f2"-->
<!-- p-id="2395"-->
<!-- data-spm-anchor-id="a313x.7781069.0.i0"-->
<!-- class="selected"-->
<!-- />-->
<!-- </svg>-->
<!-- </span>-->
</a-descriptions-item>
<a-descriptions-item label="手机号">
{{ informationData.telPhone }}
</a-descriptions-item>
<a-descriptions-item label="身份证号">
{{ informationData.idNo }}
</a-descriptions-item>
</a-descriptions>
<a-descriptions title="工单信息" :column="2">
<a-descriptions-item label="挂号类型">
{{ filterAll(informationData.registerCategory, 'category') }}
</a-descriptions-item>
<a-descriptions-item label="预约医院">
{{ informationData.hospitalName }}
</a-descriptions-item>
<a-descriptions-item label="预约医生">
{{ informationData.reservationDoctor }}
</a-descriptions-item>
<a-descriptions-item label="预约科室">
{{ informationData.reservationOffice }}
</a-descriptions-item>
<a-descriptions-item label="就诊卡号">
{{ informationData.medicalCardNo }}
</a-descriptions-item>
<a-descriptions-item label="预约时间">
{{ informationData.reservationTime }}
</a-descriptions-item>
<a-descriptions-item label="病情描述" :span="2">
{{ informationData.diseaseDescribe }}
</a-descriptions-item>
</a-descriptions>
<a-descriptions title="预约单信息" :column="2">
<a-descriptions-item label="预约单状态">
{{ informationData.state_dictText }}
</a-descriptions-item>
<a-descriptions-item label="创建时间">
{{ informationData.createTime }}
</a-descriptions-item>
<a-descriptions-item label="预约单号">
{{ informationData.reservationNo }}
</a-descriptions-item>
</a-descriptions>
<a-row class="bottom-button">
<a-button @click="backUp(informationData)">驳回</a-button>
<a-button type="primary" @click="onSiteB">派单驻场</a-button>
</a-row>
</div>
<div id="container" v-else> </div>
</div>
<a-modal :visible="visibleEnd" title="驳回意见" :footer="null" @cancel="cancelReason">
<div style="padding: 10px 20px">
<a-textarea v-model:value="rejectionReason" placeholder="" :rows="5" />
</div>
<div style="display: flex; justify-content: center; padding: 10px 0">
<a-button @click="cancelReason" style="margin-right: 10px">取消</a-button>
<a-button type="primary" @click="saveB" style="margin-left: 10px">确定</a-button>
</div>
</a-modal>
<onSite :userType="'1'" ref="onSiteRef" @siteOk="siteOk" />
<aMapDrawer :lat="lat" :lon="lon" ref="aMapDrawerRef" />
</a-row>
</template>
<script setup lang="ts">
import { queryByIdApi, operatorRejectApi, emergencyListApi, resourceHomeApi } from '/@/views/emergency/communication/components/commApi';
import onSite from './onSite.vue';
import aMapDrawer from './aMapDrawer.vue';
import { ref, shallowRef, unref } from 'vue';
import { render } from '/@/utils/common/renderUtils';
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
import moment from 'moment';
import AMapLoader from '@amap/amap-jsapi-loader';
import avatar from '/@/assets/images/avatar.png';
import { mapKey } from '/@/utils/baiduMaopKey';
import { message } from 'ant-design-vue';
const visibleEnd = ref<Boolean>(false);
const pId = ref<String>(''); // 父ID
const pIndex = ref<Number>(-1); // 选中行的下标
const rejectionReason = ref<String>();
const onSiteRef = ref();
const aMapDrawerRef = ref();
const lon = ref<Number>();
const lat = ref<Number>();
const informationData = ref<Object>({});
const ListDataForm = ref({
current: 1,
pageSize: 10,
total: 0,
}); // 操作人员左侧列表查询条件
const map = shallowRef(null);
const aMap = ref(null);
let infoWindow = ref(null);
const initMap = (list, lng, lat) => {
AMapLoader.load({
key: mapKey, // 申请好的Web端开发者Key,首次调用 load 时必填
version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: [''], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
})
.then((AMap) => {
aMap.value = AMap;
infoWindow.value = new AMap.InfoWindow({ offset: new AMap.Pixel(6, -5) });
//设置地图容器id
map.value = new AMap.Map('container', {
viewMode: '3D', //是否为3D地图模式
zoom: 8, //初始化地图级别
center: [lng, lat], //初始化地图中心点位置
});
let marker = null;
let markerList = [];
markerList = list.map((item) => {
marker = new AMap.Marker({
position: new AMap.LngLat(item.longitude, item.latitude),
icon: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-red.png',
map: map,
});
marker.content = item.name;
marker.on('click', markerClick);
marker.emit('click', { target: marker });
return marker;
});
unref(map).add(markerList);
})
.catch((e) => {
console.log(e);
});
};
function markerClick(e) {
infoWindow.value.setContent(e.target.content);
infoWindow.value.open(unref(map), e.target.getPosition());
}
const initLatLon = () => {
resourceHomeApi({
latitude: '',
longitude: '',
type: 0,
})
.then((res) => {
const list = res.resources;
const [lat, lng] = getPointsCenter(list);
initMap(list, lng, lat);
})
.catch((e) => {
console.log(e);
});
};
function backMap() {
pId.value = '';
initLatLon();
}
function getPointsCenter(points) {
let point_num = points.length; //坐标点个数
let X = 0,
Y = 0,
Z = 0;
for (let i = 0; i < points.length; i++) {
let point = [points[i].latitude, points[i].longitude];
let lat, lng, x, y, z;
lat = (parseFloat(point[0]) * Math.PI) / 180;
lng = (parseFloat(point[1]) * Math.PI) / 180;
x = Math.cos(lat) * Math.cos(lng);
y = Math.cos(lat) * Math.sin(lng);
z = Math.sin(lat);
X += x;
Y += y;
Z += z;
}
X = X / point_num;
Y = Y / point_num;
Z = Z / point_num;
let tmp_lng = Math.atan2(Y, X);
let tmp_lat = Math.atan2(Z, Math.sqrt(X * X + Y * Y));
return [(tmp_lat * 180) / Math.PI, (tmp_lng * 180) / Math.PI];
}
const loadMoreStatus = ref<Number>(0); // 加载状态 0 点击加载更多,1加载中,2加载完毕,3无更多数据
const onLoadMore = () => {
if (loadMoreStatus.value === 1 || loadMoreStatus.value === 3) return;
ListDataForm.value.current += 1;
initListData();
};
const onLoadMoreText = () => {
let result = '点击加载更多';
switch (loadMoreStatus.value) {
case 0:
result = '点击加载更多';
break;
case 1:
result = '加载中';
break;
case 2:
result = '点击加载更多';
break;
case 3:
result = '无更多数据';
break;
}
return result;
};
const ListData = ref<Array>([]); // 操作人员左侧列表
const getLocal = (la, lo) => {
lon.value = la;
lat.value = lo;
setTimeout(() => {
aMapDrawerRef.value.showDrawer();
}, 500);
};
// 点击行方法
const rowClick = (id, index) => {
pId.value = id;
pIndex.value = index;
initData();
};
const backUp = () => {
visibleEnd.value = true;
};
const cancelReason = () => {
rejectionReason.value = '';
visibleEnd.value = false;
};
const saveB = () => {
if (!rejectionReason.value) return message.info('驳回意见不能为空');
const params = {
id: pId.value,
rejectionReason: rejectionReason.value,
};
operatorRejectApi(params)
.then(() => {
rejectionReason.value = '';
initData();
ListData.value[pIndex.value].state_dictText = '驳回';
visibleEnd.value = false;
})
.catch((e) => {
console.log(e);
});
};
const onSiteB = () => {
if (!['1', '7'].includes(informationData.value['state'])) {
return message.info('该订单暂时无法派单');
}
onSiteRef.value.showModal({ id: pId.value, hospitalId: informationData.value['hospitalId'] });
};
const siteOk = () => {
initData();
};
const initData = () => {
informationData.value = {};
const params = { id: pId.value };
queryByIdApi(params)
.then((res) => {
informationData.value = res;
ListData.value[pIndex.value].state_dictText = res.state_dictText;
})
.catch((e) => {
console.log(e);
});
};
const filterEmployInfo = () => {
return Object.keys(informationData.value).length > 0
? informationData.value.realname + '-' + render.renderDict(informationData.value.sex, 'gender').children + '-' + informationData.value.age
: '';
};
const filterEmployInfoList = (data) => {
return data.sex_dictText + '-' + data.age + '-' + data.userDepart;
};
const filterAll = (item, type) => {
return render.renderDict(item, type).children;
};
const filterState = (type) => {
return render.renderDict(type, 'emergency_order_status').children;
};
const initListData = () => {
const params = {
orderType: '0',
personType: '0',
pageNo: ListDataForm.value.current,
pageSize: ListDataForm.value.pageSize,
};
loadMoreStatus.value = 1;
emergencyListApi(params)
.then((res) => {
ListData.value = [...ListData.value, ...res.records];
if (ListDataForm.value.current === 1 && ListData.value.length > 0 && !ListData.value[0].sessionId) {
// pId.value = ListData.value[0].id;
// pId.value = '1651414766494240770';
// initData();
}
if (ListDataForm.value.current < res.pages) {
loadMoreStatus.value = 2;
} else {
loadMoreStatus.value = 3;
}
})
.catch((e) => {
loadMoreStatus.value = 2;
console.log(e);
});
};
initListData();
defineExpose({
initLatLon,
});
</script>
<style scoped lang="less">
div {
box-sizing: border-box !important;
}
.sepical-des {
padding-left: 5px;
cursor: pointer;
color: #5774c1;
}
.bottom-button {
display: flex;
justify-content: center;
padding: 10px 0;
:nth-child(n) {
margin: 0 10px;
border-radius: 10px;
}
}
.list-row,
.list-row-list {
> :nth-child(1) {
width: 40%;
display: flex;
align-items: center;
justify-content: center;
}
> :nth-child(2) {
width: 22%;
display: flex;
align-items: center;
justify-content: center;
}
> :nth-child(3) {
width: 22%;
display: flex;
align-items: center;
justify-content: center;
}
> :nth-child(4) {
width: 16% !important;
display: flex;
align-items: center;
justify-content: center;
}
}
.list-row {
padding: 0 20px;
> :nth-child(n) {
justify-content: center !important;
}
height: 40px;
line-height: 45px;
}
.list-row-list {
display: flex;
overflow: auto;
padding: 5px;
background-color: #ffffff;
margin-bottom: 8px;
border-radius: 10px;
cursor: pointer;
> :nth-child(1) {
justify-content: flex-start !important;
padding-left: 5px;
}
}
.list-row-list:hover {
background-color: rgba(42, 110, 253, 0.8);
}
.back-g-b {
background-color: #2a6efd;
}
.onload-more {
transform: scale(0.8);
text-align: center;
margin-bottom: 5px;
}
#container {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
:deep(.amap-icon) {
width: 15px;
height: 20px;
img {
width: 15px;
height: 20px;
}
}
</style>
@@ -0,0 +1,135 @@
import { defHttp } from '/@/utils/http/axios';
const api = {
statistics: '/health-emergency/api/emergency/statSimple', // 获取统计数据
sessionList: '/health-consultation/consultation/conSession/list', // 获取会话列表
fastForm: '/health-emergency/api/emergency/order/getOrderById', // 应急单详情
supplement: '/health-emergency/api/emergency/order/fillSummary', // 补充小节
endB: '/health-emergency/api/emergency/order/orderOver', // 结束应急
// onSitePerson: '/sys/api/listUserByPersonType', // 获取驻场人员
onSitePerson: '/health-system/sys/healthUserStationEx/listCustom', // 获取驻场人员
onSitePersonNew: '/sys/api/listUserByPersonHospital', // 获取驻场人员(新)
orderBusiness: '/sys/dictItem/list', // 派单业务字典
stationSave: '/health-emergency/api/emergency/order/stationSendOrder', // 驻场派单保存
secondDepart: '/sys/sysDepart/allSecondaryDeparts', // 查询所有二级部门
employList: '/sys/healthUserEmployeeEx/list', // 查询二级部门下的员工
listByMc: '/sys/healthUserEmployeeEx/listByMc', // 日常诊疗,长庆员工列表最新接口 2024年4月19日09:42:30
employListNew: '/health-system/sys/healthUserEmployeeEx/listUserBackByOrg', // 查询二级部门下的员工新
updateSalvageUser: '/health-emergency/api/emergency/order/updateSalvageUser', // 驻场派单保存
stat: '/health-emergency/api/emergency/stat', //数据统计
scheduleRecord: '/health-emergency/api/emergency/schedule/scheduleShow', //年/月值班记录
// queryById: '/health-emergency/emergency/emergencySeriousDisease/queryById', // 通过id查询大病就医单
queryById: '/health-emergency/emergency/emergencySeriousDisease/queryById', // 通过id查询大病就医单
dispatchStation: '/health-emergency/emergency/emergencySeriousDisease/dispatchStation', // 大病就医驻场派单
operatorReject: '/health-emergency/emergency/emergencySeriousDisease/operatorReject', // 驳回意见
// emergencyList: '/health-emergency/api/emergency/order/page', // 操作人员列表
emergencyList: '/health-emergency/emergency/emergencySeriousDisease/operatorList', // 操作人员列表
userSigAndroid: '/health-im/wnapp/userSigAndroid', // 操作人员列表
resourceHome: '/health-emergency/api/emergency/resource/home', // 获取所有资源
salvageOpinion: '/health-emergency/api/emergency/order/salvageOpinion', // 获取救助意见
addSalvageOpinion: '/health-emergency/api/emergency/order/addSalvageOpinion', // 获取救助意见
doctorList: '/health-consultation/conDoctor/list', // 专家列表
};
/* 操作人员接口 */
export const getStatisticsApi = () => {
return defHttp.get({ url: api.statistics });
};
export const getSessionListApi = () => {
return defHttp.get({ url: api.sessionList });
};
export const fastFormApi = (params: object) => {
return defHttp.get({ url: api.fastForm, params });
};
export const supplementApi = (params: object) => {
return defHttp.post({ url: api.supplement, params });
};
export const endBApi = (params: object) => {
return defHttp.post({ url: api.endB, params });
};
export const onSitePersonApi = () => {
// const params = { personType: 7 };
return defHttp.get({ url: api.onSitePerson });
};
export const onSitePersonNewApi = (params: object) => {
params = { ...{ personType: 7 }, ...params };
return defHttp.get({ url: api.onSitePersonNew, params });
};
export const orderBusinessApi = () => {
const params = { pageNo: 1, pageSize: 999, dictId: '1651832259249328130' };
return defHttp.get({ url: api.orderBusiness, params });
};
export const stationSaveApi = (params) => {
return defHttp.post({ url: api.stationSave, params });
};
export const secondDepartApi = () => {
const params = {};
return defHttp.get({ url: api.secondDepart, params });
};
export const employListApi = (params) => {
return defHttp.get({ url: api.employList, params });
};
export const doctorListApi = (params) => {
return defHttp.get({ url: api.doctorList, params });
};
export const listByMcApi = (params) => {
return defHttp.get({ url: api.listByMc, params });
};
export const employListNewApi = (params) => {
return defHttp.get({ url: api.employListNew, params });
};
export const updateSalvageUserApi = (params) => {
return defHttp.post({ url: api.updateSalvageUser, params });
};
/* 专业人员接口 */
export const stat = (params) => {
return defHttp.get({ url: api.stat, params });
};
export const scheduleRecordApi = (params) => {
return defHttp.get({ url: api.scheduleRecord, params });
};
export const queryByIdApi = (params) => {
return defHttp.get({ url: api.queryById, params }, { successNeedMessage: false });
};
export const dispatchStationApi = (params) => {
return defHttp.get({ url: api.dispatchStation, params });
};
export const operatorRejectApi = (params) => {
return defHttp.get({ url: api.operatorReject, params });
};
export const emergencyListApi = (params: {}) => {
return defHttp.get({ url: api.emergencyList, params });
};
export const userSigAndroidApi = (params: {}) => {
return defHttp.get({ url: api.userSigAndroid, params });
};
export const resourceHomeApi = (params: {}) => {
return defHttp.get({ url: api.resourceHome, params });
};
export const salvageOpinionApi = (params: {}) => {
return defHttp.get({ url: api.salvageOpinion, params }, { successNeedMessage: false });
};
export const addSalvageOpinionApi = (params: {}) => {
return defHttp.post({ url: api.addSalvageOpinion, params });
};
@@ -0,0 +1,27 @@
export const person = [
{ labelName: '发起人', key: 'initiatorUserName', initiatorUserName: '张三' },
{ labelName: '发起人单位', key: 'initiatorUserDepart', initiatorUserDepart: '第一油厂-财务' },
{ labelName: '手机号', key: 'initiatorUserMobile', initiatorUserMobile: '13333333333' },
{ labelName: '年龄', key: 'fqrAge', fqrAge: '54', initiatorLatitude: '39.956981', initiatorLongitude: '116.345627' },
{ labelName: '被救助人', key: 'salvageUserId', salvageUserId: '李四', salvageUserId: '001' },
{ labelName: '救助人单位', key: 'salvageUserDepart', salvageUserDepart: '第一油厂-后勤' },
{ labelName: '手机号', key: 'salvageUserMobile', salvageUserMobile: '14444444444' },
{ labelName: '年龄', key: 'jzrAge', jzrAge: '53' },
];
export const messageList = [
{ labelName: '工单状态', key: 'orderStatus', gdStatus: '咨询中', spanNumber: 2 },
{ labelName: '专业人员', key: 'salvageDoctor', salvageDoctor: '扁鹊-主治', salvageDepart: '', spanNumber: 2 },
{ labelName: '救助意见', key: 'memo', memo: '', spanNumber: 2 },
{ labelName: '应急单号', key: 'id', id: 'sfsd1231f12d', spanNumber: 0 },
{ labelName: '创建时间', key: 'createTime', createTime: '2023-5-23', spanNumber: 0 },
{ labelName: '操作人员', key: 'operationUserName', operationUserName: '马岱', spanNumber: 0 },
{ labelName: '响应时间', key: 'operationResponseTime', operationResponseTime: '2023-5-26', spanNumber: 0 },
{ labelName: '派单业务', key: 'stationBusiness', stationBusiness: '咨询中', spanNumber: 0 },
{ labelName: '应急医院', key: 'salvageHospital', salvageHospital: '第一人民医院', spanNumber: 0 },
{ labelName: '驻场人员', key: 'stationUserName', stationUserName: '李四', spanNumber: 0 },
{ labelName: '接单时间', key: 'jdTime', jdTime: '2023-00', spanNumber: 0 },
{ labelName: '派单业务', key: 'pdYw', pdYw: '咨询中', spanNumber: 0 },
{ labelName: '应急医院', key: 'yjHosptil', yjHosptil: '咨询中', spanNumber: 0 },
{ labelName: '驻场人员', key: 'operate', operate: '咨询中', spanNumber: 0 },
{ labelName: '拒单时间', key: 'jjTime', jjTime: '咨询中', spanNumber: 0 },
];
@@ -0,0 +1,255 @@
<template>
<a-drawer v-model:visible="visible" class="custom-class" style="color: red; overflow: auto" title="应急详情" width="50%" placement="right">
<a-descriptions title="应急员工" :column="2">
<!-- <a-descriptions-item v-for="(item, index) in person" :label="item.labelName" :key="'person' + index">-->
<!-- {{ item[item.key] }}-->
<!-- <span v-if="item.key === 'jzr'" class="sepical-des" @click="replaceMan(item.jzrId)">更换救助人</span>-->
<!-- <span v-if="item.key === 'fqrAge'" class="sepical-des" @click="personLocal(item.lat, item.lon)">员工位置</span>-->
<!-- </a-descriptions-item>-->
<a-descriptions-item label="发起人">
{{ resultInfo?.initiatorUserName }}
</a-descriptions-item>
<a-descriptions-item label="发起人单位">
{{ filterDeptO(resultInfo?.initiatorUserSecondDepart, resultInfo?.initiatorUserDepart) }}
</a-descriptions-item>
<a-descriptions-item label="手机号">
{{ resultInfo?.initiatorUserMobile }}
</a-descriptions-item>
<a-descriptions-item label="年龄">
{{ resultInfo?.initiatorUserAge }}
<span class="sepical-des" @click="personLocal(resultInfo?.initiatorLatitude, resultInfo?.initiatorLongitude)">员工位置</span>
</a-descriptions-item>
<a-descriptions-item label="被救助人">
{{ Object.keys(newEmploy).length > 0 ? newEmploy.realname : resultInfo?.salvageUserName }}
<span class="sepical-des" @click="replaceMan()">更换救助人</span>
</a-descriptions-item>
<a-descriptions-item label="救助人单位">
{{
Object.keys(newEmploy).length > 0 ? filterDept() : filterDeptO(resultInfo?.salvageUserSecondDepart, resultInfo?.salvageUserDepart)
}}
</a-descriptions-item>
<a-descriptions-item label="手机号">
{{ Object.keys(newEmploy).length > 0 ? newEmploy.phone : resultInfo?.salvageUserMobile }}
</a-descriptions-item>
<a-descriptions-item label="年龄">
{{ Object.keys(newEmploy).length > 0 ? newEmploy.age : resultInfo?.salvageUserAge }}
</a-descriptions-item>
</a-descriptions>
<a-descriptions title="工单信息" :column="2">
<a-descriptions-item label="工单状态" :span="2">
{{ resultInfo?.orderStatus_dictText }}
</a-descriptions-item>
<a-descriptions-item label="专业人员" :span="2">
{{ resultInfo?.majorUserName }}
<!-- <span class="sepical-des" @click="comm('aa')">聊天记录</span>-->
<!-- <span class="sepical-des" @click="luYin('bb')">视频</span>-->
</a-descriptions-item>
<a-descriptions-item label="救助意见" :span="2">
{{ resultInfo?.infoDesc }}
</a-descriptions-item>
<a-descriptions-item label="应急单号">
{{ resultInfo?.id }}
</a-descriptions-item>
<a-descriptions-item label="创建时间">
{{ resultInfo?.createTime }}
</a-descriptions-item>
<a-descriptions-item label="操作人员">
{{ resultInfo?.operationUserName }}
</a-descriptions-item>
<a-descriptions-item label="响应时间">
{{ resultInfo?.operationResponseTime }}
</a-descriptions-item>
<template v-for="(item, index) in resultInfo?.orderSendRecordList" :key="'orderSendRecordList ' + index">
<a-descriptions-item label="派单业务">
{{ item.stationBusiness_dictText }}
</a-descriptions-item>
<a-descriptions-item label="应急医院">
{{ item.sendOrderHospital }}
</a-descriptions-item>
<a-descriptions-item label="驻场人员">
{{ item.stationUserName }}
</a-descriptions-item>
<a-descriptions-item :label="(item.accept == 0 ? '拒单' : '接单') + '时间'">
{{ item.transferOrderTime }}
</a-descriptions-item>
</template>
<!-- <a-descriptions-item v-for="(item, index) in messageList" :label="item.labelName" :span="item.spanNumber" :key="'messageList' + index">-->
<!-- {{ item[item.key] }}-->
<!-- <span v-if="item.key === 'proPerson'" class="sepical-des" @click="comm(item.lt)">聊天记录</span>-->
<!-- <span v-if="item.key === 'proPerson'" class="sepical-des" @click="luYin(item.luYin)">视频</span>-->
<!-- </a-descriptions-item>-->
</a-descriptions>
<a-row class="bottom-button">
<a-button type="primary" :disabled="resultInfo.orderStatus === '5'" @click="saveB" :loading="saveLoading">保存</a-button>
<a-button type="primary" :disabled="resultInfo.orderStatus === '5'" @click="supplementB(resultInfo)">补充小节</a-button>
<a-button type="primary" :disabled="resultInfo.orderStatus === '5'" @click="onSiteB(resultInfo)">驻场派单</a-button>
<!-- <a-button type="primary" :disabled="resultInfo.orderStatus === '5'" @click="endB(resultInfo)" :loading="endLoading">结束应急</a-button>-->
</a-row>
<replaceOther ref="replaceOtherRef" @choose-employ="chooseEmploy" />
<onSite :userType="'0'" @reload="reloadData" ref="onSiteRef" />
<supplement @save-info="saveSupplement" ref="supplementRef" />
<aMapDrawer :lat="resultInfo?.initiatorLatitude" :lon="resultInfo?.initiatorLongitude" ref="aMapDrawerRef" />
</a-drawer>
</template>
<script setup lang="ts">
import { message } from 'ant-design-vue';
import onSite from './onSite.vue';
import replaceOther from './replaceOther.vue';
import supplement from './supplement.vue';
import aMapDrawer from './aMapDrawer.vue';
import { ref } from 'vue';
import { fastFormApi, endBApi, updateSalvageUserApi } from '/@/views/emergency/communication/components/commApi';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
const visible = ref<Boolean>(false);
const saveLoading = ref<Boolean>(false);
const endLoading = ref<Boolean>(false);
const replaceOtherRef = ref();
const onSiteRef = ref();
const aMapDrawerRef = ref();
const supplementRef = ref();
const pId = ref('');
const resultInfo = ref<Object>({});
const newEmploy = ref<Object>({});
const showDrawer = (id) => {
pId.value = id;
newEmploy.value = {};
resultInfo.value = {};
fastForm();
visible.value = true;
};
const reloadData = () => {
fastForm();
};
/* 查询详情信息 后期参数需改为pId*/
const fastForm = () => {
// fastFormApi({ sessionId: '989898989891' })
fastFormApi({ id: pId.value })
.then((res) => {
if (res) {
resultInfo.value = res;
} else {
// visible.value = false;
resultInfo.value['orderStatus'] = '5';
message.info('该应急单已经结束');
}
})
.catch((e) => {
console.log(e);
});
};
const personLocal = () => {
if (!resultInfo.value) return;
aMapDrawerRef.value.showDrawer();
};
const replaceMan = () => {
if (resultInfo.value.orderStatus === '5') return message.info('该应急单已经结束!');
replaceOtherRef.value.showModal();
};
const comm = (comm) => {
message.info('聊天记录' + comm);
};
const luYin = (luYin) => {
message.info('录音是' + luYin);
};
const saveB = () => {
if (resultInfo.value.orderStatus === '5') return message.info('该应急单已经结束!');
if (Object.keys(newEmploy.value).length === 0) return message.info('未更换被救助人');
const params = {
id: resultInfo.value.id,
salvageUserMobile: newEmploy.value.phone,
salvageUserSex: newEmploy.value.sex,
salvageUserName: newEmploy.value.realname,
salvageUserSecondDepart: newEmploy.value.secondDepart !== null ? newEmploy.value.secondDepart.orgCode : '',
salvageUserId: newEmploy.value.id,
salvageUserDepart: newEmploy.value.orgCode,
salvageUserIdCard: newEmploy.value.idCard,
};
updateSalvageUserApi(params)
.then((res) => {
console.log(res);
})
.catch((e) => {
console.log(e);
});
};
const supplementB = (item) => {
if (item.orderStatus === '3') return message.info('该应急单已经结束!');
supplementRef.value.showSuppDrawer(item.id, item.orderDetail?.orderThrough, item.orderDetail?.orderResult);
};
const onSiteB = (item) => {
if (item.orderStatus === '3') return message.info('该应急单已经结束!');
onSiteRef.value.showModal({ id: item.id, hospitalId: '' });
};
const chooseEmploy = (e) => {
newEmploy.value = JSON.parse(e);
};
const filterDept = () => {
let result = '';
if (newEmploy.value.departTree.length === 2) {
result = newEmploy.value.departTree[1];
}
if (newEmploy.value.departTree.length === 3) {
result = newEmploy.value.departTree[1] + '-' + newEmploy.value.departTree[2];
}
return result;
};
const filterDeptO = (o, t) => {
let result = '';
if (o !== null) {
result += o;
}
if (o !== null && t !== null) {
result += '-';
}
if (t !== null) {
result += t;
}
return result;
};
const endB = (item) => {
if (item.orderStatus === '3') return message.info('该应急单已经结束!');
createConfirm({
iconType: 'warning',
title: '结束应急',
content: '是否结束应急',
okText: '确认',
cancelText: '取消',
onOk: async () => {
try {
await endBApi({ id: item.id });
resultInfo.value.orderStatus = '5';
} catch (e) {
console.log(e);
}
},
});
};
const saveSupplement = (data) => {
resultInfo.value.orderDetail.orderThrough = data.passR;
resultInfo.value.orderDetail.orderResult = data.resultR;
};
defineExpose({
showDrawer,
});
</script>
<style scoped lang="less">
.sepical-des {
margin-left: 20px;
cursor: pointer;
color: #5774c1;
}
.bottom-button {
display: flex;
justify-content: center;
padding: 10px 0;
:nth-child(n) {
margin: 0 10px;
border-radius: 10px;
}
}
</style>
@@ -0,0 +1,75 @@
<template>
<div>
<a-modal v-model:visible="visible" title="救助意见" :footer="null">
<div style="padding: 10px 20px 0">
<a-textarea
class="textarea-c"
:bordered="isSpecialized"
:readonly="!isSpecialized"
v-model:value="modalText"
placeholder=""
:rows="5"
/>
<div style="text-align: center; padding: 10px">
<a-button v-if="isSpecialized" size="small" type="primary" :disabled="!isDisabled" @click="handleOk" :loading="confirmLoading">
提交
</a-button>
</div>
</div>
</a-modal>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { salvageOpinionApi, addSalvageOpinionApi } from '/@/views/emergency/communication/components/commApi';
const visible = ref<Boolean>(false);
const confirmLoading = ref<Boolean>(false);
const modalText = ref<String>('');
const pId = ref<String>('');
const isDisabled = ref<Boolean>(true);
const handleOk = () => {
confirmLoading.value = true;
addSalvageOpinionApi({ sessionId: pId.value, infoDesc: modalText.value })
.then(() => {
confirmLoading.value = false;
visible.value = false;
})
.catch((e) => {
console.log(e);
});
};
const showModal = (id, flag) => {
modalText.value = '';
visible.value = true;
pId.value = id;
isDisabled.value = flag;
// if (!props.isSpecialized) {
// 必需得先查
showAdv(id);
// }
};
const showAdv = (id) => {
salvageOpinionApi({ sessionId: id })
.then((res) => {
modalText.value = res;
})
.catch((e) => {
console.log(e);
});
};
const props = defineProps({
isSpecialized: Boolean,
});
defineExpose({
showModal,
});
</script>
<style scoped lang="less">
.textarea-c {
background-color: #f2f2f2;
border: none;
outline: none;
color: #000000;
}
</style>
@@ -0,0 +1,31 @@
export const businessData = [
{ id: '1', label: '挂号' },
{ id: '2', label: '加号' },
{ id: '3', label: '协调检查' },
{ id: '4', label: '代办出院' },
{ id: '5', label: '送取资料' },
{ id: '6', label: '陪同检查' },
{ id: '7', label: '代缴费' },
{ id: '8', label: '临时陪护' },
{ id: '9', label: '代购药' },
{ id: '10', label: '催床位' },
{ id: '11', label: '约手术' },
{ id: '12', label: '约医生' },
{ id: '13', label: '约会诊' },
{ id: '14', label: '帮转院' },
{ id: '15', label: '全程陪诊' },
];
export const personData = [
{ id: '1', label: '西京医院 - aaa' },
{ id: '2', label: '西京医院 - bbb' },
{ id: '3', label: '西京医院 - ccc' },
{ id: '4', label: '西京医院 - ddd' },
{ id: '5', label: '宝石花医院 - aaa' },
{ id: '6', label: '宝石花医院 - bbb' },
{ id: '7', label: '宝石花医院 - ccc' },
{ id: '8', label: '宝石花医院 - ddd' },
{ id: '9', label: '长安医院 - aaa' },
{ id: '10', label: '长安医院 - bbb' },
{ id: '11', label: '长安医院 - ccc' },
{ id: '12', label: '长安医院 - ddd' },
];
@@ -0,0 +1,172 @@
<template>
<a-modal v-model:visible="visible" title="驻场派单" :footer="null">
<a-form :label-col="{ span: 5, offset: 5 }" :wrapper-col="{ span: 14 }" style="padding: 20px 0">
<a-form-item v-if="userType === '0'" label="选择派单业务:">
<a-select
v-model:value="businessType"
style="width: 200px"
:options="businessData"
label-in-value
:fieldNames="{
label: 'itemText',
value: 'itemValue',
}"
/>
</a-form-item>
<a-form-item label="选择驻场人员:">
<a-select v-model:value="personType" style="width: 200px" :options="personData" label-in-value />
</a-form-item>
<div class="button-outer-div">
<a-button size="small" @click="handleCancel"> 取消 </a-button>
<a-button size="small" type="primary" @click="handleOk" :loading="confirmLoading"> 提交 </a-button>
</div>
</a-form>
</a-modal>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { orderBusinessApi, onSitePersonApi, stationSaveApi, dispatchStationApi, onSitePersonNewApi } from './commApi';
const visible = ref<Boolean>(false);
const businessType = ref<String>('');
const personType = ref<String>('');
const businessData = ref<Array<object>>([]);
const personData = ref<Array<object>>([]);
const confirmLoading = ref<Boolean>();
const pId = ref();
const hospitalId = ref('');
const props = defineProps({
userType: String,
});
const emit = defineEmits(['reload', 'siteOk']);
const showModal = (params) => {
pId.value = params.id;
hospitalId.value = params?.hospitalId;
initData();
visible.value = true;
};
const handleCancel = () => {
visible.value = false;
resetInfo();
};
const resetInfo = () => {
businessType.value = '';
personType.value = '';
confirmLoading.value = false;
};
const handleOk = () => {
confirmLoading.value = true;
if (props.userType === '0') {
userType0();
} else {
userType1();
}
};
const userType1 = () => {
const person = personType.value;
const params = {
stationUserId: person.option.id,
id: pId.value,
};
dispatchStationApi(params)
.then((res) => {
console.log(res);
confirmLoading.value = false;
emit('siteOk');
visible.value = false;
resetInfo();
})
.catch((e) => {
console.log(e);
confirmLoading.value = false;
});
};
const userType0 = () => {
const b = businessType.value;
const person = personType.value;
const params = {
id: pId.value,
stationUserId: person.option.id,
stationUserName: person.option.realName,
sendOrderHospitalId: person.option.hospitalId,
sendOrderHospital: person.option.hospitalName,
stationUserSex: person.option.sex,
stationUserMobile: person.option.phone,
stationUserAvatar: person.option.avatar,
stationUserDepart: person.option.orgCode,
stationBusiness: b.key,
};
stationSaveApi(params)
.then((res) => {
console.log(res);
emit('reload');
confirmLoading.value = false;
visible.value = false;
resetInfo();
})
.then((e) => {
console.log(e);
confirmLoading.value = false;
});
};
const initData = () => {
orderBusinessApi()
.then((res) => {
businessData.value = res.records;
})
.catch((e) => {
console.log(e);
});
if (props.userType === '0') {
onSitePerson();
} else {
onSitePersonNew();
}
};
const onSitePerson = () => {
onSitePersonApi()
.then((res) => {
personData.value = res.map((item) => {
item['value'] = item.realName;
return item;
});
})
.catch((e) => {
console.log(e);
});
};
const onSitePersonNew = () => {
onSitePersonNewApi({ hospital: hospitalId.value || '' })
.then((res) => {
personData.value = res.map((item) => {
item['value'] = item.realname;
return item;
});
})
.catch((e) => {
console.log(e);
});
};
defineExpose({
showModal,
});
</script>
<style scoped lang="less">
.button-outer-div {
display: flex;
padding: 10px;
justify-content: center;
button {
padding: 15px 20px;
border-radius: 10px;
display: flex;
align-items: center;
}
> button:nth-child(1) {
margin-right: 10px;
}
> button:nth-child(2) {
margin-left: 10px;
}
}
</style>
@@ -0,0 +1,278 @@
<template>
<div style="width: 100%; height: 100%">
<a-row class="top-row">
<a-col :span="12" style="display: flex">
<div :class="['button-o', checked ? 'choose-this' : '']" @click="clickThis(true)">
应急服务
<!-- <div v-show="oneNumber > 0" class="number-d">-->
<!-- {{ oneNumber > 99 ? '99+' : oneNumber }}-->
<!-- </div>-->
</div>
<div :class="['button-t', checked ? '' : 'choose-this']" @click="clickThis(false)">
大病就医
<!-- <div v-show="twoNumber > 0" class="number-d">-->
<!-- {{ twoNumber > 99 ? '99+' : twoNumber }}-->
<!-- </div>-->
</div>
</a-col>
<a-col :span="12" style="display: flex; justify-content: flex-end; padding-right: 60px">
<a-row class="top-right-row" style="color: #ffa845">
<div> 应急响应率</div>
<div>
{{ stat.emeResRate + '%' }}
</div>
</a-row>
<a-row class="top-right-row" style="color: #4ad246">
<div> 大病就医率</div>
<div>
{{ stat.seriousRate + '%' }}
</div>
</a-row>
</a-col>
</a-row>
<a-row class="bottom-row">
<a-spin
class="iframe"
style="display: flex; align-items: center; justify-content: center"
tip="加载中..."
v-if="checked && loadingVisible"
:spinning="loadingVisible"
/>
<!-- <iframe-->
<!-- v-show="checked && !loadingVisible"-->
<!-- id="iframeRef"-->
<!-- ref="iframeRef"-->
<!-- class="iframe"-->
<!-- :src="`http://localhost:8080?isSpecialized=false&${qs.stringify(props.imProps)}`"-->
<!-- ></iframe>-->
<iframe
v-show="checked && !loadingVisible"
id="iframeRef"
ref="iframeRef"
class="iframe"
:src="`${imAddressSrc}isSpecialized=false&${qs.stringify(props.imProps)}`"
></iframe>
<bigInformationDetail
v-show="!checked"
style="width: 100%; height: 100%; min-height: 0; overflow: visible"
ref="bigInformationDetailRef"
/>
</a-row>
<forHelpAdv :isSpecialized="false" ref="forHelpAdvRef" />
<detail ref="detailRef" />
<bigInformation ref="bigInformationRef" />
</div>
</template>
<script setup lang="ts">
import { ref, unref } from 'vue';
import forHelpAdv from './forHelpAdv.vue';
import detail from './detail.vue';
import bigInformation from './bigInformation.vue';
import bigInformationDetail from './bigInformationDetail.vue';
import { getStatisticsApi, getSessionListApi, endBApi } from '/@/views/emergency/communication/components/commApi';
import qs from 'qs';
import { imAddressSrc } from '/@/utils/imAddressSrc';
import { message } from 'ant-design-vue';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
const stat = ref<Object>({ emeResRate: 0, seriousRate: 0 });
const checked = ref<Boolean>(true);
const loadingVisible = ref<Boolean>(true); // loading
// const oneNumber = ref<Number>(10);
// const twoNumber = ref<Number>(0);
const forHelpAdvRef = ref();
const detailRef = ref();
const bigInformationRef = ref();
const bigInformationDetailRef = ref();
const iframeRef = ref();
const initMap = ref<Boolean>(true);
const props = defineProps({
imProps: Object,
});
const clickThis = (type) => {
// if (!type) return message.info('敬请期待!');
checked.value = type;
changeTab(type ? '0' : '1');
if (!type && initMap.value) {
initMap.value = false;
unref(bigInformationDetailRef).initLatLon();
}
};
/*change后修改type,需通信*/
const changeTab = (type) => {
unref(iframeRef).contentWindow.postMessage(
JSON.stringify({
code: 'tabChange',
type: type,
}),
'*'
);
};
/*change后修改数据,需通信*/
// const changeData = (res) => {
// unref(iframeRef).contentWindow.postMessage(JSON.stringify({ code: 'dataList', type: res }), '*');
// };
// watch(loadingVisible, (nV, oV) => {
// console.log('watch===========================');
// console.log(nV);
// console.log(oV);
// nextTick(() => {
// unref(iframeRef).contentWindow.postMessage(JSON.stringify({ code: 'dataList', type: 'res' }), '*');
// });
// });
/*求助意见点击返回*/
const forHelp = (res) => {
forHelpAdvRef.value.showModal(res);
};
const forHelpDetail = (res) => {
detailRef.value.showDrawer(res);
};
const information = (res) => {
bigInformationRef.value.showDrawer(res);
};
/* 查询统计 */
const getStatInfo = () => {
getStatisticsApi()
.then((res) => {
stat.value = res;
})
.catch((e) => {
console.log(e);
});
};
getStatInfo();
/* 查询绘画列表 */
// const getSessionList = () => {
// getSessionListApi()
// .then((res) => {
// changeData(res.records);
// })
// .catch((e) => {
// console.log(e);
// });
// };
const endB = (item) => {
if (item.orderStatus === '3') return message.info('该应急单已经结束!');
createConfirm({
iconType: 'warning',
title: '结束应急',
content: '是否结束应急',
okText: '确认',
cancelText: '取消',
onOk: async () => {
try {
await endBApi({ id: item.orderId });
} catch (e) {
console.log(e);
}
},
});
};
window.onmessage = (msg) => {
const result = JSON.parse(msg.data);
console.log(result);
switch (result.code) {
case 'forHelp':
forHelp(result.userId);
break;
case 'forHelpDetail':
forHelpDetail(result.userId);
break;
case 'bigInformation':
information(result.userId);
break;
case 'closeLoading':
closeLoading();
break;
case 'endStatus':
endB(result.orderInfo);
break;
}
};
const closeLoading = () => {
loadingVisible.value = false;
};
defineExpose({
window,
forHelp,
});
</script>
<style scoped lang="less">
.outer {
width: 100%;
height: 100%;
box-sizing: border-box;
background-color: #f2f2f2;
overflow-y: hidden;
}
.top-row {
padding: 10px;
background-color: #ffffff;
height: 60px;
display: flex;
align-items: center;
}
.bottom-row {
overflow: hidden;
margin-top: 1px;
min-height: 0;
height: calc(100% - 59px);
}
.button-o,
.button-t {
position: relative;
width: 120px;
height: 35px;
line-height: 35px;
border-radius: 10px;
border: 1px solid #d2d2d2;
text-align: center;
margin-right: 20px;
cursor: pointer;
}
.choose-this {
color: #ffffff;
background-color: #466afb;
}
.number-d {
width: 20px;
height: 20px;
line-height: 20px;
background-color: red;
color: #ffffff;
position: absolute;
right: 5px;
top: 7.5px;
font-size: 9px;
border-radius: 20px;
text-align: center;
}
.iframe {
width: 100%;
height: 100%;
overflow: hidden;
}
.top-right-row {
display: inline;
margin-right: 40px;
> :nth-child(1) {
font-size: 10px;
}
> :nth-child(2) {
font-size: 20px;
font-weight: 600;
}
}
</style>
@@ -0,0 +1,189 @@
<template>
<a-drawer v-model:visible="visible" :title="title" :footer="null" width="40%">
<a-form style="padding: 10px" name="advanced_search" class="ant-advanced-search-form">
<a-row :gutter="24">
<a-col :span="9">
<a-form-item label="单位:">
<a-select v-model:value="second" style="width: 200px" @change="changeSecond">
<a-select-option v-for="(item, index) in secondData" :key="'secondData' + index" :value="JSON.stringify(item)">
{{ item.departName }}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="9">
<a-form-item label="姓名:">
<a-input v-model:value="realname" style="width: 200px" />
</a-form-item>
</a-col>
<a-col :span="6" style="display: flex; align-items: center; justify-content: center">
<a-button type="primary" @click="searchBySearchInfo">查询</a-button>
</a-col>
</a-row>
</a-form>
<a-radio-group v-model:value="checked" button-style="solid" style="width: 100%; padding: 0 10px">
<a-table
:pagination="pSet"
@change="changeTable"
:dataSource="personData"
bordered
:scroll="{ y: '70vh' }"
:loading="pSet.tableLoading"
:custom-row="(record) => customRowF(record)"
>
<a-table-column key="selectOne" title="" align="center" width="80px">
<template #default="{ record }">
<a-radio :value="JSON.stringify(record)" />
</template>
</a-table-column>
<a-table-column key="realname" title="姓名" data-index="realname" align="center" />
<a-table-column key="secondD" title="单位" align="center">
<template #default="{ record }">
{{ record.secondDepart !== null ? record.secondDepart.departName : '' }}
</template>
</a-table-column>
<!-- <a-table-column key="depart" title="组织机构">-->
<!-- <template #default="{ record }">-->
<!-- {{ record.depart !== null ? record.depart.departName : '' }}-->
<!-- </template>-->
<!-- </a-table-column>-->
</a-table>
</a-radio-group>
<div class="button-outer-div">
<a-button @click="handleCancel"> 取消 </a-button>
<a-button type="primary" @click="handleOk"> 确定 </a-button>
</div>
</a-drawer>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { secondDepartApi, employListApi } from './commApi';
import { message } from 'ant-design-vue';
const visible = ref<Boolean>();
const secondData = ref<Array>();
const personData = ref<Array>();
const realname = ref<String>('');
const second = ref<String>('');
const checked = ref<String>();
const emit = defineEmits(['chooseEmploy']);
const props = defineProps({
title: {
default: () => '更换被救助人',
type: String,
},
});
const pSet = ref<Object>({
showTotal: (total) => showTotal(total),
current: 1,
pageSize: 10,
pageSizeOptions: ['10', '50', '80', '100'],
total: 0,
showQuickJumper: true,
size: 'small',
tableLoading: false,
});
const showTotal = (total) => {
return ' 共 ' + total + ' 条数据';
};
const initData = () => {
const params = {
pageNo: pSet.value.current,
pageSize: pSet.value.pageSize,
};
pSet.value.tableLoading = true;
if (realname.value) params['realname'] = realname.value;
if (second.value) params['orgCode'] = JSON.parse(second.value).orgCode;
employListApi(params)
.then((res) => {
personData.value = res.records;
pSet.value.total = res.total;
pSet.value.tableLoading = false;
})
.catch((e) => {
pSet.value.tableLoading = false;
console.log(e);
});
};
const changeTable = (pagination) => {
pSet.value.current = pagination.current;
pSet.value.pageSize = pagination.pageSize;
initData();
};
const showModal = () => {
restInfo();
visible.value = true;
initData();
};
const initSecondD = () => {
secondDepartApi()
.then((res) => {
secondData.value = res;
})
.catch((e) => {
console.log(e);
});
};
const handleCancel = () => {
restInfo();
visible.value = false;
};
const handleOk = () => {
if (!checked.value) {
return message.info('请至少选择一条');
}
emit('chooseEmploy', checked.value);
restInfo();
visible.value = false;
};
const searchBySearchInfo = () => {
pSet.value.current = 1;
checked.value = '';
initData();
};
const customRowF = (record) => {
return {
onClick: () => {
checked.value = JSON.stringify(record);
},
};
};
const changeSecond = () => {
// ?column=createTime&order=desc&pageNo=1&pageSize=10&orgCode=A01A44&_t=1685093387324
};
const restInfo = () => {
pSet.value.current = 1;
personData.value = [];
realname.value = '';
second.value = '';
checked.value = '';
};
initSecondD();
defineExpose({
showModal,
customRowF,
});
</script>
<style scoped lang="less">
.button-outer-div {
display: flex;
padding: 10px;
justify-content: center;
button {
padding: 15px 20px;
border-radius: 10px;
display: flex;
align-items: center;
}
> button:nth-child(1) {
margin-right: 10px;
}
> button:nth-child(2) {
margin-left: 10px;
}
}
:deep(.ant-form-item) {
margin-bottom: 0 !important;
width: 65px;
}
</style>
@@ -0,0 +1,155 @@
<template>
<a-drawer v-model:visible="visible" :title="title" :footer="null" width="40%">
<a-form style="padding: 10px" name="advanced_search" class="ant-advanced-search-form">
<a-row :gutter="24">
<a-col :span="9">
<a-form-item label="姓名:">
<a-input v-model:value="doctorName" style="width: 200px" />
</a-form-item>
</a-col>
<a-col :span="6" style="display: flex; align-items: center; justify-content: center">
<a-button type="primary" @click="searchBySearchInfo">查询</a-button>
</a-col>
</a-row>
</a-form>
<a-radio-group v-model:value="checked" button-style="solid" style="width: 100%; padding: 0 10px">
<a-table
:pagination="pSet"
@change="changeTable"
:dataSource="personData"
bordered
:scroll="{ y: '70vh' }"
:loading="pSet.tableLoading"
:custom-row="(record) => customRowF(record)"
>
<a-table-column key="selectOne" title="" align="center" width="80px">
<template #default="{ record }">
<a-radio :value="JSON.stringify(record)" />
</template>
</a-table-column>
<a-table-column key="doctorName" title="姓名" data-index="doctorName" align="center" />
<a-table-column key="resourceName" title="医院" data-index="resourceName" align="center"/>
<a-table-column key="departmentName" title="科室" data-index="departmentName" align="center"/>
</a-table>
</a-radio-group>
<div class="button-outer-div">
<a-button @click="handleCancel"> 取消 </a-button>
<a-button type="primary" @click="handleOk"> 确定 </a-button>
</div>
</a-drawer>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { doctorListApi } from './commApi';
import { message } from 'ant-design-vue';
const visible = ref<Boolean>();
const personData = ref<Array>();
const doctorName = ref<String>('');
const checked = ref<String>();
const emit = defineEmits(['chooseEmploy']);
const props = defineProps({
title: {
default: () => '--',
type: String,
},
});
const pSet = ref<Object>({
showTotal: (total) => showTotal(total),
current: 1,
pageSize: 10,
pageSizeOptions: ['10', '50', '80', '100'],
total: 0,
showQuickJumper: true,
size: 'small',
tableLoading: false,
});
const showTotal = (total) => {
return ' 共 ' + total + ' 条数据';
};
const initData = () => {
const params = {
pageNo: pSet.value.current,
pageSize: pSet.value.pageSize,
};
pSet.value.tableLoading = true;
if (doctorName.value) params['doctorName'] = doctorName.value;
doctorListApi(params)
.then((res) => {
personData.value = res.records;
pSet.value.total = res.total;
pSet.value.tableLoading = false;
})
.catch((e) => {
pSet.value.tableLoading = false;
console.log(e);
});
};
const changeTable = (pagination) => {
pSet.value.current = pagination.current;
pSet.value.pageSize = pagination.pageSize;
initData();
};
const showModal = () => {
restInfo();
visible.value = true;
initData();
};
const handleCancel = () => {
restInfo();
visible.value = false;
};
const handleOk = () => {
if (!checked.value) {
return message.info('请至少选择一条');
}
emit('chooseEmploy', checked.value);
restInfo();
visible.value = false;
};
const searchBySearchInfo = () => {
pSet.value.current = 1;
checked.value = '';
initData();
};
const customRowF = (record) => {
return {
onClick: () => {
checked.value = JSON.stringify(record);
},
};
};
const restInfo = () => {
pSet.value.current = 1;
personData.value = [];
doctorName.value = '';
checked.value = '';
};
defineExpose({
showModal,
customRowF,
});
</script>
<style scoped lang="less">
.button-outer-div {
display: flex;
padding: 10px;
justify-content: center;
button {
padding: 15px 20px;
border-radius: 10px;
display: flex;
align-items: center;
}
> button:nth-child(1) {
margin-right: 10px;
}
> button:nth-child(2) {
margin-left: 10px;
}
}
:deep(.ant-form-item) {
margin-bottom: 0 !important;
width: 65px;
}
</style>
@@ -0,0 +1,363 @@
<template>
<div class="outer-s" style="position: relative">
<div style="height: 100%; width: 100%; overflow: auto; position: absolute; top: 0; left: 0; display: flex">
<div class="outer-inner-left">
<a-spin
class="iframe"
style="display: flex; align-items: center; justify-content: center"
tip="加载中..."
v-if="loadingVisible"
:spinning="loadingVisible"
/>
<!-- <iframe-->
<!-- v-show="!loadingVisible"-->
<!-- id="iframeRef"-->
<!-- ref="iframeRef"-->
<!-- class="iframe"-->
<!-- :src="`http://localhost:8080?isSpecialized=true&${qs.stringify(props.imProps)}&sessionId=${route.query?.sessionId}`"-->
<!-- ></iframe>-->
<iframe
v-show="!loadingVisible"
id="iframeRef"
ref="iframeRef"
class="iframe"
:src="`${imAddressSrc}isSpecialized=true&${qs.stringify(props.imProps)}&sessionId=${route.query?.sessionId}`"
></iframe>
</div>
<div class="outer-inner-right">
<a-row class="e-div">
<a-col class="col-des-o">
<div class="col-des"> 应急响应及时率 </div>
<div class="col-des-d">
{{ statInfo.timelinessRate ?? '0' + '%' }}
<div style="flex: 1">
<img style="width: 20px; height: 25px" src="../../../../assets/images/bg-1.png" alt="" />
</div>
</div>
</a-col>
<a-col class="col-des-t">
<div class="col-des"> 应急任务完成率 </div>
<div class="col-des-d">
{{ statInfo.completionRate ?? '0' + '%' }}
<div style="flex: 1">
<img style="width: 20px; height: 25px" src="../../../../assets/images/bg-2.png" alt="" />
</div>
</div>
</a-col>
<a-col class="col-des-tr">
<div class="col-des"> 值班小组 </div>
<div class="col-des-d">
{{ statInfo.dutyTeamNum ?? '0' }}
<div style="flex: 1">
<img style="width: 20px; height: 25px" src="../../../../assets/images/bg-3.png" alt="" />
</div>
</div>
</a-col>
<a-col class="col-des-f">
<div class="col-des"> 应急统计 </div>
<div class="col-des-d">
{{ statInfo.totalNum ?? '0' }}
<div style="flex: 1">
<img style="width: 20px; height: 25px" src="../../../../assets/images/bg-4.png" alt="" />
</div>
</div>
</a-col>
</a-row>
<a-row style="margin: 10px 0 0 20px">
<span style="font-size: 18px; font-weight: bold">值班</span>
</a-row>
<a-row class="calendar-row">
<a-calendar :weekStartsOn="3" :fullscreen="false" v-model:value="value" @panelChange="onPanelChange">
<template #headerRender="{ value: current, type, onChange, onTypeChange }">
<a-row style="display: flex; align-items: center; margin-bottom: 5px">
<a-col :span="8" style="font-size: 17px">
<div style="display: flex; cursor: pointer" @click="clickPreMonth(current, onChange)">
<div style="margin-right: 7px; display: flex; align-items: center; justify-content: center">
<svg
t="1684721034832"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="5243"
width="10"
height="10"
>
<path
d="M735.208665 65.582671l-446.41733 446.417329 446.41733 446.417329z"
p-id="5244"
fill="#999999"
/>
</svg>
</div>
上月
</div>
</a-col>
<a-col :span="8" style="display: flex; justify-content: center">
<span style="font-size: 17px; font-weight: 500; display: flex; align-items: center">
{{ String(current.year()) }}
<svg
t="1684735413489"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="6335"
width="10"
height="10"
>
<path
d="M96 512a32 32 0 0 1 32-32h768a32 32 0 0 1 0 64H128a32 32 0 0 1-32-32z"
fill="#303133"
p-id="6336"
/>
</svg>
{{ String(current.month() + 1) < 10 ? '0' + String(current.month() + 1) : String(current.month() + 1) }}
</span>
</a-col>
<a-col :span="8" style="font-size: 17px">
<div style="cursor: pointer; display: flex; justify-content: flex-end" @click="clickNextMonth(current, onChange)">
下月
<div style="margin-left: 7px; display: flex; align-items: center; justify-content: end">
<svg
t="1684720978954"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="4154"
width="10"
height="10"
>
<path
d="M288.791335 65.582671l446.41733 446.417329-446.41733 446.417329z"
p-id="4155"
fill="#999999"
/>
</svg>
</div>
</div>
</a-col>
</a-row>
</template>
<template #dateFullCellRender="{ current }">
<div class="calendar-d">
<div :class="[isBackG(current) ? 'date-background' : 'date-no-background']">
<span style="font-weight: 500">{{ current.date() }}</span>
</div>
</div>
</template>
</a-calendar>
</a-row>
<forHelpAdv :isSpecialized="true" ref="forHelpAdvRef" />
<detail ref="detailRef" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { Dayjs } from 'dayjs';
import detail from './detail.vue';
import { stat, scheduleRecordApi } from './commApi';
import forHelpAdv from './forHelpAdv.vue';
import moment from 'moment';
import qs from 'qs';
import { imAddressSrc } from '/@/utils/imAddressSrc';
import { useRoute } from 'vue-router';
const props = defineProps({
imProps: Object,
});
const route = useRoute();
moment.updateLocale('en', {
weekdaysMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
});
const value = ref<Dayjs>();
const detailRef = ref();
const statInfo = ref<Object>({});
const dayS = ref<Array>();
const loadingVisible = ref<Boolean>(true); // loading
const forHelpDetail = (res) => {
detailRef.value.showDrawer(res);
};
const onPanelChange = (value: Dayjs, mode: string) => {
console.log('click');
console.log(value);
console.log(mode);
};
const isBackG = (current) => {
return dayS.value?.includes(current.month() + 1 + '-' + current.date());
};
const clickPreMonth = (current, onChange) => {
onChange(current.month(current.month() - 1));
scheduleRecord(current.year(), current.month());
};
const clickNextMonth = (current, onChange) => {
onChange(current.month(current.month() + 1));
scheduleRecord(current.year(), current.month() + 2);
};
const forHelpAdvRef = ref();
const forHelp = (userId, isDisabled) => {
forHelpAdvRef.value.showModal(userId, isDisabled);
};
window.onmessage = (msg) => {
const result = JSON.parse(msg.data);
switch (result.code) {
case 'forHelp':
forHelp(result.userId, result.isDisabled);
break;
case 'forHelpDetail':
forHelpDetail(result.userId);
break;
case 'closeLoading':
closeLoading();
break;
}
};
const closeLoading = () => {
loadingVisible.value = false;
};
const initStat = () => {
const params = {
personType: '7',
};
stat(params)
.then((res) => {
statInfo.value = res;
})
.catch((e) => {
console.log(e);
});
};
const scheduleRecord = (year, month) => {
if (month * 1 === 13) {
year = year * 1 + 1;
month = 1;
}
if (month * 1 === 0) {
year = year * 1 - 1;
month = 12;
}
const params = {
year: year,
month: month,
};
scheduleRecordApi(params)
.then((res) => {
if (res.months !== null) {
let result = [];
res.months.forEach((item) => {
item.days.forEach((it) => {
result.push(item.month + '-' + it.day);
});
});
dayS.value = result;
}
})
.catch((e) => {
console.log(e);
});
};
const nowDate = new Date();
scheduleRecord(nowDate.getFullYear(), nowDate.getMonth() + 1);
initStat();
</script>
<style scoped lang="less">
.outer-s {
height: 100% !important;
display: flex;
padding: 0 5px 0 0;
}
.iframe {
width: 100%;
height: 100%;
overflow: hidden;
}
.outer-inner-left,
.outer-inner-right {
height: 100%;
overflow: auto;
}
.outer-inner-left {
width: calc(100% - 370px);
}
.outer-inner-right {
width: 370px;
border-left: 2px solid #f9f9f9;
background: #ffffff;
}
.e-div {
display: flex;
}
.col-des,
.col-des-d {
padding: 0 10px !important;
display: flex;
align-items: center;
justify-content: space-between;
}
//.ant-col {
// padding: 10px 10px;
//}
.col-des {
height: 34px;
font-size: 10px;
align-items: flex-end;
}
.col-des-d {
align-items: flex-start;
height: 42px;
font-size: 20px;
> :nth-child(1) {
display: flex;
height: 100%;
justify-content: flex-end;
align-items: center;
padding-right: 5px;
}
}
.col-des,
.col-des-d {
color: #ffffff;
}
.col-des-o {
background-color: #ffa845;
}
.col-des-t {
background-color: #4ad246;
}
.col-des-tr {
background-color: #0093fe;
}
.col-des-f {
background-color: #8068f2;
}
.col-des-o,
.col-des-t,
.col-des-tr,
.col-des-f {
width: calc(50% - 10px);
margin: 10px 0 0 5px;
border-radius: 15px;
}
.calendar-row {
padding: 0 10px;
margin-top: 5px;
}
.date-background {
background-color: #dae0ff;
border-radius: 10px;
}
.date-no-background,
.date-background {
padding: 5px 0;
}
.calendar-d {
padding: 5px;
}
</style>
@@ -0,0 +1,66 @@
<template>
<a-drawer v-model:visible="visible" class="custom-class" style="color: red; overflow: auto" title="补充小节" width="40%" placement="right">
<a-descriptions title="补充小节" :column="2">
<!-- <a-descriptions-item label="病情记录" :span="2">-->
<!-- <a-textarea v-model:value="readR" placeholder="" :rows="5"></a-textarea>-->
<!-- </a-descriptions-item>-->
<a-descriptions-item label="应急过程" :span="2">
<a-textarea v-model:value="passR" placeholder="" :rows="5" />
</a-descriptions-item>
<a-descriptions-item label="应急结果" :span="2">
<a-textarea v-model:value="resultR" placeholder="" :rows="5" />
</a-descriptions-item>
</a-descriptions>
<div style="display: flex; justify-content: center">
<a-button type="primary" size="small" class="bottom-button" @click="saveInfo" :loading="confirmLoading"> 保存 </a-button>
</div>
</a-drawer>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { supplementApi } from '/@/views/emergency/communication/components/commApi';
const visible = ref<Boolean>(false);
const confirmLoading = ref<Boolean>(false);
const readR = ref<String>('');
const passR = ref<String>('');
const resultR = ref<String>('');
const pId = ref<String>('');
const emit = defineEmits(['saveInfo']);
const showSuppDrawer = (id, orderThrough, orderResult) => {
readR.value = '';
passR.value = orderThrough;
resultR.value = orderResult;
pId.value = id;
visible.value = true;
};
const saveInfo = () => {
confirmLoading.value = true;
const params = {
id: pId.value,
orderRecord: readR.value,
orderThrough: passR.value,
orderResult: resultR.value,
};
supplementApi(params)
.then(() => {
confirmLoading.value = false;
visible.value = false;
emit('saveInfo', { readR: readR, passR: passR, resultR: resultR });
})
.catch((e) => {
confirmLoading.value = false;
console.log(e);
});
};
defineExpose({
showSuppDrawer,
});
</script>
<style scoped lang="less">
.bottom-button {
display: flex;
align-items: center;
padding: 15px 20px;
}
</style>
@@ -0,0 +1,52 @@
<template>
<div class="outer">
<specialized :imProps="imProps" v-if="isSpecialized === '6'" />
<opearate :imProps="imProps" v-if="isSpecialized === '5'" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import specialized from './components/specialized.vue';
import opearate from './components/operate.vue';
import { userSigAndroidApi } from '/@/views/emergency/communication/components/commApi';
import { getToken } from '/@/utils/auth';
import { useGlobSetting } from '/@/hooks/setting';
import { useUserStore } from '/@/store/modules/user';
const isSpecialized = ref<String>('');
const imProps = ref<Object>({
sdkAppId: '',
userSig: '',
tokenF: getToken(),
userId: '',
urlF: '',
});
const userStore = useUserStore();
isSpecialized.value = userStore.getUserInfo.personType;
const globSetting = useGlobSetting();
const apiUrl = globSetting.apiUrl;
imProps.value.urlF = apiUrl.replace('://', 'lol');
const getSig = () => {
userSigAndroidApi({})
.then((res) => {
imProps.value.userSig = res.userSig;
imProps.value.sdkAppId = res.sdkAppId;
imProps.value.userId = res.userId;
})
.catch((e) => {
console.log(e);
});
};
getSig();
</script>
<style scoped lang="less">
.outer {
width: 100%;
height: 100%;
}
</style>
@@ -0,0 +1,70 @@
<template>
<BasicDrawer @register="registerDrawer" width="500" title="详情">
<!-- <template v-for="(item, index) in columns" :key="`emergency-center-${index}`">-->
<!-- <div class="list-d" v-if="!item.show">-->
<!-- <template v-if="item.dataIndex === 'status'">-->
<!-- <div class="list-d-label">{{ item.title }}</div>-->
<!-- <div class="list-d-value">{{ info[item.dataIndex] == '0' ? '开启' : '关闭' }}</div>-->
<!-- </template>-->
<!-- <template v-else-if="item.dataIndex === 'defaultCenter'">-->
<!-- <div class="list-d-label">{{ item.title }}</div>-->
<!-- <div class="list-d-value">{{ info[item.dataIndex] ? '是' : '否' }}</div>-->
<!-- </template>-->
<!-- <template v-else-if="item.dataIndex === 'operatorsNum'">-->
<!-- <div class="list-d-label">{{ item.title }}</div>-->
<!-- <div class="list-d-value">{{ info[item.dataIndex] || 0 }}</div>-->
<!-- </template>-->
<!-- <template v-else-if="item.dataIndex === 'openTimes'">-->
<!-- <div class="list-d-label">{{ item.title }}</div>-->
<!-- <div class="list-d-value">-->
<!-- <div v-if="info[item.dataIndex] && info[item.dataIndex].length > 0">-->
<!-- <div-->
<!-- v-for="(it, i) in info[item.dataIndex]"-->
<!-- :key="`openTime-${i}`"-->
<!-- :style="{ paddingBottom: i === info[item.dataIndex].length - 1 ? '' : '10px' }"-->
<!-- >-->
<!-- {{ `${it['openTimeStart']} ~ ${it['openTimeEnd']}` }}-->
<!-- </div>-->
<!-- </div>-->
<!-- <template v-else> &#45;&#45; </template>-->
<!-- </div>-->
<!-- </template>-->
<!-- <template v-else-if="item.dataIndex === 'professionalsNum'">-->
<!-- <div class="list-d-label">{{ item.title }}</div>-->
<!-- <div class="list-d-value">{{ info[item.dataIndex] || 0 }}</div>-->
<!-- </template>-->
<!-- <template v-else>-->
<!-- <div class="list-d-label">{{ item.title }}</div>-->
<!-- <div class="list-d-value">{{ info[item.dataIndex] || '&#45;&#45;' }}</div>-->
<!-- </template>-->
<!-- </div>-->
<!-- </template>-->
<Description :schema="descItems" :data="info" :labelStyle="{ width: '160px' }" :column="1" :contentStyle="{ width: '340px' }" />
</BasicDrawer>
</template>
<script setup lang="ts">
import BasicDrawer from '/@/components/Drawer/src/BasicDrawer.vue';
import { useDrawerInner } from '/@/components/Drawer';
import { columns, descItems } from '/@/views/emergency/emergencyManage/emergencyManage.data';
import { ref } from 'vue';
import Description from '/@/components/Description/src/Description.vue';
const info = ref({});
const [registerDrawer, {}] = useDrawerInner((data) => {
info.value = data.record;
});
</script>
<style scoped lang="less">
.list-d {
display: flex;
padding: 5px;
.list-d-label {
width: 150px;
text-align: right;
}
.list-d-value {
width: calc(100% - 150px);
}
}
</style>
@@ -0,0 +1,274 @@
<template>
<BasicDrawer @register="registerDrawer" width="700" :title="isUpdate ? '修改应急中心' : '新增应急中心'" @ok="handleSubmit" :showFooter="true">
<BasicForm @register="registerForm">
<template #addressInfo="{ model }">
<a-input style="width: calc(100% - 100px)" v-model:value="model['address']" :disabled="true" />
<a-button style="margin-left: 10px" @click="viewMap"> 查看地图</a-button>
</template>
<!-- <template #orgCode="{ model }">-->
<!-- <a-tree-select-->
<!-- v-model:value="model['orgCode']"-->
<!-- tree-data-simple-mode-->
<!-- style="width: 100%"-->
<!-- :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"-->
<!-- :tree-data="treeData1"-->
<!-- placeholder="请选择管理单位"-->
<!-- :load-data="whichOnLoad1"-->
<!-- :selectedKeys="selectedKeys1"-->
<!-- :fieldNames="{-->
<!-- value: 'orgCode',-->
<!-- label: 'preTitle',-->
<!-- key: 'orgCode',-->
<!-- }"-->
<!-- show-search-->
<!-- tree-node-filter-prop="preTitle"-->
<!-- />-->
<!-- </template>-->
<template #openTimes>
<template v-if="listTimes.length > 0">
<div v-for="(item, index) in listTimes" :key="`openTime-${index}`" style="padding-bottom: 10px">
<a-time-picker v-model:value="item['openTimeStart']" value-format="HH:mm" format="HH:mm" /> ~
<a-time-picker v-model:value="item['openTimeEnd']" value-format="HH:mm" format="HH:mm" />
<a-button type="text" style="color: red" @click="delListTimes(index)"> 删除 </a-button>
<a-button type="text" style="color: #1890ff" v-if="index === listTimes.length - 1" @click="addListTimes"> 添加 </a-button>
</div>
</template>
<template v-else>
<a-button type="text" style="color: #1890ff; margin-left: 5px" @click="addListTimes"> 添加 </a-button>
</template>
</template>
<template #serviceScope="{ model }">
<a-tree-select
v-model:value="model['serviceScope']"
tree-data-simple-mode
style="width: 100%"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
:tree-data="treeData2"
placeholder="请选择服务范围"
:selectedKeys="selectedKeys2"
:expandedKeys="expandedKeys2"
multiple
:load-data="whichOnLoad2"
:fieldNames="{
value: 'orgCode',
label: 'preTitle',
key: 'orgCode',
}"
show-search
tree-node-filter-prop="preTitle"
/>
</template>
</BasicForm>
</BasicDrawer>
<Map @register="registerMap" :state="state" ref="map" @get-position="getPosition" />
</template>
<script setup lang="ts">
import BasicDrawer from '/@/components/Drawer/src/BasicDrawer.vue';
import { useDrawerInner } from '/@/components/Drawer';
import BasicForm from '/@/components/Form/src/BasicForm.vue';
import { useForm } from '/@/components/Form';
import { schemas } from '/@/views/emergency/emergencyManage/emergencyManage.data';
import Map from '/@/views/consult/resource/components/Map.vue';
import { ref } from 'vue';
import { useModal } from '/@/components/Modal';
import { queryDepartTreeSync } from '/@/views/system/depart/depart.api';
import { addCenterApi, updateCenterApi } from '/@/views/emergency/emergencyManage/emergencyManage.api';
import { merge } from 'lodash-es';
const emit = defineEmits(['success']);
const isUpdate = ref(false);
const state = ref({});
const listTimes = ref<any[]>([]);
// const selectedKeys1 = ref('');
const selectedKeys2 = ref<any[]>([]);
// const expandedKeys1 = ref('');
const expandedKeys2 = ref<any[]>([]);
// const treeData1 = ref<any[]>([]);
const treeData2 = ref<any[]>([]);
const [registerMap, { openModal }] = useModal();
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
await resetFields();
listTimes.value = [];
isUpdate.value = data.isUpdate;
if (isUpdate.value) {
// selectedKeys1.value = data.record.orgCode;
selectedKeys2.value = data.record.serviceScope ? data.record.serviceScope.split(',') : [];
listTimes.value = data.record?.openTimes || [];
await setFieldsValue({
...data.record,
serviceScope: data.record.serviceScope ? data.record.serviceScope.split(',') : [],
openTimes: listTimes.value.length > 0 ? '123' : undefined,
});
await clearValidate();
}
await loadRootTreeData();
});
const [registerForm, { getFieldsValue, setFieldsValue, resetFields, validate, clearValidate }] = useForm({
schemas: schemas,
showActionButtonGroup: false,
});
function addListTimes() {
listTimes.value.push({ openTimeStart: '', openTimeEnd: '' });
setFieldsValue({
openTimes: '123',
});
}
function delListTimes(index) {
if (listTimes.value.length === 1) {
setFieldsValue({
openTimes: undefined,
});
}
listTimes.value.splice(index, 1);
}
async function loadRootTreeData() {
try {
// treeData1.value = [];
treeData2.value = [];
const fResult = await queryDepartTreeSync({});
if (!fResult || fResult.length < 0) return;
const result = await queryDepartTreeSync({ pid: fResult[0].id });
if (Array.isArray(result)) {
result.forEach((item: any) => {
item['preTitle'] = item.title;
item['key'] = item['orgCode'];
});
// treeData1.value = merge(result);
treeData2.value = merge(result);
// if (selectedKeys1.value) {
// try {
// await getChildren(treeData1.value, selectedKeys1.value.split(','));
// } catch {}
// }
if (selectedKeys2.value) {
try {
await getChildren(treeData2.value, selectedKeys2.value);
} catch {}
}
}
} catch {}
}
async function getChildren(list: any[], selectKeys: any[]) {
for (let i = 0; i < list.length; i++) {
for (let j = 0; j < selectKeys.length; j++) {
if (selectKeys[j].indexOf(list[i].orgCode) !== -1 && list[i].orgCode !== selectKeys[j]) {
if (list[i].children && list[i].children.length > 0) {
await getChildren(list[i].children, selectKeys);
} else {
try {
list[i].children = (await queryDepartTreeSync({ pid: list[i].id })).map((item: any) => {
item['preTitle'] = list[i]['preTitle'] + '/' + item.title;
item['key'] = item['orgCode'];
return item;
});
await getChildren(list[i].children || [], selectKeys);
} catch (e) {
console.log(e);
}
}
}
}
}
}
function preData(data, id, res) {
for (let i = 0; i < data.length; i++) {
if (data[i]?.id === id) {
data[i].children = res;
return;
}
preData(data[i].children, id, res);
}
}
// async function whichOnLoad1(treeNode: any) {
// await onLoadData(treeNode, '0');
// }
async function whichOnLoad2(treeNode: any) {
await onLoadData(treeNode);
}
async function onLoadData(treeNode) {
try {
const result = await queryDepartTreeSync({
pid: treeNode.dataRef.id,
});
treeNode.dataRef.children = result.map((item: any) => {
item['pId'] = treeNode.dataRef.id;
item['preTitle'] = treeNode.dataRef.preTitle + '/' + item.title;
item['key'] = item['orgCode'];
return item;
});
preData(
treeData2.value,
treeNode.dataRef.id,
result.map((item: any) => {
item['pId'] = treeNode.dataRef.id;
item['key'] = item['orgCode'];
return item;
})
);
} catch (e) {
console.error(e);
}
return Promise.resolve(true);
}
async function getPosition(val) {
let { pname, cityname, adname, address, name } = val.handleItem || '';
let nameList = [pname, cityname, adname, address, name];
let str = '';
nameList.map((item) => {
if (item !== undefined) {
str += item;
}
});
await setFieldsValue({
latitude: val.lat,
longitude: val.lng,
address: str,
});
state.value = {
...state.value,
latitude: val.lat,
longitude: val.lng,
address: str,
};
}
function viewMap() {
openModal(true, {
record: { ...getFieldsValue(), ...state.value, lat: getFieldsValue().latitude, lng: getFieldsValue().longitude },
});
}
async function handleSubmit() {
try {
const value = await validate();
value['openTimes'] = listTimes.value;
setDrawerProps({ confirmLoading: true });
if (!value?.centerHeadTel) delete value['centerHeadTel'];
if (isUpdate.value) {
await updateCenterApi(value);
} else {
await addCenterApi({ ...value, status: '1' });
}
closeDrawer();
setDrawerProps({ confirmLoading: false });
emit('success');
} catch {
setDrawerProps({ confirmLoading: false });
}
}
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,245 @@
<template>
<BasicModal @register="registerModal" width="800px" :title="`应急中心${info.adminType == '0' ? '' : '大屏'}管理员`">
<div style="height: 60vh">
<div class="top-d">
<div class="top-item-d"> 中心名称{{ info.centerName }} </div>
<div class="top-item-d"> 管理单位{{ info.secondDepart }} </div>
<div class="top-item-d"> 详细地址{{ info.address }} </div>
</div>
<BasicTable @register="registerTable">
<template #tableTitle>
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="addB"> 新增 </a-button>
<a-button type="primary" @click="chooseUser"> 选择用户 </a-button>
</template>
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
</BasicTable>
</div>
</BasicModal>
<emergency-manager-modal-modal @register="registerModalModal" @success="handleSuccess" />
<ChooseSome
:width="800"
ref="chooseMedical"
@register="userDrawer"
@select-some="onSelectUserOk"
title="选择指定员工"
:tableprops="userTableProp"
selection-type="checkbox"
:params-info="{ centerId: info.id }"
:async-func="true"
/>
<!-- 重置密码 -->
<RestPass @register="restPassModal" />
</template>
<script setup lang="ts">
import BasicModal from '/@/components/Modal/src/BasicModal.vue';
import { useModal, useModalInner } from '/@/components/Modal';
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import {
managerColumns,
managerSearchSchema,
managerChooseColumns,
managerChooseSearchSchema,
} from '/@/views/emergency/emergencyManage/emergencyManage.data';
import { addBatchCenterAdminApi, adminListApi, chooseUserApi, delAdminApi } from '/@/views/emergency/emergencyManage/emergencyManage.api';
import { ref } from 'vue';
import EmergencyManagerModalModal from '/@/views/emergency/emergencyManage/components/emergencyManagerModalModal.vue';
import { TableAction } from '/@/components/Table';
import ChooseSome from '/@/views/compoents/chooseSome/index.vue';
import { useDrawer } from '/@/components/Drawer';
import RestPass from '/@/views/system/user/restPass/RestPass.vue';
const info = ref({});
const chooseMedical = ref();
async function onSelectUserOk(v) {
try {
const params = v.map((item) => {
return {
...JSON.parse(item),
centerId: info.value.id,
adminType: info.value.adminType,
};
});
await addBatchCenterAdminApi({ admins: params });
chooseMedical.value.closeDrawerInfo();
await reload();
} catch {
chooseMedical.value.confirmLoadingFalse();
}
}
const userTableProp = ref({
api: chooseUserApi,
columns: managerChooseColumns,
immediate: false,
canResize: false,
showIndexColumn: true,
rowKey: (record: Recordable) => {
return JSON.stringify({ userId: record?.id, username: record?.username, realname: record?.realname });
},
rowSelection: {
getCheckboxProps(record: Recordable) {
// Demo: 第一行(id为0)的选择框禁用
if (record.personType !== '0' && record.personType !== '1') {
return { disabled: false };
} else {
return { disabled: true };
}
},
},
formConfig: {
schemas: managerChooseSearchSchema,
autoSubmitOnEnter: true,
showAdvancedButton: false,
fieldMapToNumber: [],
fieldMapToTime: [],
labelWidth: 100,
actionColOptions: {
style: {
paddingLeft: '104px',
},
span: 24,
offset: 0,
xs: 24,
sm: 24,
md: 12,
lg: 12,
xl: 12,
xxl: 12,
},
baseColProps: {
xs: 24,
sm: 24,
md: 12,
lg: 12,
xl: 12,
xxl: 12,
},
},
actionColumn: {
width: 180,
fixed: 'right',
},
});
const [userDrawer, { openDrawer }] = useDrawer();
const [registerModalModal, { openModal }] = useModal();
const [restPassModal, { openModal: resetPasswordModal }] = useModal();
const [registerModal, { setModalProps }] = useModalInner(async (data) => {
setModalProps({ showCancelBtn: false, showOkBtn: false });
info.value = { ...data.record, adminType: data.adminType };
setProps({
searchInfo: { centerId: data.record?.id, type: data.adminType },
});
await reload();
});
const { tableContext } = useListPage({
tableProps: {
title: '应急中心管理-管理员',
api: adminListApi,
columns: managerColumns,
immediate: false,
canResize: false,
showIndexColumn: true,
formConfig: {
schemas: managerSearchSchema,
autoSubmitOnEnter: true,
showAdvancedButton: false,
fieldMapToNumber: [],
fieldMapToTime: [],
actionColOptions: {
span: 24,
offset: 0,
xs: 24,
sm: 24,
md: 12,
lg: 12,
xl: 12,
xxl: 12,
},
baseColProps: {
xs: 24,
sm: 24,
md: 12,
lg: 12,
xl: 12,
xxl: 12,
},
},
actionColumn: {
width: 180,
fixed: 'right',
},
},
});
const [registerTable, { setProps, reload }] = tableContext;
function addB() {
openModal(true, {
record: { centerId: info.value.id, adminType: info.value.adminType },
title: info.value.adminType == '1' ? '新增大屏账号' : '新增管理员',
isUpdate: false,
});
}
function chooseUser() {
openDrawer(true, {});
}
function handleSuccess() {
reload();
}
function getTableAction(record: Recordable) {
return [
{
label: '重置密码',
onClick: resetPassword.bind(null, record),
},
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
{
label: '删除',
onClick: handleDel.bind(null, record),
},
];
}
function resetPassword(record: Recordable) {
resetPasswordModal(true, {
record: record.userId,
isUpdate: true,
showFooter: false,
});
}
function handleEdit(record: Recordable) {
openModal(true, {
record: { centerId: info.value.id, adminType: info.value.adminType, ...record },
title: info.value.adminType == '1' ? '新增大屏账号' : '新增管理员',
isUpdate: true,
});
}
function handleDel(record: Recordable) {
delAdminApi(record, reload);
}
</script>
<style scoped lang="less">
.top-d {
flex-wrap: wrap;
display: flex;
.top-item-d {
padding: 0 20px;
width: 50%;
&:nth-child(3) {
width: 100%;
}
}
}
</style>
@@ -0,0 +1,67 @@
<template>
<BasicModal @register="registerModal" :title="title" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script setup lang="ts">
import BasicForm from '/@/components/Form/src/BasicForm.vue';
import { useForm } from '/@/components/Form';
import { managerSchema } from '/@/views/emergency/emergencyManage/emergencyManage.data';
import BasicModal from '/@/components/Modal/src/BasicModal.vue';
import { useModalInner } from '/@/components/Modal';
import { ref } from 'vue';
import { addCenterAdminApi, updateAdminApi } from '/@/views/emergency/emergencyManage/emergencyManage.api';
import { dealParams } from '/@/views/system/user/user.data';
const emit = defineEmits(['success']);
const title = ref('');
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
await resetFields();
await setFieldsValue({ ...data.record });
await clearValidate();
if (data.isUpdate) {
await updateSchema({
field: 'username',
componentProps: () => {
return {
disabled: true,
};
},
});
} else {
await updateSchema({
field: 'username',
componentProps: () => {
return {
disabled: false,
};
},
});
}
title.value = data.title;
});
const [registerForm, { setFieldsValue, validate, resetFields, clearValidate, updateSchema }] = useForm({
schemas: managerSchema,
showActionButtonGroup: false,
});
async function handleSubmit() {
try {
const values = await validate();
setModalProps({ confirmLoading: true });
if (values?.id) {
await updateAdminApi(values);
} else {
await addCenterAdminApi(dealParams(values));
}
setModalProps({ confirmLoading: false });
emit('success');
closeModal();
} catch {
setModalProps({ confirmLoading: false });
}
}
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,156 @@
<template>
<BasicModal @register="registerModal" destroy-on-close width="800px" title="关联医疗点">
<div style="height: 60vh">
<div class="top-d">
<div class="top-item-d"> 中心名称{{ info.centerName }} </div>
<div class="top-item-d"> 管理单位{{ info.centerHeadName }} </div>
<div class="top-item-d"> 详细地址{{ info.address }} </div>
</div>
<BasicTable @register="registerTable" :row-selection="rowSelection">
<template #tableTitle>
<a-button type="primary" @click="chooseUser" v-auth="'emergency:emergency_center_resource:add'"> 选择医疗点 </a-button>
<a-button
type="primary"
@click="largeDel"
preIcon="ant-design:delete-outlined"
v-auth="'emergency:emergency_center_resource:deleteBatch'"
>
批量取消关联
</a-button>
</template>
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
</BasicTable>
</div>
</BasicModal>
<ChooseSome
ref="chooseMedical"
:width="800"
@register="userDrawer"
@select-some="onSelectUserOk"
title="选择医疗点"
:tableprops="medicalTableProp"
selection-type="checkbox"
:async-func="true"
/>
<!-- 重置密码 -->
</template>
<script setup lang="ts">
import BasicModal from '/@/components/Modal/src/BasicModal.vue';
import { useModalInner } from '/@/components/Modal';
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import { medicalColumns, medicalTableProp, searchMedicalSchema } from '/@/views/emergency/emergencyManage/emergencyManage.data';
import {
emergencyCenterResourceAddApi,
emergencyCenterResourceApi,
medicalDeleteApi,
medicalDeleteBatchApi,
} from '/@/views/emergency/emergencyManage/emergencyManage.api';
import { ref } from 'vue';
import { TableAction } from '/@/components/Table';
import ChooseSome from '/@/views/compoents/chooseSome/index.vue';
import { useDrawer } from '/@/components/Drawer';
const info = ref({});
const chooseMedical = ref();
async function onSelectUserOk(v: any) {
try {
await emergencyCenterResourceAddApi({ emergencyCenterId: info.value.id, resources: v });
chooseMedical.value.closeDrawerInfo();
await reload();
} catch {
chooseMedical.value.confirmLoadingFalse();
}
}
const [userDrawer, { openDrawer }] = useDrawer();
const [registerModal, { setModalProps }] = useModalInner(async (data) => {
setModalProps({ showCancelBtn: false, showOkBtn: false });
info.value = data.record;
setProps({
searchInfo: { emergencyCenterId: data.record?.id },
});
await reload();
});
const { tableContext } = useListPage({
tableProps: {
title: '应急中心管理-管理员',
api: emergencyCenterResourceApi,
columns: medicalColumns,
immediate: false,
canResize: false,
showIndexColumn: true,
formConfig: {
schemas: searchMedicalSchema,
autoSubmitOnEnter: true,
showAdvancedButton: false,
fieldMapToNumber: [],
fieldMapToTime: [],
labelWidth: 100,
actionColOptions: {
style: {
paddingLeft: '104px',
},
span: 24,
offset: 0,
xs: 24,
sm: 24,
md: 12,
lg: 12,
xl: 12,
xxl: 12,
},
baseColProps: {
xs: 24,
sm: 24,
md: 12,
lg: 12,
xl: 12,
xxl: 12,
},
},
actionColumn: {
width: 80,
fixed: 'right',
},
},
});
const [registerTable, { setProps, reload }, { rowSelection, selectedRowKeys }] = tableContext;
function chooseUser() {
openDrawer(true, {});
}
function getTableAction(record: Recordable) {
return [
{
label: '取消关联',
onClick: handleDel.bind(null, record),
auth: 'emergency:emergency_center_resource:delete',
},
];
}
function handleDel(record: Recordable) {
medicalDeleteApi({ medicalResourceId: record.id, emergencyCenterId: info.value.id }, reload);
}
function largeDel() {
medicalDeleteBatchApi({ medicalResourceIds: selectedRowKeys.value, emergencyCenterId: info.value.id }, reload);
}
</script>
<style scoped lang="less">
.top-d {
flex-wrap: wrap;
display: flex;
.top-item-d {
padding: 0 20px;
width: 50%;
&:nth-child(3) {
width: 100%;
}
}
}
</style>
@@ -0,0 +1,91 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
enum Api {
list = '/health-emergency/emergency/center/list',
addCenter = '/health-emergency/emergency/center/addCenter',
delCenter = '/health-emergency/emergency/center/delCenter',
updateCenter = '/health-emergency/emergency/center/updateCenter',
updateCenterStatus = '/health-emergency/emergency/center/updateCenterStatus',
settingDefaultCenter = '/health-emergency/emergency/center/settingDefaultCenter',
export = '/health-emergency/emergency/center/export',
adminList = '/health-emergency/emergency/center/admin/list',
addCenterAdmin = '/health-emergency/emergency/center/admin/addCenterAdmin',
updateAdmin = '/health-emergency/emergency/center/admin/updateAdmin',
delAdmin = '/health-emergency/emergency/center/admin/delAdmin',
chooseUser = '/health-emergency/emergency/center/admin/chooseUser',
emergencyCenterResource = '/health-emergency/emergency/emergencyCenterResource/list',
selectResourceByHospitalNew = '/medical-center/medicalCenter/medicalResource/selectResourceByHospitalNew',
emergencyCenterResourceAdd = '/health-emergency/emergency/emergencyCenterResource/add',
medicalDelete = '/health-emergency/emergency/emergencyCenterResource/delete',
medicalDeleteBatch = '/health-emergency/emergency/emergencyCenterResource/deleteBatch',
addBatchCenterAdmin = '/health-emergency/emergency/center/admin/addBatchCenterAdmin',
}
export const listApi = (params: any) => defHttp.get({ url: Api.list, params });
export const addCenterApi = (params: any) => defHttp.post({ url: Api.addCenter, params });
export const delCenterApi = (params: any, handleSuccess: any) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await defHttp.post({ url: Api.delCenter, params });
handleSuccess();
},
});
};
export const updateCenterApi = (params: any) => defHttp.post({ url: Api.updateCenter, params });
export const updateCenterStatusApi = (params: any) => defHttp.post({ url: Api.updateCenterStatus, params });
export const settingDefaultCenterApi = (params: any) => defHttp.get({ url: Api.settingDefaultCenter, params });
export const exportApi = (params: any) => defHttp.get({ url: Api.export, params });
export const adminListApi = (params: any) => defHttp.get({ url: Api.adminList, params });
export const addCenterAdminApi = (params: any) => defHttp.post({ url: Api.addCenterAdmin, params });
export const updateAdminApi = (params: any) => defHttp.post({ url: Api.updateAdmin, params });
export const delAdminApi = (params: any, handleSuccess: any) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await defHttp.post({ url: Api.delAdmin, params });
handleSuccess();
},
});
};
export const chooseUserApi = (params: any) => defHttp.get({ url: Api.chooseUser, params });
export const emergencyCenterResourceApi = (params: any) => defHttp.post({ url: Api.emergencyCenterResource, params });
export const selectResourceByHospitalNewApi = (params: any) => defHttp.get({ url: Api.selectResourceByHospitalNew, params });
export const emergencyCenterResourceAddApi = (params: any) => defHttp.post({ url: Api.emergencyCenterResourceAdd, params });
export const addBatchCenterAdminApi = (params: any) => defHttp.post({ url: Api.addBatchCenterAdmin, params });
export const medicalDeleteApi = (params: any, handleSuccess: any) => {
createConfirm({
iconType: 'warning',
title: '确认移除',
content: '是否移除选中医疗点',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await defHttp.delete({ url: Api.medicalDelete, params }, { joinParamsToUrl: true });
handleSuccess();
},
});
};
export const medicalDeleteBatchApi = (params: any, handleSuccess: any) => {
createConfirm({
iconType: 'warning',
title: '确认移除',
content: '是否移除选中医疗点',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await defHttp.delete({ url: Api.medicalDeleteBatch, params });
handleSuccess();
},
});
};
@@ -0,0 +1,662 @@
import { BasicColumn, FormSchema } from '/@/components/Table';
import { checkPassword } from '/@/hooks/checkPassword/checkPassword';
import { rules } from '/@/utils/helper/validator';
import { allSecondaryDepartsNew, allSecondaryDepartsNewBack } from '/@/utils/orgSearchInfo';
import { selectResourceByHospitalNewApi } from '/@/views/emergency/emergencyManage/emergencyManage.api';
import { DescItem } from '/@/components/Description';
import { h } from 'vue';
import { useUserStore } from '/@/store/modules/user';
import { FormActionType } from '/@/components/Form';
const { getUserInfo } = useUserStore();
export const columns: BasicColumn[] = [
{
title: '中心名称',
dataIndex: 'centerName',
align: 'center',
fixed: 'left',
},
{
title: '大屏标题',
dataIndex: 'screenTitle',
align: 'center',
fixed: 'left',
},
{
title: '简称',
dataIndex: 'simpleName',
align: 'center',
fixed: 'left',
},
{
title: '管理单位',
dataIndex: 'secondDepart',
align: 'center',
},
// {
// title: '大屏地址',
// dataIndex: 'screenUrl',
// align: 'center',
// },
{
title: '详细地址',
dataIndex: 'address',
align: 'center',
},
{
title: '中心电话',
dataIndex: 'centerTel',
align: 'center',
},
{
title: '值班电话',
dataIndex: 'dutyPhone',
},
{
title: '上班时间',
dataIndex: 'openTimes',
width: 0,
},
{
title: '服务范围',
dataIndex: 'serviceScopeTr',
align: 'center',
width: 0,
},
{
title: '负责人',
dataIndex: 'centerHeadName',
align: 'center',
},
{
title: '负责人电话',
dataIndex: 'centerHeadTel',
align: 'center',
},
{
title: '建成日期',
dataIndex: 'completionTime',
align: 'center',
},
{
title: '投用日期',
dataIndex: 'commissioningTime',
align: 'center',
},
{
title: '配备全额(万元)',
dataIndex: 'equipmentAmount',
align: 'center',
},
{
title: '操作人员',
dataIndex: 'operatorsNum',
align: 'center',
customRender: ({ text }) => {
return text || 0;
},
},
{
title: '专业人员',
dataIndex: 'professionalsNum',
align: 'center',
customRender: ({ text }) => {
return text || 0;
},
},
{
title: '开启状态',
dataIndex: 'status',
align: 'center',
fixed: 'right',
width: 80,
},
{
title: '是否为默认中心',
dataIndex: 'defaultCenter',
align: 'center',
fixed: 'right',
width: 120,
},
];
export const descItems: DescItem[] = [
{
label: '中心名称',
field: 'centerName',
},
{
label: '大屏标题',
dataIndex: 'screenTitle',
},
{
label: '简称',
field: 'simpleName',
},
{
label: '管理单位',
field: 'secondDepart',
},
{
label: '大屏路由',
field: 'screenPath',
show: () => getUserInfo.roleCodes?.indexOf('admin') !== -1,
},
{
label: '详细地址',
field: 'address',
},
{
label: '中心电话',
field: 'centerTel',
},
{
label: '值班电话',
field: 'dutyPhone',
},
{
label: '上班时间',
field: 'openTimes',
render: (val) => {
let result = '--';
if (val) {
result = '';
val.forEach((item, index) => {
result = result + `${index !== 0 ? ',' : ''}${item.openTimeStart} ~ ${item.openTimeEnd}`;
});
}
return result;
},
},
{
label: '服务范围',
field: 'serviceScopeTr',
},
{
label: '负责人',
field: 'centerHeadName',
},
{
label: '负责人电话',
field: 'centerHeadTel',
},
{
label: '建成日期',
field: 'completionTime',
},
{
label: '投用日期',
field: 'commissioningTime',
},
{
label: '配备全额(万元)',
field: 'equipmentAmount',
},
{
label: '操作人员',
field: 'operatorsNum',
render: (val) => {
return val || 0;
},
},
{
label: '专业人员',
field: 'professionalsNum',
render: (val) => {
return val || 0;
},
},
{
label: '开启状态',
field: 'status',
render: (val) => {
return val == '0' ? '开启' : '关闭';
},
},
{
label: '是否为默认中心',
field: 'defaultCenter',
render: (val) => {
return val ? '是' : '否';
},
},
];
export const searchSchema: FormSchema[] = [
{
label: '中心名称',
field: 'name',
component: 'Input',
},
{
label: '管理单位',
field: 'orgCode',
component: 'ApiSelect',
componentProps: () => {
return {
api: allSecondaryDepartsNewBack,
resultField: 'list',
labelField: 'departName',
valueField: 'orgCode',
placeholder: '请选择管理单位',
showSearch: true,
showDefaultValue: false,
filterOption: (input: string, option: any): boolean => {
const str: string = input.trim().toLowerCase();
return option.departName.toLowerCase().indexOf(str) >= 0;
},
};
},
},
];
export const schemas: FormSchema[] = [
{
label: '中心名称',
field: 'centerName',
component: 'Input',
required: true,
},
{
label: '大屏标题',
field: 'screenTitle',
component: 'Input',
},
{
label: '简称',
field: 'simpleName',
component: 'Input',
componentProps: () => {
return {
maxLength: 4,
};
},
required: true,
},
{
label: '管理单位',
field: 'orgCode',
component: 'ApiSelect',
componentProps: () => {
return {
api: allSecondaryDepartsNewBack,
resultField: 'list',
labelField: 'departName',
valueField: 'orgCode',
placeholder: '请选择管理单位',
showSearch: true,
showDefaultValue: false,
filterOption: (input: string, option: any): boolean => {
const str: string = input.trim().toLowerCase();
return option.departName.toLowerCase().indexOf(str) >= 0;
},
};
},
required: true,
},
{
label: '大屏路由',
field: 'screenPath',
component: 'Input',
ifShow: getUserInfo.roleCodes?.indexOf('admin') !== -1,
},
{
label: '详细地址',
field: 'address',
component: 'Input',
slot: 'addressInfo',
required: true,
},
{
label: '中心电话',
field: 'centerTel',
component: 'Input',
required: true,
// rules: rules.phoneAndTelPhone(true),
},
{
label: '值班电话',
field: 'dutyPhone',
component: 'Input',
helpMessage: '多个手机号码请用英文逗号“,”隔开',
dynamicRules: ({ values }) => {
return [
rules.multiplePhone(false)[0],
{
required: false,
validator: () => {
console.log(values);
if (values.openTimes && !values.dutyPhone) {
return Promise.reject('上班时间不为空时,值班电话也不能为空');
}
return Promise.resolve();
},
trigger: 'change',
},
];
},
},
{
label: '上班时间',
field: 'openTimes',
component: 'Input',
dynamicRules: ({ values }) => {
return [
{
required: false,
validator: () => {
if (values.dutyPhone && !values.openTimes) {
return Promise.reject('值班电话不为空时,上班时间也不能为空');
}
return Promise.resolve();
},
trigger: 'change',
},
];
},
slot: 'openTimes',
},
{
label: '服务范围',
field: 'serviceScope',
component: 'Input',
slot: 'serviceScope',
required: true,
},
{
label: '负责人',
field: 'centerHeadName',
component: 'Input',
},
{
label: '负责人电话',
field: 'centerHeadTel',
component: 'Input',
rules: rules.phoneAndTelPhone(false),
},
{
label: '建成日期',
field: 'completionTime',
component: 'DatePicker',
required: true,
componentProps: () => ({ format: 'YYYY-MM-DD', valueFormat: 'YYYY-MM-DD', style: { width: '100%' } }),
},
{
label: '投用日期',
field: 'commissioningTime',
component: 'DatePicker',
required: true,
componentProps: () => ({ format: 'YYYY-MM-DD', valueFormat: 'YYYY-MM-DD', style: { width: '100%' } }),
},
{
label: '配备金额',
field: 'equipmentAmount',
component: 'InputNumber',
componentProps: () => ({ min: 0, style: { width: '100%' }, addonAfter: '万元' }),
},
{
label: '',
field: 'longitude',
component: 'Input',
show: false,
},
{
label: '',
field: 'latitude',
component: 'Input',
show: false,
},
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
];
export const managerColumns: BasicColumn[] = [
{
title: '账号',
dataIndex: 'username',
align: 'center',
},
{
title: '姓名',
dataIndex: 'realname',
align: 'center',
},
];
export const managerSearchSchema: FormSchema[] = [
{
label: '',
field: 'realName',
component: 'Input',
componentProps: () => {
return {
placeholder: '请输入姓名',
};
},
},
];
export const managerChooseColumns: BasicColumn[] = [
{
title: '单位名称',
dataIndex: ['secondDepart', 'departName'],
align: 'center',
},
{
title: '部门名称',
dataIndex: ['threeDepart', 'departName'],
align: 'center',
},
{
title: '员工姓名',
dataIndex: 'realname',
align: 'center',
},
{
title: '员工工号',
dataIndex: 'workNo',
align: 'center',
},
];
export const managerChooseSearchSchema: FormSchema[] = [
{
label: '单位名称',
field: 'orgCode',
component: 'ApiSelect',
componentProps: () => {
return {
api: allSecondaryDepartsNew,
resultField: 'result',
labelField: 'departName',
valueField: 'orgCode',
placeholder: '请选择单位',
showSearch: true,
showDefaultValue: false,
filterOption: (input: string, option: any): boolean => {
const str: string = input.trim().toLowerCase();
return option.label.toLowerCase().indexOf(str) >= 0;
},
};
},
},
{
label: '员工姓名',
field: 'realname',
component: 'Input',
},
{
label: '员工工号',
field: 'workNo',
component: 'Input',
},
];
export const managerSchema: FormSchema[] = [
{
label: '账号',
field: 'username',
component: 'Input',
required: true,
},
{
label: '登录密码',
field: 'password',
component: 'StrengthMeter',
componentProps: () => {
return {
autocomplete: 'new-password',
};
},
dynamicRules: () => {
return [
{
required: true,
validator: (_, value) => {
if (!value) {
return Promise.reject('请输入登录密码');
}
const { message } = checkPassword(value);
if (message === 'ok') {
return Promise.resolve();
} else {
return Promise.reject(message);
}
},
trigger: 'blur',
},
];
},
ifShow: ({ values }) => {
return !values.id;
},
},
{
label: '确认密码',
field: 'confirmPassword',
component: 'InputPassword',
dynamicRules: ({ values }) => rules.confirmPassword(values, true),
ifShow: ({ values }) => {
return !values.id;
},
},
{
label: '姓名',
field: 'realname',
component: 'Input',
required: true,
},
{
label: '',
field: 'adminType',
component: 'Input',
show: false,
},
{
label: '',
field: 'centerId',
component: 'Input',
show: false,
},
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
{
label: '',
field: 'userId',
component: 'Input',
show: false,
},
];
export const medicalChooseColumns: BasicColumn[] = [];
export const medicalChooseSearchSchema: FormSchema[] = [];
export const medicalColumns: BasicColumn[] = [
{
title: '医疗点名称',
dataIndex: 'name',
},
{
title: '医疗点所属单位',
dataIndex: 'departName',
},
{
title: '医疗点状态',
dataIndex: 'status_dictText',
},
];
export const searchMedicalSchema: FormSchema[] = [
{
label: '医疗点名称',
field: 'name',
component: 'Input',
},
{
label: '医疗点所属单位',
field: 'departCode',
component: 'ApiSelect',
componentProps: () => {
return {
api: allSecondaryDepartsNewBack,
resultField: 'list',
labelField: 'departName',
valueField: 'orgCode',
placeholder: '请选择所属单位',
showSearch: true,
showDefaultValue: false,
getPopupContainer: () => document.body,
filterOption: (input: string, option: any): boolean => {
const str: string = input.trim().toLowerCase();
return option.label.toLowerCase().indexOf(str) >= 0;
},
};
},
},
];
export const medicalTableProp = {
api: selectResourceByHospitalNewApi,
columns: medicalColumns,
canResize: false,
showIndexColumn: true,
rowKey: (record: Recordable) => {
return record.id;
},
formConfig: {
//labelWidth: 120,
schemas: searchMedicalSchema,
autoSubmitOnEnter: true,
showAdvancedButton: false,
fieldMapToNumber: [],
fieldMapToTime: [],
labelWidth: 100,
actionColOptions: {
style: {
paddingLeft: '104px',
},
span: 24,
offset: 0,
xs: 24,
sm: 24,
md: 12,
lg: 12,
xl: 12,
xxl: 12,
},
baseColProps: {
xs: 24,
sm: 24,
md: 12,
lg: 12,
xl: 12,
xxl: 12,
},
},
actionColumn: {
width: 250,
fixed: 'right',
},
};
@@ -0,0 +1,316 @@
<template>
<BasicTable @register="registerTable">
<!-- <template #form-orgCode="{ model, field }">-->
<!-- <a-tree-select-->
<!-- v-model:value="model[field]"-->
<!-- tree-data-simple-mode-->
<!-- style="width: 100%"-->
<!-- :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"-->
<!-- :tree-data="treeData"-->
<!-- placeholder="选择管理单位"-->
<!-- :load-data="onLoadData"-->
<!-- :fieldNames="{-->
<!-- value: 'orgCode',-->
<!-- label: 'preTitle',-->
<!-- key: 'orgCode',-->
<!-- }"-->
<!-- show-search-->
<!-- tree-node-filter-prop="preTitle"-->
<!-- />-->
<!-- </template>-->
<template #tableTitle>
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="addB" v-auth="'emergency:emergencyManage:add'"> 新增 </a-button>
<a-button type="primary" preIcon="ant-design:export-outlined" @click="exportInfo"> 导出 </a-button>
<a-button type="primary" preIcon="ant-design:export-outlined" @click="exportInfoRecord"> 查看导出记录 </a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'status'">
<a-switch
v-model:checked="record.status"
checkedValue="0"
un-checked-value="1"
checked-children="开启"
un-checked-children="关闭"
@change="changeSwitch(record)"
:loading="record.loading1"
/>
</template>
<template v-if="column.dataIndex === 'defaultCenter'">
<a-switch
v-model:checked="record.defaultCenter"
:checkedValue="true"
:un-checked-value="false"
checked-children=""
un-checked-children=""
@change="changeSwitch1(record)"
:loading="record.loading2"
:disabled="!showCenter"
/>
</template>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :drop-down-actions="getDropAction(record)" />
</template>
</BasicTable>
<emergency-drawer @register="registerDrawer" />
<emergency-manager-modal @register="registerManagerModal" />
<emergency-medical-modal @register="registerMedicalModal" />
<emergency-info-drawer @register="registerInfoDrawer" @success="handleSuccess" />
<ExportUtil task-code="emergencyCenterExportCode" @register="registerExportDrawer" />
</template>
<script setup lang="ts">
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import { columns, searchSchema } from '/@/views/emergency/emergencyManage/emergencyManage.data';
import { TableAction } from '/@/components/Table';
import EmergencyManagerModal from '/@/views/emergency/emergencyManage/components/emergencyManagerModal.vue';
import { useDrawer } from '/@/components/Drawer';
import EmergencyDrawer from '/@/views/emergency/emergencyManage/components/emergencyDrawer.vue';
import { useModal } from '/@/components/Modal';
import {
delCenterApi,
exportApi,
listApi,
settingDefaultCenterApi,
updateCenterStatusApi,
} from '/@/views/emergency/emergencyManage/emergencyManage.api';
import EmergencyInfoDrawer from '/@/views/emergency/emergencyManage/components/emergencyInfoDrawer.vue';
import { onMounted, ref } from 'vue';
import { queryDepartTreeSync } from '/@/views/system/depart/depart.api';
import ExportUtil from '/@/utils/export/exportUtil.vue';
import EmergencyMedicalModal from '/@/views/emergency/emergencyManage/components/emergencyMedicalModal.vue';
import { useUserStore } from '/@/store/modules/user';
const userInfo = useUserStore().getUserInfo;
const [registerDrawer, { openDrawer }] = useDrawer();
const [registerExportDrawer, { openDrawer: openExportDrawer }] = useDrawer();
const [registerManagerModal, { openModal: openManagerModal }] = useModal();
const [registerInfoDrawer, { openDrawer: openInfoDrawer }] = useDrawer();
const [registerMedicalModal, { openModal: openMedicalModal }] = useModal();
const treeData = ref<any[]>([]);
const showCenter = ref(false);
onMounted(() => {
if (['admin', 'system'].includes(userInfo?.roleCodes)) {
showCenter.value = true;
}
});
function onSelectMedicalOk() {}
function exportInfo() {
const params = getForm().getFieldsValue();
exportApi(params);
}
function exportInfoRecord() {
openExportDrawer(true, {});
}
// async function loadRootTreeData() {
// try {
// treeData.value = [];
//
// const fResult = await queryDepartTreeSync({});
// if (!fResult || fResult.length < 0) return;
// const result = await queryDepartTreeSync({ pid: fResult[0].id });
// if (Array.isArray(result)) {
// result.forEach((item: any) => {
// item['preTitle'] = item.title;
// item['key'] = item['orgCode'];
// });
// treeData.value = result;
// }
// } catch {}
// }
//
// loadRootTreeData();
// async function onLoadData(treeNode) {
// try {
// const result = await queryDepartTreeSync({
// pid: treeNode.dataRef.id,
// });
// if (result && result.length == 0) {
// treeNode.dataRef.isLeaf = true;
// } else {
// treeNode.dataRef.children = result
// ? result.map((item: any) => {
// item['pId'] = treeNode.dataRef.id;
// item['preTitle'] = treeNode.dataRef.preTitle + '/' + item.title;
// item['key'] = item['orgCode'];
// return item;
// })
// : [];
//
// preData(
// treeData.value,
// treeNode.dataRef.id,
// result
// ? result.map((item: any) => {
// item['pId'] = treeNode.dataRef.id;
// item['key'] = item['orgCode'];
// return item;
// })
// : []
// );
// }
// } catch (e) {
// console.error(e);
// }
// return Promise.resolve(true);
// }
function preData(data, id, res) {
for (let i = 0; i < data.length; i++) {
if (data[i]?.id === id) {
data[i].children = res;
return;
}
preData(data[i].children, id, res);
}
}
async function changeSwitch(record: Recordable) {
try {
record.loading1 = true;
record.status = record.status == '0' ? '1' : '0';
await updateCenterStatusApi({ id: record.id, status: record.status == '0' ? '1' : '0' });
record.status = record.status === '0' ? '1' : '0';
record.loading1 = false;
} catch {
record.loading1 = false;
}
}
async function changeSwitch1(record: Recordable) {
try {
record.loading2 = true;
record.defaultCenter = !record.defaultCenter;
await settingDefaultCenterApi({ centerId: record.id, defaultCenter: !record.defaultCenter });
const data = getDataSource().map((item: any) => {
if (item.id === record.id) {
item['defaultCenter'] = !record.defaultCenter;
} else {
item['defaultCenter'] = false;
}
return item;
});
setTableData(data);
// record.defaultCenter = !record.defaultCenter;
record.loading2 = false;
} catch {
record.loading2 = false;
}
}
const { tableContext } = useListPage({
tableProps: {
title: '应急中心管理',
api: listApi,
columns,
canResize: false,
showIndexColumn: true,
formConfig: {
//labelWidth: 120,
schemas: searchSchema,
autoSubmitOnEnter: true,
showAdvancedButton: false,
fieldMapToNumber: [],
fieldMapToTime: [],
},
afterFetch: (data) => {
data.forEach((item: any) => {
item['defaultCenter'] = item['defaultCenter'] || false;
item['loading1'] = false;
item['loading2'] = false;
});
return data;
},
actionColumn: {
width: 250,
fixed: 'right',
},
},
});
function getDropAction(record: Recordable) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
{
label: '关联医疗点',
onClick: handleMedical.bind(null, record),
},
// {
// label: '删除',
// onClick: handleDel.bind(null, record),
// },
];
}
function handleSuccess() {
reload();
}
function handleMedical(record: Recordable) {
openMedicalModal(true, { record });
}
// function handleDel(record: Recordable) {
// delCenterApi(record, handleSuccess);
// }
function getTableAction(record: Recordable) {
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
},
{
label: '管理员',
onClick: handleManage.bind(null, record),
},
{
label: '大屏账号',
onClick: bigScreenUser.bind(null, record),
},
];
}
function handleDetail(record: Recordable) {
openDrawer(true, { record });
}
function handleManage(record: Recordable) {
openManagerModal(true, { record, adminType: 0 });
}
function bigScreenUser(record: Recordable) {
openManagerModal(true, { record, adminType: 1 });
}
function addB() {
openInfoDrawer(true, {
isUpdate: false,
});
}
function handleEdit(record: Recordable) {
openInfoDrawer(true, {
isUpdate: true,
record,
});
}
const [registerTable, { reload, getForm, getDataSource, setTableData }] = tableContext;
</script>
<style scoped lang="less">
:deep(.ant-table-cell-fix-left, .ant-table-cell-fix-right) {
position: relative;
border-bottom: none !important;
&:after {
position: absolute;
content: '';
width: 100%;
top: 0;
left: 0;
border-bottom: 1px solid #f0f0f0;
}
}
</style>
+8
View File
@@ -0,0 +1,8 @@
import { defHttp } from '/@/utils/http/axios';
import qs from 'qs';
enum Api {
getDepartDoctor = '/health-consultation/conHelper/getDepartDoctor',
getMedicalRecord = '/health-consultation/consultation/conSession/getMedicalRecord',
}
export const getDepartDoctorApi = (params) => defHttp.get({ url: Api.getDepartDoctor, params });
export const getMedicalRecordApi = (params) => defHttp.post({ url: `${Api.getMedicalRecord}?${qs.stringify(params)}`, params });
+99
View File
@@ -0,0 +1,99 @@
import { FormSchema } from '/@/components/Form';
export const listData = [
{
id: 'asssd1d213197ua',
name: '外科',
children: [
{
id: '12edasd2145r52341d',
aImg: 'temp/20230606/45e964377e42182ea052c75c82cefcc0_1_1686038684080.jpg',
name: '张医师',
pro: '外科',
zc: '主任医师',
hospital: '三甲第一人民医院',
times: '123',
status: '1',
},
{
id: '12edasd214qwe5r52341d',
aImg: 'temp/20230606/45e964377e42182ea052c75c82cefcc0_1_1686038684080.jpg',
name: '张医师1',
pro: '外科',
zc: '主任医师',
hospital: '三甲第一人民医院',
times: '123',
status: '2',
},
],
},
{
id: 'asssd1d213197ua',
name: '皮肤科',
children: [
{
id: '12edasd2145r52341d',
aImg: 'temp/20230606/45e964377e42182ea052c75c82cefcc0_1_1686038684080.jpg',
name: '王医师',
pro: '皮肤科',
zc: '主任医师',
hospital: '三甲第一人民医院',
times: '123',
status: '1',
},
{
id: '12edasd2145r5234asd1d',
aImg: 'temp/20230606/45e964377e42182ea052c75c82cefcc0_1_1686038684080.jpg',
name: '王医师1',
pro: '皮肤科',
zc: '主任医师',
hospital: '三甲第一人民医院',
times: '123',
status: '2',
},
],
},
];
export const basicInfoInfoForm: FormSchema[] = [
{
label: '姓名',
field: 'name',
component: 'Input',
},
{
label: '性别',
field: 'gender_dictText',
component: 'Input',
},
{
label: '出生日期',
field: 'birthday',
component: 'Input',
},
{
label: '身高',
field: 'height',
component: 'Input',
componentProps: ({}) => {
return {
suffix: 'CM',
};
},
},
{
label: '体重',
field: 'weight',
component: 'Input',
componentProps: ({}) => {
return {
suffix: 'KG',
};
},
},
{
label: '住址',
field: 'address',
component: 'Input',
},
];
+437
View File
@@ -0,0 +1,437 @@
<template>
<div class="outer-helper">
<div class="left-d">
<a-spin
class="iframe"
style="display: flex; align-items: center; justify-content: center"
tip="加载中..."
v-if="loadingVisible"
:spinning="loadingVisible"
/>
<iframe
v-show="!loadingVisible"
id="iframeRef"
ref="iframeRef"
class="iframe"
:src="`${imAddressSrc}isSpecialized=expert&${qs.stringify(sigInfo)}&sessionId=${route.query?.imId}&checkedExpert=${
route.query?.checkedExpert
}`"
></iframe>
</div>
<div class="right-d">
<div style="height: 80px; padding: 0 10px; background-color: #ffffff">
<div style="padding: 5px 0; font-weight: bold; font-size: 18px">
平台专家
<span style="color: rgba(0, 0, 0, 0.45); font-weight: bold; cursor: pointer" @click="handleRedo">
<RedoOutlined :spin="loadingDoctor" />
</span>
</div>
<div>
<a-input v-model:value="searchName" style="border-radius: 10px" placeholder="请输入专家或科室名称" />
</div>
</div>
<div style="height: calc(100% - 80px); padding: 10px; overflow: auto; background-color: #f0f2f5">
<template v-if="loadingDoctor">
<div style="display: flex; align-items: center; justify-content: center; height: 100%">
<a-spin
class="iframe"
style="display: flex; align-items: center; justify-content: center"
tip="加载中..."
:spinning="loadingDoctor"
/>
</div>
</template>
<template v-else>
<template v-if="listInfo.length > 0">
<a-collapse
style="border: none; background-color: #f0f2f5"
v-model:activeKey="activeKey"
@change="changeActivekey"
expandIconPosition="right"
accordion
>
<a-collapse-panel
style="margin-bottom: 10px; border-radius: 10px"
v-for="(item, index) in listInfo"
:key="index"
:header="item.name"
>
<div class="item-d-o" :key="'listData' + index">
<div class="item-d" v-for="(it, count) in item?.children" :key="'listDataC' + count">
<div>
<Image
style="width: 40px; height: 40px"
v-if="it.aimg"
:width="200"
:height="200"
:src="getFileAccessHttpUrl(it.aimg)"
:preview="false"
:fallback="doctor"
/>
<img
v-else
style="width: 40px; height: 40px; border-radius: 10px"
src="../../../assets/images/doctor-img.webp"
alt=""
/>
</div>
<div>
<!-- <div>{{ `${it.name}-${it.pro}-${it.zc_dictText}` }}</div>-->
<div>{{ getDoctorList(it.name, it.pro, it.zc_dictText) }}</div>
<div>{{ `${it.hospital}-本月已咨询${it.times}` }}</div>
</div>
<div :style="{ fontSize: '12px', display: 'flex', alignItems: it.status === '1' ? 'center' : 'flex-start' }">
<img
v-if="it.status === '1'"
style="width: 50px; height: 30px"
src="../../../assets/images/push.png"
alt=""
@click="clickPushImg(it)"
/>
<span v-else style="color: red">暂停服务</span>
</div>
</div>
</div>
</a-collapse-panel>
</a-collapse>
</template>
<template v-else>
<div style="display: flex; align-items: center; justify-content: center; height: 100%">
<a-empty />
</div>
</template>
</template>
<!-- <div class="onload-more" style="cursor: pointer" @click="onLoadMore()">-->
<!-- <span>-->
<!-- <a-spin v-if="loadMoreStatus === 1" />-->
<!-- {{ onLoadMoreText() }}-->
<!-- </span>-->
<!-- </div>-->
</div>
</div>
<!-- 表单区域 -->
<PersonalFile @register="medicalRecordsModal" />
</div>
</template>
<script setup lang="ts">
import doctor from '/@/assets/images/doctor-img.webp';
import qs from 'qs';
import { ref, unref, watch, h } from 'vue';
import { listData } from '/@/views/emergency/helper/helper.data';
import { userSigAndroidApi } from '/@/views/emergency/communication/components/commApi';
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
import { getDepartDoctorApi } from '/@/views/emergency/helper/helper.api';
import { useGlobSetting } from '/@/hooks/setting';
import { getToken } from '/@/utils/auth';
import { Image, notification } from 'ant-design-vue';
import { imAddressSrc } from '/@/utils/imAddressSrc';
import { useRoute } from 'vue-router';
import PersonalFile from '../helperHistory/components/personalFile.vue';
import { useModal } from '/@/components/Modal';
import { getDoctorList } from '/@/utils';
import { InfoCircleOutlined, RedoOutlined } from '@ant-design/icons-vue';
import { useDesign } from '/@/hooks/web/useDesign';
const loadMoreStatus = ref<Number>(0); // 加载状态 0 点击加载更多,1加载中,2加载完毕,3无更多数据
const sigInfo = ref<Object>({
userSig: '',
sdkAppId: '',
userId: '',
urlF: '',
});
const ListDataForm = ref({
listData: [],
current: 1,
pageSize: 10,
total: 1,
});
const { prefixCls } = useDesign('multiple-tabs-content');
const activeKey = ref<Number>(0);
const listInfo = ref<any[]>([]);
const listInfoInit = ref<any[]>([]);
const loadingVisible = ref<Boolean>(true); // loading
const loadingDoctor = ref<Boolean>(true); // 查询医生loading
const visible = ref<Boolean>(false); // loading
const searchName = ref<String>(''); // visible
let archives = ref<Object>({
titleName: '',
recordsName: '',
medicalDescribe: '',
image: '',
imageList: [],
haveTime_dictText: '',
desire: '',
lookOffice: '',
map: {},
}); // visible
const route = useRoute();
const closeLoading = () => {
loadingVisible.value = false;
};
window.onmessage = async (msg) => {
const result = JSON.parse(msg.data);
switch (result.code) {
case 'closeLoading':
closeLoading();
break;
case 'showConsultation':
await openDialog(result.archivesId, result.archivesName);
break;
case 'newMessage':
showNewMessage();
break;
}
};
const [medicalRecordsModal, { openModal }] = useModal();
function showNewMessage() {
notification.open({
message: '提示',
description: '您有新的消息',
icon: () => h(InfoCircleOutlined, { style: 'color: #108ee9' }),
});
}
async function openDialog(id, name) {
await openModal(true, {
record: { memberName: name, medicalRecordsId: id },
isUpdate: false,
showFooter: false,
});
// await getMedicalRecordApi({ id: id })
// .then((res) => {
// // nextTick(() => {
// res.lookOffice = res.lookOffice || '无';
// res['imageList'] = res.image.split(',').map((item) => ({
// width: 150,
// height: 150,
// src: getFileAccessHttpUrl(item),
// }));
// res['titleName'] = name;
// // archives.value = { ...archives.value, ...res };
//
// // });
// })
// .catch(() => {});
// visible.value = true;
}
watch(
() => searchName.value,
(nV: String) => {
activeKey.value = 0;
let data = JSON.parse(JSON.stringify(listInfoInit.value));
let child = [];
let result = data.filter((item) => {
child =
item.children && item.children.filter((it) => (it.name && it.name.indexOf(nV) !== -1) || (it.pro && it.pro.indexOf(nV) !== -1));
if (child && child.length > 0) {
item.children = child;
return item;
} else {
return item.name && item.name.indexOf(nV) !== -1;
}
});
listInfo.value = result;
}
);
const changeActivekey = () => {};
const onLoadMore = () => {
if (loadMoreStatus.value === 1 || loadMoreStatus.value === 3) return;
ListDataForm.value.current += 1;
// initListData();
};
const onLoadMoreText = () => {
let result = '点击加载更多';
switch (loadMoreStatus.value) {
case 0:
result = '点击加载更多';
break;
case 1:
result = '加载中';
break;
case 2:
result = '点击加载更多';
break;
case 3:
result = '无更多数据';
break;
}
return result;
};
const globSetting = useGlobSetting();
const apiUrl = globSetting.apiUrl;
const getSig = () => {
userSigAndroidApi({})
.then((res) => {
const { userSig, sdkAppId, userId } = res;
sigInfo.value = { userSig, sdkAppId, userId, urlF: apiUrl.replace('://', 'lol'), tokenF: getToken() };
})
.catch((e) => {
console.log(e);
});
};
const iframeRef = ref();
const clickPushImg = (item) => {
const { name, zc_dictText, hospital, pro, id, aimg } = item;
const result = {
code: 'custom',
data: {
businessID: 'business_card',
cardId: id,
doctorName: name,
organization: hospital,
departmentName: pro,
doctorTitle: zc_dictText,
doctorHeadImg: getFileAccessHttpUrl(aimg),
},
};
unref(iframeRef).contentWindow.postMessage(JSON.stringify(result), '*');
};
function handleRedo() {
initData();
}
const initData = () => {
loadingDoctor.value = true;
getDepartDoctorApi({})
.then((res) => {
let arr = res.filter((item) => {
if (item.children.length > 0) {
item.children = item.children.filter((it) => {
return it.status == '1';
});
return item;
}
});
listInfo.value = arr;
listInfoInit.value = arr;
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loadingDoctor.value = false;
});
};
const handleCancel = () => {
visible.value = false;
};
getSig();
initData();
</script>
<style scoped lang="less">
.outer-helper {
overflow: hidden;
display: flex;
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 10px;
position: relative;
.left-d {
width: 70%;
}
.right-d {
border-left: 1px solid #f4f5f9;
width: calc(30% - 20px);
left: calc(70% + 10px);
}
}
.left-d,
.right-d {
height: calc(100% - 20px);
position: absolute;
overflow: auto;
}
.iframe {
height: 100%;
width: 100%;
}
:deep(.jeecg-layout-content) {
height: 100%;
overflow: hidden;
background-color: yellow;
}
.expert {
background-color: #466afb !important;
color: #ffffff !important;
}
.onload-more {
transform: scale(0.8);
text-align: center;
margin-bottom: 5px;
}
.item-d {
display: flex;
padding: 5px 10px;
background-color: #f0f2f5;
margin-bottom: 5px;
border-radius: 10px;
> :nth-child(1) {
width: 45px;
display: flex;
justify-content: center;
align-items: center;
}
> :nth-child(2) {
width: calc(100% - 105px);
font-size: 13px;
> :nth-child(n) {
padding: 0 3px 3px;
display: flex;
}
> :nth-child(2) {
color: #a1a1a1;
}
}
> :nth-child(3) {
width: 60px;
img {
cursor: pointer;
}
> :nth-child(n) {
padding: 0 0 3px;
display: flex;
justify-content: center;
}
}
}
.item-d-o {
background-color: #ffffff;
border-radius: 10px;
}
:deep(.ant-collapse-content > .ant-collapse-content-box) {
padding: 10px;
}
:deep(.ant-collapse-content) {
border-top: none;
}
:deep(.ant-collapse-header) {
background-color: #ffffff;
}
:deep(.ant-form-item-label) {
width: 100px;
}
:deep(.ant-image-img) {
width: 150px;
height: 150px;
}
:deep(.ant-image) {
display: inline !important;
margin: 0 10px 5px 0;
}
:deep(.ant-modal-header) {
font-size: 20px !important;
}
:deep(.ant-image) {
width: 40px !important;
height: 40px !important;
}
</style>
@@ -0,0 +1,63 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose title="历史记录" :width="800" @close="closeModalF">
<div style="width: 100%; height: 60vh; display: flex; align-items: center; justify-content: center">
<a-spin class="iframe" tip="加载中..." v-if="loadingVisible" :spinning="loadingVisible" />
<iframe v-show="!loadingVisible" id="iframeRef" ref="iframeRef" style="width: 100%; height: 100%" class="iframe"></iframe>
</div>
</BasicModal>
<PersonalFile @register="medicalRecordsModal" />
</template>
<script setup lang="ts">
import { BasicModal, useModal, useModalInner } from '/@/components/Modal';
import { imAddressSrc } from '/@/utils/imAddressSrc';
import { ref } from 'vue';
import qs from 'qs';
import PersonalFile from '/@/views/emergency/helperHistory/components/personalFile.vue';
const props = defineProps({
imProps: Object,
});
const loadingVisible = ref(true);
const sessionId = ref('');
const isOvertime = ref('0');
const iframeRef = ref();
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
loadingVisible.value = true;
sessionId.value = data.record.imId;
isOvertime.value = data.isOvertime;
iframeRef.value.src = `${imAddressSrc}isSpecialized=true&${qs.stringify(props.imProps)}&sessionId=${
sessionId.value
}&getMessageList=0&isOvertime=${isOvertime.value}`;
setModalProps({
footer: null,
});
});
window.onmessage = (msg) => {
const result = JSON.parse(msg.data);
switch (result.code) {
case 'closeLoading':
loadingVisible.value = false;
break;
case 'showConsultation':
openDialog(result.archivesId, result.archivesName);
break;
}
};
function closeModalF() {
iframeRef.value.src = '';
closeModal();
}
const [medicalRecordsModal, { openModal: openRecordModal }] = useModal();
function openDialog(id, name) {
openRecordModal(true, {
record: { memberName: name, medicalRecordsId: id },
isUpdate: false,
showFooter: false,
});
}
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,135 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
<div class="title">咨询信息</div>
<BasicForm @register="registerForm">
<template #medicalRecords="{ model }">
<span class="click-text" @click="medicalRecords(model)">查看档案</span>
</template>
<template #resourceName="{ model, field }">
<span class="click-text" v-if="resourceNameType == '1'" @click="chatRecords(model, field)">聊天记录</span>
<span class="click-text" v-if="resourceNameType == '2'" @click="chatRecords(model, field)">通话记录</span>
</template>
</BasicForm>
<div class="title">订单信息</div>
<BasicForm @register="registerFormOrder" />
<!--查看档案-->
<PersonalFile @register="medicalRecordsModal" />
</BasicModal>
</template>
<script lang="ts" setup>
import { computed, defineExpose, ref, unref } from 'vue';
import { BasicModal, useModalInner, useModal } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema, formSchemaOrder } from '../helperHistory.data';
import { saveOrUpdate } from '../helperHistory.api';
import PersonalFile from './personalFile.vue';
// Emits声明
const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true);
//表单配置
const [registerForm, { setProps, resetFields, setFieldsValue, validate }] = useForm({
labelWidth: 80,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { span: 12 },
});
// 图文1 视频 2 电话3 应急 4
let resourceNameType = ref('');
//表单配置
const [registerFormOrder, { setProps: setPropsOrder, setFieldsValue: setFieldsValueOrder }] = useForm({
labelWidth: 80,
schemas: formSchemaOrder,
showActionButtonGroup: false,
baseColProps: { span: 12 },
});
//表单赋值
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
resourceNameType.value = data.record.contentType;
//重置表单
await resetFields();
setModalProps({
confirmLoading: false,
showCancelBtn: !!data?.showFooter,
showOkBtn: !!data?.showFooter,
});
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
//表单赋值
await setFieldsValue({
...data.record,
});
await setFieldsValueOrder({
...data.record,
});
}
// 隐藏底部时禁用整个表单
await setProps({ disabled: !data?.showFooter });
await setPropsOrder({ disabled: !data?.showFooter });
});
//设置标题
const title = computed(() => (!unref(isUpdate) ? '编辑' : '咨询详情'));
//注册model
const [medicalRecordsModal, { openModal }] = useModal();
// 查看档案
function medicalRecords(model) {
openModal(true, {
record: model,
isUpdate: false,
showFooter: false,
});
}
// 聊天记录
function chatRecords(model, field) {
console.log('聊天记录', model, field);
}
//表单提交事件
async function handleSubmit() {
try {
let values = await validate();
setModalProps({ confirmLoading: true });
//提交表单
await saveOrUpdate(values, isUpdate.value);
//关闭弹窗
closeModal();
//刷新列表
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
function handleRecordTable(record) {
console.log(record);
}
defineExpose({
handleRecordTable,
});
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
.title {
box-sizing: border-box;
color: #333;
font-weight: bold;
padding: 12px 16px;
}
.click-text {
cursor: pointer;
color: #1890ff;
}
</style>
@@ -0,0 +1,100 @@
<template>
<!--/* <div style="height: 65vh; overflow: auto">*/-->
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit" @cancel="clearData">
<div class="personal-container">
<div class="title">基本信息</div>
<BasicForm @register="registerBasicInfo" />
<div class="title">咨询档案</div>
<BasicForm @register="registerForm" />
<div class="title">健康信息</div>
<BasicForm @register="registerHealthInfo" />
</div>
</BasicModal>
<!-- </div>-->
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { personalFileForm, healthInfoForm, basicInfoInfoForm } from '../helperHistory.data';
import { getMedicalRecordApi } from '../helperHistory.api';
const title = ref('');
//表单配置
//咨询档案
const [registerForm, { setProps, resetFields, setFieldsValue }] = useForm({
labelWidth: 80,
schemas: personalFileForm,
showActionButtonGroup: false,
baseColProps: { span: 24 },
});
//健康信息
const [registerHealthInfo, { setProps: setHealthInfoProps, setFieldsValue: setHealthFieldsValue }] = useForm({
labelWidth: 80,
schemas: healthInfoForm,
showActionButtonGroup: false,
baseColProps: { span: 12 },
});
// 基本信息
const [registerBasicInfo, { setProps: setBasicInfoInfoProps, setFieldsValue: setBasicInfoFieldsValue }] = useForm({
labelWidth: 80,
schemas: basicInfoInfoForm,
showActionButtonGroup: false,
baseColProps: { span: 12 },
});
//表单赋值
const [registerModal, { setModalProps }] = useModalInner(async (data) => {
let { memberName, medicalRecordsId } = data.record;
title.value = memberName ? memberName + '档案' : '患者档案';
const res = await getMedicalRecordApi({ id: medicalRecordsId });
//重置表单
await resetFields();
setModalProps({
confirmLoading: false,
showCancelBtn: !!data?.showFooter,
showOkBtn: !!data?.showFooter,
});
await setBasicInfoFieldsValue({
...res.user,
});
await setFieldsValue({
...res,
});
let bottomProps = ref<Array>([]);
for (const k in res.map) {
bottomProps.value.push({
label: k,
field: k,
component: 'Input',
defaultValue: res.map[k],
});
}
// 隐藏底部时禁用整个表单
await setBasicInfoInfoProps({ disabled: !data?.showFooter });
await setProps({ disabled: !data?.showFooter });
await setHealthInfoProps({ schemas: bottomProps.value, disabled: !data?.showFooter });
});
function clearData() {}
function handleSubmit() {}
</script>
<style scoped lang="less">
.personal-container {
height: 65vh;
overflow: auto;
}
.title {
box-sizing: border-box;
color: #333;
font-weight: bold;
padding: 12px 16px;
}
.click-text {
cursor: pointer;
background-color: #1890ff;
}
</style>
@@ -0,0 +1,76 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
import qs from 'qs';
const { createConfirm } = useMessage();
enum Api {
list = '/health-consultation/consultation/conSession/list',
listO = '/health-consultation/consultation/conSession/listByHelper',
save = '/health-consultation/consultation/conSession/add',
edit = '/health-consultation/consultation/conSession/edit',
deleteOne = '/health-consultation/consultation/conSession/delete',
deleteBatch = '/health-consultation/consultation/conSession/deleteBatch',
importExcel = '/health-consultation/consultation/conSession/importExcel',
exportXls = '/health-consultation/consultation/conSession/exportXls',
getMedicalRecord = '/health-consultation/consultation/conSession/getMedicalRecord',
syncImMessage = '/health-im/txImMessage/syncImMessage',
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) => {
return defHttp.get({ url: Api.list, params });
};
export const syncImMessageApi = (params) => defHttp.get({ url: Api.syncImMessage, params }, { isTransformResponse: false });
export const listO = (params) => {
return defHttp.get({ url: Api.listO, params });
};
/**
* 删除单个
*/
export const deleteOne = (params, handleSuccess) => {
return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
},
});
};
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
const url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
export const getMedicalRecordApi = (params) => {
return defHttp.post({ url: `${Api.getMedicalRecord}?${qs.stringify(params)}`, params });
};
@@ -0,0 +1,926 @@
import { getSecondaryDepartmentList, getThirdDepartmentList } from '/@/views/system/user/user.api';
import { BasicColumn, FormSchema } from '/@/components/Table';
import { render } from '/@/utils/common/renderUtils';
import { BODY_CONTAINER } from '/@/utils/domUtils';
import { isQH } from '/@/utils/getEnv';
import { selectResourceList } from '/@/views/consult/doctor/message/conDoctor.api';
import { message } from 'ant-design-vue';
//列表数据
export const columns: BasicColumn[] = [
{
title: '员工姓名',
align: 'center',
width: 120,
dataIndex: 'fromName',
},
{
title: '员工单位',
align: 'center',
width: 180,
customRender: ({ record }) => {
const userInfo = record.userInfo;
if (!userInfo) {
return '';
}
const departs = userInfo.parentDepart;
if (departs && departs.length > 0) {
return departs[departs.length - 1].departName;
} else {
return userInfo.depart.departName || '';
}
},
},
{
title: '员工部门',
align: 'center',
width: 180,
customRender: ({ record }) => {
const userInfo = record.userInfo;
if (!userInfo) {
return '';
}
return userInfo.depart.departName || '';
},
},
{
title: '咨询方式',
align: 'center',
dataIndex: 'contentType',
width: 120,
customRender: ({ text }) => {
const conType = render.renderDict(text, 'con_type');
switch (text) {
case '1':
return render.renderTag(conType, 'green');
case '2':
return render.renderTag(conType, 'blue');
default:
return '';
}
},
},
{
title: '咨询类型',
align: 'center',
dataIndex: 'sessionType',
width: 120,
customRender: ({ record }) => {
switch (record.sessionType) {
case '1':
return render.renderTag('咨询专家', 'green');
case '2':
return render.renderTag(isQH() ? '咨询全科医生' : '咨询小助手', 'blue');
default:
return '';
}
},
},
...(isQH()
? ([
{
title: '疾病所属科室',
align: 'center',
dataIndex: 'departmentId',
customRender: ({ record }) => {
if (record?.sessionType !== '2') {
return '-';
}
},
},
{
title: '疾病名称',
align: 'center',
dataIndex: 'disable',
customRender: ({ record }) => {
if (record?.sessionType !== '2') {
return '-';
}
},
},
] as BasicColumn[])
: ([] as BasicColumn[])),
{
title: '专家姓名',
align: 'center',
width: 120,
dataIndex: ['doctorInfo', 'doctorName'],
},
{
title: '医院',
align: 'center',
width: 180,
dataIndex: ['doctorInfo', 'resourceName'],
},
{
title: '科室',
align: 'center',
width: 150,
dataIndex: ['doctorInfo', 'departmentName'],
},
{
title: '专家职称',
align: 'center',
width: 120,
dataIndex: ['doctorInfo', 'doctorJob_dictText'],
},
{
title: '专家职务',
align: 'center',
width: 120,
dataIndex: ['doctorInfo', 'doctorTitle_dictText'],
},
{
title: '专家类型',
align: 'center',
width: 120,
dataIndex: ['doctorInfo', 'type'],
customRender: ({ text }) => {
return render.renderDict(text, 'z_doct_typ');
},
},
{
title: isQH() ? '全科医生名称' : '小助手姓名',
align: 'center',
width: 120,
customRender: ({ record }) => {
switch (record.sessionType) {
case '1':
return record.thirdName;
case '2':
return record.toName;
default:
return '';
}
},
defaultHidden: !isQH(),
},
{
title: '员工发送状态',
align: 'center',
dataIndex: 'userTfReply',
fixed: 'right',
width: 120,
customRender: ({ record }) => {
if (record.contentType !== '1') {
return '';
}
switch (record.userTfReply) {
case '0':
return render.renderTag('未发送', 'red');
case '1':
return render.renderTag('已发送', 'green');
default:
return '';
}
},
},
{
title: '专家回复状态',
align: 'center',
dataIndex: 'tfReply',
fixed: 'right',
width: 120,
customRender: ({ record }) => {
if (record.contentType !== '1') {
return '';
}
switch (record.tfReply) {
case 0:
if (record.userTfReply === '0') {
return '';
}
return render.renderTag('未回复', 'red');
case 1:
return render.renderTag('已回复', 'green');
default:
return '';
}
},
},
{
title: '专家首次回复时间',
align: 'center',
dataIndex: 'doctorFirstReplyTime',
fixed: 'right',
width: 180,
sorter: true,
showSorterTooltip: true,
sortDirections: ['descend', 'ascend', null],
},
{
title: '咨询状态',
align: 'center',
width: 120,
dataIndex: 'contentStatus',
customRender: ({ text }) => {
return render.renderDict(text, 'o_status');
},
},
{
title: '咨询发起时间',
align: 'center',
dataIndex: 'createTime',
width: 180,
sorter: true,
showSorterTooltip: true,
defaultSortOrder: 'descend',
sortDirections: ['descend', 'ascend', null],
fixed: 'right',
},
];
export const columns1: BasicColumn[] = [
{
title: '专家姓名',
align: 'center',
dataIndex: ['doctorInfo', 'doctorName'],
},
{
title: '医院',
align: 'center',
dataIndex: ['doctorInfo', 'resourceName'],
},
{
title: '科室',
align: 'center',
dataIndex: ['doctorInfo', 'departmentName'],
},
{
title: '专家职称',
align: 'center',
dataIndex: ['doctorInfo', 'doctorJob_dictText'],
},
{
title: '专家职务',
align: 'center',
dataIndex: ['doctorInfo', 'doctorTitle_dictText'],
},
{
title: '专家类型',
align: 'center',
dataIndex: ['doctorInfo', 'type'],
customRender: ({ text }) => {
return render.renderDict(text, 'z_doct_typ');
},
},
{
title: '小助手姓名',
align: 'center',
customRender: ({ record }) => {
return record.toName;
},
defaultHidden: true,
},
{
title: '咨询时间',
align: 'center',
width: 180,
dataIndex: 'createTime',
fixed: 'right',
},
{
title: '咨询状态',
align: 'center',
width: 120,
dataIndex: 'contentStatus',
customRender: ({ text }) => {
return render.renderDict(text, 'o_status');
},
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
{
label: '咨询类型',
field: 'searchType',
component: 'Input',
slot: 'consultType',
show: !isQH(),
defaultValue: '1',
},
{
label: '员工姓名',
field: 'userName',
component: 'Input',
},
{
label: '员工单位',
field: 'secondDepart',
component: 'ApiSelect',
componentProps: ({ formModel }) => {
return {
api: getSecondaryDepartmentList,
resultField: 'result',
labelField: 'departName',
valueField: 'id',
immediate: true,
onChange: (_value, record) => {
formModel.orgCode = record.orgCode;
formModel.orgCodeTmp = record.orgCode;
},
onDeselect: () => {
formModel.secondDepart = '';
formModel.thirdDepart = '';
formModel.orgCode = '';
},
getPopupContainer: () => document.body,
};
},
},
{
label: '员工部门',
field: 'thirdDepart',
component: 'ApiSelect',
componentProps: ({ formModel }) => {
return {
api: getThirdDepartmentList,
resultField: 'list',
labelField: 'departName',
valueField: 'id',
params: {
secondDepartId: formModel?.secondDepart || '12313',
},
immediate: true,
onFocus: () => {
if (!formModel.secondDepart) {
return message.warn('请先选择单位!');
}
},
onChange: (_value, record) => {
formModel.orgCode = record.orgCode;
},
onDeselect: () => {
formModel.thirdDepart = '';
formModel.orgCode = formModel.orgCodeTmp ? formModel.orgCodeTmp : '';
},
getPopupContainer: () => document.body,
};
},
},
{
label: '部门code',
field: 'orgCode',
component: 'Input',
show: false,
},
{
label: '部门codeTmp',
field: 'orgCodeTmp',
component: 'Input',
show: false,
},
{
label: '专家姓名',
field: 'doctorName',
component: 'Input',
},
{
label: '专家医院',
field: 'hospitalId',
component: 'ApiSelect',
componentProps: {
// @ts-ignore
api: selectResourceList,
resultField: 'list',
labelField: 'name',
valueField: 'id',
immediate: false,
showSearch: true,
filterOption: (input: string, option: any): boolean => {
const str: string = input.toLowerCase();
return option.label.toLowerCase().indexOf(str) >= 0;
},
},
},
{
label: '专家职称',
field: 'doctorJob',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'z_doct_job',
},
},
{
label: '专家类型',
field: 'doctorType',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'z_doct_typ',
},
},
{
label: '用户发送状态',
field: 'userTfReply',
component: 'Select',
componentProps: {
options: [
{ value: '0', label: '未发送' },
{ value: '1', label: '已发送' },
],
},
},
{
label: '专家回复状态',
field: 'tfReply',
component: 'Select',
componentProps: {
options: [
{ value: '0', label: '未回复' },
{ value: '1', label: '已回复' },
],
},
},
{
label: '咨询类型',
field: 'sessionType',
component: 'Select',
componentProps: {
options: [
{ value: '1', label: '咨询专家' },
{ value: '2', label: isQH() ? '咨询全科医生' : '咨询小助手' },
],
},
},
{
label: '咨询状态',
field: 'contentStatus',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'o_status',
},
},
{
label: '咨询时间',
field: 'Date',
component: 'RangePicker',
componentProps: ({ formModel }) => {
return {
valueType: 'Date',
valueFormat: 'YYYY-MM-DD',
getPopupContainer: () => BODY_CONTAINER,
onChange: (times: any) => {
if (times === null) {
formModel.startDate = null;
formModel.endDate = null;
return;
}
const [start, end] = times;
formModel.startDate = start + ' 00:00:00';
formModel.endDate = end + ' 23:59:59';
},
};
},
},
{
label: '首次回复时间',
field: 'replyDate',
component: 'RangePicker',
componentProps: ({ formModel }) => {
return {
valueType: 'Date',
valueFormat: 'YYYY-MM-DD',
getPopupContainer: () => BODY_CONTAINER,
onChange: (times: any) => {
if (times === null) {
formModel.replyStartDate = null;
formModel.replyEndDate = null;
return;
}
const [start, end] = times;
formModel.replyStartDate = start + ' 00:00:00';
formModel.replyEndDate = end + ' 23:59:59';
},
};
},
},
{
label: '',
field: 'startDate',
component: 'Input',
show: false,
},
{
label: '',
field: 'endDate',
component: 'Input',
show: false,
},
{
label: '',
field: 'replyStartDate',
component: 'Input',
show: false,
},
{
label: '',
field: 'replyEndDate',
component: 'Input',
show: false,
},
];
export const searchFormSchema1: FormSchema[] = [
{
label: '咨询类型',
field: 'searchType',
component: 'Input',
slot: 'consultType',
defaultValue: '2',
},
{
label: '专家姓名',
field: 'doctorName',
component: 'Input',
},
{
label: '专家医院',
field: 'hospitalId',
component: 'ApiSelect',
componentProps: {
// @ts-ignore
api: selectResourceList,
resultField: 'list',
labelField: 'name',
valueField: 'id',
immediate: false,
showSearch: true,
filterOption: (input: string, option: any): boolean => {
const str: string = input.toLowerCase();
return option.label.toLowerCase().indexOf(str) >= 0;
},
},
},
{
label: '专家职称',
field: 'doctorJob',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'z_doct_job',
},
},
{
label: '专家类型',
field: 'doctorType',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'z_doct_typ',
},
},
{
label: '咨询状态',
field: 'contentStatus',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'o_status',
},
},
{
label: '咨询时间',
field: 'Date',
component: 'RangePicker',
componentProps: ({ formModel }) => {
return {
valueType: 'Date',
valueFormat: 'YYYY-MM-DD',
getPopupContainer: () => BODY_CONTAINER,
onChange: ([start, end]) => {
formModel.startDate = start + ' 00:00:00';
formModel.endDate = end + ' 23:59:59';
},
};
},
},
{
label: '',
field: 'startDate',
component: 'Input',
show: false,
},
{
label: '',
field: 'endDate',
component: 'Input',
show: false,
},
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '咨询员工',
field: 'fromName',
component: 'Input',
},
{
label: '所属单位',
field: 'orgCode',
component: 'Input',
},
{
label: '咨询患者',
field: 'memberName',
component: 'Input',
ifShow: ({ values }) => {
return !!values.memberName;
},
},
{
label: '患者年龄',
field: 'memberAge',
component: 'Input',
ifShow: ({ values }) => {
return !!values.memberAge;
},
},
{
label: '患者档案',
field: 'medicalRecordsId',
component: 'Input',
ifShow: ({ values }) => {
return !!values.medicalRecordsId;
},
},
{
label: '关系',
field: 'familyRelation',
component: 'Input',
ifShow: ({ values }) => {
return !!values.familyRelation;
},
},
{
label: '专家姓名',
field: 'doctorName',
component: 'Input',
ifShow: ({ values }) => {
return !!values.doctorName;
},
},
{
label: '所属医院',
field: 'resourceName',
component: 'Input',
ifShow: ({ values }) => {
return !!values.resourceName;
},
},
{
label: '专家科室',
field: 'deptName',
component: 'Input',
ifShow: ({ values }) => {
return !!values.deptName;
},
},
{
label: '专家职称',
field: 'doctorTitle',
component: 'Input',
ifShow: ({ values }) => {
return !!values.doctorTitle;
},
},
{
label: '咨询记录',
field: 'resourceName',
component: 'Input',
},
{
label: '咨询单状态',
field: 'contentStatus',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'o_status',
},
},
{
label: '咨询方式',
field: 'contentType',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'con_type',
},
},
{
label: '创建时间',
field: 'createTime',
component: 'Input',
},
{
label: '订单号',
field: 'id',
component: 'Input',
},
// TODO 主键隐藏字段,目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
];
export const formSchema1: FormSchema[] = [];
//订单信息数据
export const formSchemaOrder: FormSchema[] = [
{
label: '咨询单状态',
field: 'contentStatus',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'o_status',
},
},
{
label: '咨询方式',
field: 'contentType',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'con_type',
},
},
{
label: '订单号',
field: 'id',
component: 'Input',
},
];
/**
* 流程表单调用这个方法获取formSchema
* @param param
*/
export function getBpmFormSchema(_formData): FormSchema[] {
// 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
return formSchema;
}
export const personalFileForm: FormSchema[] = [
{
label: '患病时长',
field: 'haveTime_dictText',
component: 'Input',
componentProps: {
disabled: true,
},
},
{
label: '问题描述',
field: 'medicalDescribe',
component: 'Input',
componentProps: {
disabled: true,
},
},
{
label: '就诊医院',
field: 'lookOffice',
component: 'Input',
componentProps: {
disabled: true,
},
},
{
label: '病情资料',
field: 'image',
component: 'JImageUpload',
componentProps: {
disabled: true,
},
},
{
label: '期望帮助',
field: 'desire',
component: 'Input',
componentProps: {
disabled: true,
},
},
// {
// label: '体检报告',
// field: 'fromName',
// component: 'Input',
// slot: 'record',
// },
];
export const healthInfoForm: FormSchema[] = [
// {
// label: '身高',
// field: 'fromName',
// component: 'Input',
// },
// {
// label: '体重',
// field: 'fromName',
// component: 'Input',
// },
// {
// label: '疾病史',
// field: 'fromName',
// component: 'Input',
// },
// {
// label: '家族史',
// field: 'fromName',
// component: 'Input',
// },
// {
// label: '既往史',
// field: 'fromName',
// component: 'Input',
// },
// {
// label: '过敏史',
// field: 'fromName',
// component: 'Input',
// },
// {
// label: '手术史',
// field: 'fromName',
// component: 'Input',
// },
// {
// label: '肝功能',
// field: 'fromName',
// component: 'Input',
// },
// {
// label: '肾功能',
// field: 'fromName',
// component: 'Input',
// },
// {
// label: '用药史',
// field: 'fromName',
// component: 'Input',
// },
// {
// label: '生活习惯',
// field: 'fromName',
// component: 'Input',
// },
// {
// label: '烟酒习惯',
// field: 'fromName',
// component: 'Input',
// },
];
export const basicInfoInfoForm: FormSchema[] = [
{
label: '姓名',
field: 'name',
component: 'Input',
componentProps: {
disabled: true,
},
},
{
label: '性别',
field: 'gender_dictText',
component: 'Input',
componentProps: {
disabled: true,
},
},
{
label: '出生日期',
field: 'birthday',
component: 'Input',
componentProps: {
disabled: true,
},
},
{
label: '身高',
field: 'height',
component: 'Input',
componentProps: ({}) => {
return {
suffix: 'CM',
disabled: true,
};
},
},
{
label: '体重',
field: 'weight',
component: 'Input',
componentProps: ({}) => {
return {
suffix: 'KG',
disabled: true,
};
},
},
{
label: '住址',
field: 'address',
component: 'Input',
componentProps: {
disabled: true,
},
},
];
@@ -0,0 +1,288 @@
<template>
<div>
<!--引用表格-->
<BasicTable :rowSelection="null" @register="registerTable" v-if="!checkedExpert">
<template #form-consultType="{ model, filed }">
<div style="display: flex">
<div class="checkedPro" @click="clickExpert(false)" :class="[checkedExpert ? '' : 'expert']"> 员工咨询 </div>
<div class="checkedPro" @click="clickExpert(true)" style="margin-left: 10px" :class="[checkedExpert ? 'expert' : '']">
专家咨询
</div>
</div>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
</BasicTable>
<BasicTable :rowSelection="null" @register="registerTable1" v-if="checkedExpert">
<template #form-consultType="{ model, filed }">
<div style="display: flex">
<div class="checkedPro" @click="clickExpert(false)" :class="[checkedExpert ? '' : 'expert']"> 员工咨询 </div>
<div class="checkedPro" @click="clickExpert(true)" style="margin-left: 10px" :class="[checkedExpert ? 'expert' : '']">
专家咨询
</div>
</div>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
</BasicTable>
<!-- 表单区域 -->
<staffForDoctorModal @register="registerModal" @success="handleSuccess" />
<emergency-modal @register="registerModal1" :im-props="imProps" />
<medical-modal
@register="registerModalM"
@success="
() => {
reload();
}
"
/>
</div>
</template>
<script lang="ts" name="consultation-helperHistory" setup>
import { ref } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import { useModal } from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage';
import staffForDoctorModal from './components/helperHistoryModal.vue';
import { columns, columns1, searchFormSchema, searchFormSchema1 } from './helperHistory.data';
import { getExportUrl, getImportUrl, listO, syncImMessageApi } from './helperHistory.api';
import { useUserStore } from '/@/store/modules/user';
import { useGlobSetting } from '/@/hooks/setting';
import { userSigAndroidApi } from '/@/views/emergency/communication/components/commApi';
import { getToken } from '/@/utils/auth';
import EmergencyModal from '/@/views/emergency/helperHistory/components/emergencyModal.vue';
import { getEnvInfo, isQH } from '/@/utils/getEnv';
import { useMessage } from '/@/hooks/web/useMessage';
import { message } from 'ant-design-vue';
import MedicalModal from '/@/views/consult/staff/staffForHelper/components/medicalModal.vue';
import ExportUtil from '/@/utils/export/exportUtil.vue';
const checkedExpert = ref<Boolean>(false);
//注册model
const [registerModal, { openModal }] = useModal();
const [registerModal1, { openModal: openModal1 }] = useModal();
const [registerModalM, { openModal: openModalM }] = useModal();
const { createConfirm } = useMessage();
const userStore = useUserStore();
const imProps = ref<Object>({
sdkAppId: '',
userSig: '',
tokenF: getToken(),
userId: '',
urlF: '',
});
const clickExpert = (flag: boolean) => {
if (flag !== checkedExpert.value) checkedExpert.value = !checkedExpert.value;
};
//注册table数据
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
tableProps: {
title: 'con_session',
api: listO,
columns,
showIndexColumn: true,
canResize: false,
beforeFetch(params) {
delete params.orgCodeTmp;
delete params.secondDepart;
delete params.thirdDepart;
return params;
},
formConfig: {
//labelWidth: 120,
schemas: searchFormSchema,
//去掉展开收起按钮
showAdvancedButton: false,
autoSubmitOnEnter: true,
fieldMapToNumber: [],
fieldMapToTime: [],
},
// showActionColumn: false,
actionColumn: {
width: isQH() ? 230 : 150,
fixed: 'right',
},
},
exportConfig: {
name: 'con_session',
url: getExportUrl,
},
importConfig: {
url: getImportUrl,
success: handleSuccess,
},
});
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
const { tableContext: tableContext1 } = useListPage({
tableProps: {
title: 'con_session',
api: listO,
columns: columns1,
showIndexColumn: true,
canResize: false,
beforeFetch(params) {
return params;
},
formConfig: {
//labelWidth: 120,
schemas: searchFormSchema1,
//去掉展开收起按钮
showAdvancedButton: false,
autoSubmitOnEnter: true,
fieldMapToNumber: [],
fieldMapToTime: [],
},
// showActionColumn: false,
actionColumn: {
width: 150,
fixed: 'right',
},
},
exportConfig: {
name: 'con_session',
url: getExportUrl,
},
importConfig: {
url: getImportUrl,
success: handleSuccess,
},
});
const [registerTable1, { reload: reload1 }] = tableContext1;
function handleSession(record: Recordable) {
console.log(isAdmin());
let datetime = new Date(record.sessionDate).getTime() - new Date('2024-4-22').getTime() > 0 ? '1' : '0';
// if (!['1', '2', '3'].includes(record.contentStatus)) {
openModal1(true, { record, isOvertime: datetime });
// } else {
// router.push({ path: '/emergency/helpers', query: { imId: record.imId, checkedExpert: checkedExpert.value ? '0' : '1' } });
// }
}
function synchronous(record: Recordable) {
createConfirm({
iconType: 'info',
title: '确认同步',
content: '是否确认同步聊天记录',
okText: '确认',
cancelText: '取消',
onOk: async () => {
const { success, message: msg } = await syncImMessageApi({ groupId: record?.imId });
if (success) {
message.success('同步中,请稍后。');
} else {
message.error(msg);
}
},
});
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record: Recordable) {
return [
{
label: '聊天记录',
// disabled: ['1', '2', '3'].includes(record.contentStatus),
onClick: handleSession.bind(null, record),
},
{
label: '同步',
ifShow: isAdmin() || getEnvInfo().VITE_PLATFORM === 'YT',
onClick: synchronous.bind(null, record),
},
{
label: '就医信息维护',
onClick: handleK.bind(null, record),
ifShow: isQH() && record?.sessionType === '2',
},
];
}
function handleK(record: Recordable) {
const departs = record?.userInfo?.parentDepart;
let secondName = '';
if (departs && departs.length > 0) {
secondName = departs[departs.length - 1]?.departName;
} else {
secondName = record?.userInfo?.depart?.departName || '';
}
openModalM(true, {
record: {
...record,
orgCode: secondName + (record?.userInfo?.depart?.departName ? '-' + record?.userInfo?.depart?.departName : ''),
},
});
}
function isAdmin() {
const userInfo = userStore.getUserInfo || {};
return Object.keys(userStore.getFakeUserInfo).length > 0 || (userInfo?.roleCodes && userInfo?.roleCodes.includes('admin'));
}
const globSetting = useGlobSetting();
const apiUrl = globSetting.apiUrl;
imProps.value.urlF = apiUrl.replace('://', 'lol');
const getSig = () => {
userSigAndroidApi({})
.then((res) => {
imProps.value.userSig = res.userSig;
imProps.value.sdkAppId = res.sdkAppId;
imProps.value.userId = res.userId;
})
.catch((e) => {
console.log(e);
});
};
getSig();
/**
* 下拉操作栏
*/
// function getDropDownAction(record){
// return [
// {
// label: '详情',
// onClick: handleDetail.bind(null, record),
// }, {
// label: '删除',
// popConfirm: {
// title: '是否确认删除',
// confirm: handleDelete.bind(null, record),
// }
// }
// ]
// }
</script>
<style scoped lang="less">
.checkedPro {
height: 30px;
padding: 0 20px;
line-height: 30px;
border-radius: 10px;
background-color: #ffffff;
color: #000000;
cursor: pointer;
}
.checkedPro:hover {
opacity: 0.8;
}
.expert {
background-color: #466afb !important;
color: #ffffff !important;
}
</style>
@@ -0,0 +1,71 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
enum Api {
list = '/health-emergency/emergency/orderSendRecord/list',
save = '/health-emergency/emergency/orderSendRecord/add',
edit = '/health-emergency/emergency/orderSendRecord/edit',
deleteOne = '/health-emergency/emergency/orderSendRecord/delete',
deleteBatch = '/health-emergency/emergency/orderSendRecord/deleteBatch',
importExcel = '/health-emergency/emergency/orderSendRecord/importExcel',
exportXls = '/health-emergency/emergency/orderSendRecord/exportXls',
queryById = '/emergency/orderSendRecord/queryById',
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
export const queryByIdUrl = Api.queryById;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
* 删除单个
*/
export const deleteOne = (params, handleSuccess) => {
return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
},
});
};
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
const url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
@@ -0,0 +1,184 @@
import { BasicColumn, FormSchema } from '/@/components/Table';
import { render } from '/@/utils/common/renderUtils';
// 列表数据
export const columns: BasicColumn[] = [
{
title: '驻场人员',
align: 'center',
dataIndex: 'stationUserName',
},
// {
// title: '驻场人员部门',
// align: 'center',
// dataIndex: 'stationUserDepart',
// },
{
title: '是否接单',
align: 'center',
dataIndex: 'accept',
customRender: ({ text }) => {
return render.renderDict(text, 'emergency_order_send_accept');
},
},
{
title: '派单医院',
align: 'center',
dataIndex: 'sendOrderHospital',
},
{
title: '驻场人员派单业务',
align: 'center',
dataIndex: 'stationBusiness_dictText',
// 字典:emergency_send_order_type
},
{
title: '处理时间',
align: 'center',
dataIndex: 'transferOrderTime',
customRender: ({ text }) => {
return !text ? '' : text.length > 10 ? text.substr(0, 10) : text;
},
},
// {
// title: '状态(1-正常,2-冻结)',
// align:"center",
// dataIndex: 'status'
// },
// {
// title: '删除状态(0-正常,1-已删除)',
// align:"center",
// dataIndex: 'delFlag'
// },
// {
// title: '备注',
// align:"center",
// dataIndex: 'memo'
// },
];
// 查询数据
export const searchFormSchema: FormSchema[] = [
{
label: '驻场人员',
field: 'stationUserName',
component: 'Input',
},
{
label: '是否接单',
field: 'accept',
component: 'Select',
componentProps: {
options: [
{
value: null,
label: '请选择...',
},
{
value: 0,
label: '否',
},
{
value: 1,
label: '是',
},
],
},
},
];
// 表单数据
export const formSchema: FormSchema[] = [
{
label: '驻场人员',
field: 'stationUserName',
component: 'Input',
},
// {
// field: 'stationUserSex',
// component: 'JDictSelectTag',
// label: '性别',
// componentProps: {
// dictCode: 'sex',
// type: 'radioButton',
// },
// },
{
// label: '驻场人员部门:二级-三级(使用,隔开)',
label: '驻场人员部门',
field: 'stationUserDepart',
component: 'Input',
},
{
label: '是否接单',
field: 'accept',
component: 'RadioGroup',
componentProps: {
options: [
{
value: '0',
label: '否',
},
{
value: '1',
label: '是',
},
],
},
},
{
label: '派单医院',
field: 'sendOrderHospital',
component: 'Input',
},
{
label: '驻场人员派单业务',
field: 'stationBusiness_dictText',
component: 'Input',
},
{
label: '转单时间',
field: 'transferOrderTime',
component: 'DatePicker',
},
// {
// label: '状态(1-正常,2-冻结)',
// field: 'status',
// component: 'InputNumber',
// dynamicRules: ({model,schema}) => {
// return [
// { required: true, message: '请输入状态(1-正常,2-冻结)!'},
// ];
// },
// },
// {
// label: '删除状态(0-正常,1-已删除)',
// field: 'delFlag',
// component: 'InputNumber',
// dynamicRules: ({model,schema}) => {
// return [
// { required: true, message: '请输入删除状态(0-正常,1-已删除)!'},
// ];
// },
// },
// {
// label: '备注',
// field: 'memo',
// component: 'Input',
// },
// TODO 主键隐藏字段,目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
];
/**
* 流程表单调用这个方法获取formSchema
* @param _formData
*/
export function getBpmFormSchema(_formData): FormSchema[] {
// 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
return formSchema;
}
@@ -0,0 +1,111 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="null">
<!--插槽:table标题-->
<template #tableTitle></template>
<!--操作栏-->
<!-- <template #action="{ record }">-->
<!-- <TableAction :actions="getTableAction(record)" />-->
<!-- </template>-->
</BasicTable>
<!-- 表单区域 -->
<OrderSendRecordModal @register="registerModal" @success="handleSuccess" />
</div>
</template>
<script lang="ts" name="emergency-orderSendRecord" setup>
import { BasicTable, TableAction } from '/@/components/Table';
import { useModal } from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage';
import OrderSendRecordModal from './components/OrderSendRecordModal.vue';
import { columns, searchFormSchema } from './OrderSendRecord.data';
import { list } from './OrderSendRecord.api';
const props = defineProps({
orderId: String,
});
//注册model
const [registerModal, { openModal }] = useModal();
//注册table数据
const { tableContext } = useListPage({
tableProps: {
title: 'emergency_order_send_record',
api: list,
columns,
canResize: false,
formConfig: {
//labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter: true,
showAdvancedButton: false,
fieldMapToNumber: [],
fieldMapToTime: [],
baseColProps: {
xs: 8, // <576px
sm: 8, // ≥576px
md: 8, // ≥768px
lg: 8, // ≥992px
xl: 8, // ≥1200px
xxl: 8, // ≥1600px
},
actionColOptions: {
offset: 0,
span: 8,
xs: 8,
sm: 8,
md: 8,
lg: 8,
xl: 8,
xxl: 8,
},
},
beforeFetch: (info) => {
info['stationUserName'] = info['stationUserName'] && `*${info['stationUserName']}*`;
info['orderId'] = props.orderId;
delete info['order'];
return info;
},
actionColumn: {
ifShow: false,
width: 120,
fixed: 'right',
},
},
});
const [registerTable, { reload }] = tableContext;
/**
* 详情
*/
function handleDetail(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: false,
});
}
/**
* 成功回调
*/
function handleSuccess() {
reload();
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
},
];
}
</script>
<style scoped></style>
@@ -0,0 +1,66 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from '../OrderSendRecord.data';
import { saveOrUpdate } from '../OrderSendRecord.api';
// Emits声明
const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true);
//表单配置
const [registerForm, { setProps, resetFields, setFieldsValue, validate }] = useForm({
//labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { span: 24 },
});
//表单赋值
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//重置表单
await resetFields();
setModalProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
//表单赋值
await setFieldsValue({
...data.record,
});
}
// 隐藏底部时禁用整个表单
await setProps({ disabled: !data?.showFooter });
});
//设置标题
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
//表单提交事件
async function handleSubmit() {
try {
let values = await validate();
setModalProps({ confirmLoading: true });
//提交表单
await saveOrUpdate(values, isUpdate.value);
//关闭弹窗
closeModal();
//刷新列表
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>
@@ -0,0 +1,136 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
enum Api {
list = '/health-emergency/emergency/scheduleCustom/list',
save = '/health-emergency/emergency/scheduleCustom/add',
edit = '/health-emergency/emergency/scheduleCustom/edit',
deleteOne = '/health-emergency/emergency/scheduleCustom/delete',
deleteBatch = '/health-emergency/emergency/scheduleCustom/deleteBatch',
importExcel = '/health-emergency/emergency/scheduleCustom/importExcel',
exportXls = '/health-emergency/emergency/scheduleCustom/exportXls',
queryById = '/emergency/scheduleCustom/queryById',
delCustom = '/health-emergency/emergency/scheduleCustom/delCustom',
updateScheduleCustom = '/health-emergency/emergency/scheduleCustom/updateScheduleCustom',
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
export const queryByIdUrl = Api.queryById;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
* 删除单个
*/
export const deleteOne = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () =>
defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
}),
});
};
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
},
});
};
export const customDeleteOne = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除该数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.post({ url: Api.delCustom, data: params }).then(() => {
console.log('查询');
handleSuccess();
});
},
});
};
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
const url = isUpdate ? Api.edit : Api.updateScheduleCustom;
return defHttp.post({ url: url, params });
};
/**
* 专业人员列表
* */
export const professional = () => {
const arr = [
{
label: '张1',
value: '张1111',
},
{
label: '张2',
value: '张2222',
},
{
label: '张3',
value: '张3333',
},
];
return new Promise((resolve) => resolve(arr));
};
/**
* 专业人员列表
* */
export const operator = () => {
const arr = [
{
label: '李1',
value: '李1111',
},
{
label: '李2',
value: '李2222',
},
{
label: '李3',
value: '李3333',
},
];
return new Promise((resolve) => resolve(arr));
};
@@ -0,0 +1,150 @@
import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
import { personType2 } from '/@/views/emergency/outburst/ScheduleCustom/ScheduleDefault.api';
import { getPhysicalHospitalsList } from '/@/views/system/user/user.api';
//列表数据
export const columns: BasicColumn[] = [
{
title: '排班时间',
align: 'center',
dataIndex: 'scheduleTime',
},
{
title: '姓名',
align: 'center',
dataIndex: 'userName',
},
{
title: '类型',
align: 'center',
dataIndex: 'userType',
customRender: ({ text }) => {
return text == '0' ? '操作人员' : text == '1' ? '专业人员' : '';
},
},
{
title: '时间',
align: 'center',
dataIndex: 'type',
customRender: ({ text }) => {
return text == '0' ? '上午' : text == '1' ? '下午' : '';
},
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
{
label: '姓名',
field: 'userName',
component: 'Input',
},
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '排班时间',
field: 'time',
component: 'DatePicker',
dynamicRules: () => {
return [{ required: true, message: '请输入排班时间!' }];
},
componentProps: {
getPopupContainer: () => document.body,
valueFormat: 'YYYY-MM-DD',
},
},
{
label: '班次',
field: 'type',
component: 'RadioGroup',
componentProps: {
options: [
{
value: '2',
label: '全天',
},
{
value: '0',
label: '上午',
},
{
value: '1',
label: '下午',
},
],
},
dynamicRules: () => {
return [{ required: true, message: '请选择班次' }];
},
},
{
label: '操作人员',
field: 'operators',
component: 'ApiSelect',
componentProps: (res) => {
return {
api: personType2,
params: { personType: 5 },
resultField: 'list',
labelField: 'realname',
valueField: 'id',
mode: 'multiple',
getPopupContainer: () => document.body,
showSearch: true,
filterOption: (input: string, option: any): boolean => {
const str: string = input.toLowerCase();
return option.label.toLowerCase().indexOf(str) >= 0;
},
};
},
required: true,
},
{
label: '专业人员',
field: 'majors',
component: 'ApiSelect',
componentProps: {
api: personType2,
params: { personType: 6 },
resultField: 'list',
labelField: 'realname',
valueField: 'id',
mode: 'multiple',
getPopupContainer: () => document.body,
showSearch: true,
filterOption: (input: string, option: any): boolean => {
const str: string = input.toLowerCase();
return option.label.toLowerCase().indexOf(str) >= 0;
},
},
required: true,
},
// {
// label: '性别',
// field: 'userSex',
// component: 'JDictSelectTag',
// componentProps: {
// dictCode: 'sex',
// type: 'radioButton',
// },
// },
// TODO 主键隐藏字段,目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
];
// };
/**
* 流程表单调用这个方法获取formSchema
* @param _formData
*/
export function getBpmFormSchema(_formData): FormSchema[] {
// 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
return formSchema;
}
@@ -0,0 +1,168 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<!-- <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> -->
<!-- <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> -->
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined" />
删除
</a-menu-item>
</a-menu>
</template>
<a-button
>批量操作
<Icon icon="mdi:chevron-down" />
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
</template>
<!--字段回显插槽-->
<template #htmlSlot="{ text }">
<div v-html="text"></div>
</template>
<!--省市区字段回显插槽-->
<template #pcaSlot="{ text }">
{{ getAreaTextByCode(text) }}
</template>
<template #fileSlot="{ text }">
<span v-if="!text" style="font-size: 12px; font-style: italic">无文件</span>
<a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)"
>下载</a-button
>
</template>
</BasicTable>
<!-- 表单区域 -->
<ScheduleCustomModal @register="registerModal" @success="handleSuccess" />
</div>
</template>
<script lang="ts" name="emergency-scheduleCustom" setup>
import { ref, computed, unref } from 'vue';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { useModal } from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage';
import ScheduleCustomModal from './components/ScheduleCustomModal.vue';
import { columns, searchFormSchema } from './ScheduleCustom.data';
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './ScheduleCustom.api';
import { downloadFile } from '/@/utils/common/renderUtils';
const checkedKeys = ref<Array<string | number>>([]);
//注册model
const [registerModal, { openModal }] = useModal();
//注册table数据
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
tableProps: {
title: 'emergency_schedule_custom',
api: list,
columns,
canResize: false,
formConfig: {
//labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter: true,
showAdvancedButton: true,
fieldMapToNumber: [],
fieldMapToTime: [],
},
actionColumn: {
width: 120,
fixed: 'right',
},
},
exportConfig: {
name: 'emergency_schedule_custom',
url: getExportUrl,
},
importConfig: {
url: getImportUrl,
success: handleSuccess,
},
});
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
/**
* 新增事件
*/
function handleAdd() {
openModal(true, {
isUpdate: false,
showFooter: true,
});
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: true,
});
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: false,
});
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({ id: record.id }, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
];
}
/**
* 下拉操作栏
*/
function getDropDownAction(record) {
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
},
{
label: '删除',
onClick: handleDelete.bind(null, record),
},
];
}
</script>
<style scoped></style>
@@ -0,0 +1,117 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
import { resolve } from 'path';
const { createConfirm } = useMessage();
enum Api {
list = '/health-emergency/emergency/scheduleDefault/list',
save = '/health-emergency/emergency/scheduleDefault/add',
edit = '/health-emergency/emergency/scheduleDefault/edit',
deleteOne = '/health-emergency/emergency/scheduleDefault/delete',
deleteBatch = '/health-emergency/emergency/scheduleDefault/deleteBatch',
importExcel = '/health-emergency/emergency/scheduleDefault/importExcel',
exportXls = '/health-emergency/emergency/scheduleDefault/exportXls',
queryById = '/emergency/scheduleDefault/queryById',
personType = '/sys/api/listUserByPersonType',
updateScheduleDefault = '/health-emergency/emergency/scheduleDefault/updateScheduleDefault', //修改排班人员
// customList = '/health-emergency/emergency/scheduleCustom/list',
customList = '/health-emergency/emergency/scheduleCustom/listCustom',
updateScheduleCustom = '/health-emergency/emergency/scheduleCustom/updateScheduleCustom',
scheduleRecord = '/health-emergency/emergency/scheduleRecord/listCustom',
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
export const queryByIdUrl = Api.queryById;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
* @desc 操作 专业人员列表
* 5: 操作人员 6:专业人员
* */
export const personType = (params) => {
return new Promise((resolve) => {
defHttp.get({ url: Api.personType, params }).then((res) => {
resolve(res);
});
});
};
export const personType2 = async (params) => {
return await defHttp.get({ url: Api.personType, params });
};
export const updateScheduleDefault = (params) =>
defHttp.post({
url: Api.updateScheduleDefault,
params,
});
export const updateScheduleCustom = (params) =>
defHttp.post({
url: Api.updateScheduleCustom,
params,
});
/**
* 删除单个
*/
export const deleteOne = (params, handleSuccess) => {
return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp
.delete(
{
url: Api.deleteBatch,
data: params,
},
{ joinParamsToUrl: true }
)
.then(() => {
handleSuccess();
});
},
});
};
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
//自定义排班
//1.获取列表
export const customList = (params) => defHttp.get({ url: Api.customList, params });
// 排班记录
export const scheduleRecord = (params) => defHttp.get({ url: Api.scheduleRecord, params });
@@ -0,0 +1,535 @@
import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
import { render } from '/@/utils/common/renderUtils';
import dayjs from 'dayjs';
function getWeek(text) {
return render.renderDict(text, 'week');
}
function getTime(text) {
return render.renderDict(text, 'am_pm');
}
function getUserType(text) {
return text == '0' ? '操作人员' : text == '1' ? '专业人员' : '';
}
/**
* @time1
* @time2
* @desc 第二个时间是否更大,
* */
export function compareDate(time1, time2) {
const time = dayjs(time1).valueOf();
const today = dayjs(time2).format('YYYY-MM-DD');
return time < dayjs(`${today}`).valueOf();
}
export const day = {
today: () => new Date(),
nextDay: () => {
const day = new Date();
return day.getTime() + 24 * 60 * 60 * 1000;
},
};
//列表数据
export const columns: BasicColumn[] = [
{
title: '姓名',
align: 'center',
dataIndex: 'userName',
},
{
title: '星期',
align: 'center',
dataIndex: 'week',
customRender: ({ text }) => {
return getWeek(text);
},
},
{
title: '时间',
align: 'center',
dataIndex: 'type',
customRender: ({ text }) => {
return getTime(text);
},
},
{
title: '人员类型',
align: 'center',
dataIndex: 'userType',
customRender: ({ text }) => {
return getUserType(text);
},
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
{
label: '星期',
field: 'week',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'week',
},
},
];
//排班表格列表项
export const defaultColumns = [
{
title: '星期',
dataIndex: 'week_dictText',
key: 'week_dictText',
width: 80,
customCell: (_, index) => {
if (index % 2 === 0) {
return {
rowSpan: 2,
};
} else {
return {
rowSpan: 0,
};
}
},
},
{
title: '班次',
width: 80,
// dataIndex: 'type',
dataIndex: 'type_dictText',
// type_dictText
// customRender: ({ index }) => {
// return index % 2 == 0 ? '上午' : '下午';
// },
},
{
title: '值班人员',
children: [
{
title: '操作人员',
dataIndex: 'operations',
key: 'operations',
},
{
title: '专业人员',
dataIndex: 'majors',
key: 'majors',
},
],
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
width: 80,
},
];
export const defaultColumnData = [
{
time: null,
week: 1,
week_dictText: '星期一',
detail: [
{
type: '0',
type_dictText: '上午',
operations: [],
majors: [],
},
{
type: '1',
type_dictText: '下午',
operations: [],
majors: [],
},
],
},
{
time: null,
week: 2,
week_dictText: '星期二',
detail: [
{
type: '0',
type_dictText: '上午',
operations: [],
majors: [],
},
{
type: '1',
type_dictText: '下午',
operations: [],
majors: [],
},
],
},
{
time: null,
week: 3,
week_dictText: '星期三',
detail: [
{
type: '0',
type_dictText: '上午',
operations: [],
majors: [],
},
{
type: '1',
type_dictText: '下午',
operations: [],
majors: [],
},
],
},
{
time: null,
week: 4,
week_dictText: '星期四',
detail: [
{
type: '0',
type_dictText: '上午',
operations: [],
majors: [],
},
{
type: '1',
type_dictText: '下午',
operations: [],
majors: [],
},
],
},
{
time: null,
week: 5,
week_dictText: '星期五',
detail: [
{
type: '0',
type_dictText: '上午',
operations: [],
majors: [],
},
{
type: '1',
type_dictText: '下午',
operations: [],
majors: [],
},
],
},
{
time: null,
week: 6,
week_dictText: '星期六',
detail: [
{
type: '0',
type_dictText: '上午',
operations: [],
majors: [],
},
{
type: '1',
type_dictText: '下午',
operations: [],
majors: [],
},
],
},
{
time: null,
week: 7,
week_dictText: '星期日',
detail: [
{
type: '0',
type_dictText: '上午',
operations: [],
majors: [],
},
{
type: '1',
type_dictText: '下午',
operations: [],
majors: [],
},
],
},
];
// 1.处理默认排班格式
export function dealObj(obj, index) {
return {
week: obj.week,
week_dictText: render.renderDict(obj.week, 'week').children,
operations: obj.detail[index]['operations'].map((val) => val.userName).join('、'),
majors: obj.detail[index]['majors'].map((val) => val.userName).join('、'),
type_dictText: obj.detail[index].type_dictText,
type: obj.detail[index].type,
};
}
// 2.处理自定义排班格式
export function dealCustomObj(obj, index) {
return {
time: obj.time,
operations: obj.detail[index]['operations'].map((val) => val.userName).join('、'),
majors: obj.detail[index]['majors'].map((val) => val.userName).join('、'),
type_dictText: obj.detail[index].type_dictText,
type: obj.detail[index].type,
majorsId: obj.detail[index]['majors'].map((val) => val.userId),
operationsId: obj.detail[index]['operations'].map((val) => val.userId),
};
}
/**
* @defaultData 接口数据
* @dealObj 返回格式
* @desc 处理排班返回数据格式
* */
export function dealResData(defaultData, dealObj) {
const res = [];
defaultData &&
defaultData.map((item) => {
const obj1 = dealObj(item, 0);
const obj2 = dealObj(item, 1);
res.push(obj1);
res.push(obj2);
});
return res;
}
// 自定义排班表单配置
export const customSearchForm: FormSchema[] = [
{
field: 'date',
component: 'DatePicker',
label: '排班时间',
colProps: {
span: 6,
},
componentProps: {
placeholder: '请选择排班时间',
valueFormat: 'YYYY-MM-DD',
},
},
{
field: 'amOrPm',
component: 'Select',
label: '排班班次',
colProps: {
span: 6,
},
componentProps: {
options: [
{
label: '上午',
value: '0',
},
{
label: '下午',
value: '1',
},
],
placeholder: '请选择班次',
},
},
];
//排班记录表格列表项
export const recordColumns = [
{
title: '排班时间',
dataIndex: 'time',
key: 'time',
width: 120,
customCell: (_, index) => {
if (index % 2 === 0) {
return {
rowSpan: 2,
};
} else {
return {
rowSpan: 0,
};
}
},
},
{
title: '班次',
width: 80,
dataIndex: 'type',
customRender: ({ text }) => text && render.renderDict(text, 'am_pm'),
},
{
title: '值班人员',
children: [
{
title: '操作人员',
dataIndex: 'operations',
key: 'operations',
},
{
title: '专业人员',
dataIndex: 'majors',
key: 'majors',
},
],
},
];
export const customColumns = [
{
title: '排班时间',
dataIndex: 'time',
key: 'time',
width: 120,
customCell: (_, index) => {
if (index % 2 === 0) {
return {
rowSpan: 2,
};
} else {
return {
rowSpan: 0,
};
}
},
},
{
title: '班次',
width: 80,
dataIndex: 'type',
customRender: ({ text }) => text && render.renderDict(text, 'am_pm'),
},
{
title: '值班人员',
children: [
{
title: '操作人员',
dataIndex: 'operations',
key: 'operations',
},
{
title: '专业人员',
dataIndex: 'majors',
key: 'majors',
},
],
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
width: 80,
},
];
// 处理自定义排班数据
export function dealData(customData) {
const arr = {};
for (const jsonElement of customData) {
if (!arr.hasOwnProperty(jsonElement.scheduleTime)) {
arr[jsonElement.scheduleTime] = {
'0': { ...jsonElement, '0': [], '1': [] },
'1': { ...jsonElement, '0': [], '1': [] },
};
}
if (jsonElement.type && jsonElement.userType) {
arr[jsonElement.scheduleTime][jsonElement.type][jsonElement.userType].push(jsonElement);
}
}
const result = [];
for (const j in arr) {
for (const k in arr[j]) {
result.push(arr[j][k]);
}
}
return result;
}
// 处理数据返回格式
export function renderType(type) {
return render.renderDict(type, 'am_pm').children;
}
//自定义表单新增
export const formSchema: FormSchema[] = [
{
label: '姓名',
field: 'userName',
component: 'Input',
dynamicRules: () => {
return [{ required: true, message: '请输入${label}!' }];
},
},
{
label: '星期',
field: 'week',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'week',
stringToNumber: true,
},
},
{
label: '类型',
field: 'type',
component: 'RadioGroup',
componentProps: {
options: [
{
value: '0',
label: '上午',
},
{
value: '1',
label: '下午',
},
],
},
},
{
label: '人员类型',
field: 'userType',
component: 'RadioGroup',
componentProps: {
options: [
{
value: '0',
label: '操作人员',
},
{
value: '1',
label: '专业人员',
},
],
},
},
{
label: '性别',
field: 'userSex',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'sex',
type: 'radioButton',
},
},
// TODO 主键隐藏字段,目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
];
/**
* 流程表单调用这个方法获取formSchema
* @param _formData
*/
export function getBpmFormSchema(_formData): FormSchema[] {
// 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
return formSchema;
}
@@ -0,0 +1,327 @@
<template>
<div class="schedule-default-list">
<div class="schedule-def-content">
<a-tabs v-model:activeKey="activeKey" :destroyInactiveTabPane="true">
<template #rightExtra>
<a-button v-show="activeKey === '2'" type="primary" preIcon="ant-design:plus-outlined" @click="customDataAdd">新增 </a-button>
</template>
<a-tab-pane key="1" tab="默认排班">
<a-table :columns="defaultColumns" :data-source="defaultState.columnData" bordered size="small" :pagination="false">
<template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'action'">
<a @click="defaultEdit(record, index)">编辑</a>
</template>
</template>
</a-table>
</a-tab-pane>
<a-tab-pane key="2" tab="自定义排班">
<BasicForm
:labelWidth="80"
:schemas="customSearchForm"
:actionColOptions="{ span: 8 }"
@submit="handleSubmit"
@reset="resetFields"
/>
<a-table
:columns="customColumns"
:data-source="customState.customData"
@change="changeTable"
border
size="small"
:pagination="paginationState"
>
<template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'action'">
<table-action :actions="getTableAction(record, index)" />
</template>
</template>
</a-table>
</a-tab-pane>
<a-tab-pane key="3" tab="值班记录">
<schedule-tab v-if="activeKey === '3'" />
</a-tab-pane>
</a-tabs>
</div>
<ScheduleCustomModal v-if="activeKey === '2'" @register="registerModal" @success="handleSuccess" />
<default-drawer-edit ref="defaultEditRef" :edit-data="defaultEditData" :visible="visible" @submit="defaultSubmit" />
<custom-drawer-edit ref="customEditRef" :edit-data="customEditData" :visibleCustom="visibleCustom" @on-submit="customSubmit" />
</div>
</template>
<script setup lang="ts">
import { nextTick, onMounted, reactive, ref, watch } from 'vue';
import {
compareDate,
customColumns,
customSearchForm,
dealCustomObj,
dealObj,
dealResData,
defaultColumnData,
defaultColumns,
day,
} from './ScheduleDefault.data';
import { BasicForm } from '/@/components/Form';
import { useModal } from '/@/components/Modal';
import { TableAction } from '/@/components/Table';
import ScheduleCustomModal from './components/ScheduleCustomModal.vue';
import DefaultDrawerEdit from '/@/views/emergency/outburst/ScheduleCustom/components/DefaultDrawerEdit.vue';
import CustomDrawerEdit from '/@/views/emergency/outburst/ScheduleCustom/components/CustomDrawerEdit.vue';
import ScheduleTab from '/@/views/emergency/outburst/ScheduleCustom/components/ScheduleTab.vue';
import {
customList,
list,
personType,
updateScheduleCustom,
updateScheduleDefault,
} from '/@/views/emergency/outburst/ScheduleCustom/ScheduleDefault.api';
import { customDeleteOne } from '/@/views/emergency/outburst/ScheduleCustom/ScheduleCustom.api';
const activeKey = ref('1');
let visible = ref(false);
let visibleCustom = ref(false);
const defaultEditRef = ref(null);
const customEditRef = ref(null);
let defaultState = reactive({
columnData: dealResData(defaultColumnData, dealObj),
apiData: [],
});
let paginationState = ref({
current: 1,
pageSize: 10,
pageSizeOptions: ['5', '10', '50', '80', '100'],
total: 0,
showQuickJumper: true,
size: 'small',
showTotal: (total) => ' 共 ' + total / 2 + ' 条数据',
});
// 当前排班
onMounted(() => {
getDefaultList();
});
function getDefaultList() {
list('').then((res) => {
let params = res.length > 0 ? res : defaultColumnData;
defaultState.apiData = params;
defaultState.columnData = dealResData(params, dealObj);
});
}
const defaultEditData = reactive({});
/**
* @Description:默认排班编辑
* @date 2023/6/26
*/
async function defaultEdit(row, index) {
let i = Math.floor(index / 2);
const rowData = defaultState.apiData[i]?.detail[row.type] || {};
const operationOptions = await personType({ personType: 5 });
const majorOptions = await personType({ personType: 6 });
Object.assign(defaultEditData, {
...row,
majors: rowData?.majors?.map((item) => item.userId) || [],
operations: rowData?.operations?.map((item) => item.userId) || [],
renderType: () => row.week_dictText + row.type_dictText,
majorOptions,
operationOptions,
});
defaultEditRef?.value?.openDrawer(defaultEditData);
}
function defaultSubmit(data) {
updateScheduleDefault(data).then(() => {
getDefaultList();
});
}
watch(activeKey, (val) => {
const fun = {
'1': getDefaultList,
'2': getCustomList,
'3': () => 1,
};
return fun[val]();
});
//自定义排班
const customState = reactive({
form: {
date: '',
type: '',
},
customData: [],
apiData: [],
});
/**
* @Description:自定义表单查询
* @date 2023/6/26
*/
function handleSubmit(val) {
customState.form = val;
getCustomList(1);
}
/**
* @Description:自定义排版表单重置
* @date 2023/6/26
*/
function resetFields() {
let form = customState.form;
for (const key in form) {
customState.form[key] = '';
}
nextTick(() => {
customState.form = form;
getCustomList(1);
});
}
/**
* @Description: 获取自定义页码
* @date 2023/6/20
*/
function getCustomList(pageNo?: number) {
const params = {
...customState.form,
pageNo: pageNo ?? paginationState.value.current,
pageSize: 5,
};
return customList(params).then((res) => {
nextTick(() => {
customState.customData = dealResData(res.records, dealCustomObj);
customState.apiData = res.records;
const { current, total } = res;
paginationState.value = {
...paginationState.value,
current,
total: total * 2,
};
});
});
}
/**
* @Description:页码改变事件
* @date 2023/6/20
* @param pagination
*/
const changeTable = (pagination) => {
paginationState.value.current = pagination.current;
paginationState.value.pageSize = 10;
getCustomList();
};
//注册model
const [registerModal, { openModal }] = useModal();
/**
* @Description:自定义排班操作列
* @date 2023/6/26
*/
function getTableAction(record, index) {
return [
{
label: '编辑',
disabled: compareDate(record.time, day.nextDay()),
onClick: customEdit.bind(null, record, index),
},
{
label: '删除',
disabled: compareDate(record.time, day.nextDay()),
onClick: customDelete.bind(null, record),
},
];
}
/**
* @Description:自定义排班新增
* @date 2023/6/26
*/
function customDataAdd() {
openModal(true, {
isUpdate: false,
showFooter: true,
});
}
const customEditData = reactive({
scheduleTime: '',
type: '',
opeVal: [],
opeOptions: [],
proVal: [],
proOptions: [],
});
/**
* @Description:自定义排班编辑
* @date 2023/6/26
* @param:
*/
async function customEdit(row) {
const operationOptions = await personType({ personType: 5 });
const majorOptions = await personType({ personType: 6 });
Object.assign(customEditData, {
...row,
majors: row.majorsId,
operations: row.operationsId,
majorOptions,
operationOptions,
});
customEditRef?.value?.openDrawer(customEditData);
}
/**
* @Description:自定义排班编辑成功后更新列表
* @date 2023/6/26
* @param:
*/
function customSubmit(data) {
updateScheduleCustom(data).then(() => {
getCustomList();
});
}
/**
* @Description:自定义排版删除
* @date 2023/6/26
* @param:{row}
*/
function customDelete(row) {
const params = {
time: row.time,
amOrPm: row.type,
};
customDeleteOne(params, getCustomList);
}
function handleSuccess() {
getCustomList();
}
</script>
<style lang="less" scoped>
.schedule-default-list {
padding: 10px 10px 0 10px;
height: 100%;
overflow: hidden;
}
.schedule-def-content {
box-sizing: border-box;
padding: 12px;
height: 100%;
overflow: auto;
background-color: #fff;
}
.edit-content {
.form-item {
margin: 16px 0;
}
.form-label {
}
}
:deep(table tr, table th, table td) {
border-right: 1px solid #f0f0f0 !important;
border-bottom: 1px solid #f0f0f0 !important;
}
</style>
@@ -0,0 +1,127 @@
<template>
<a-drawer forceRender v-model:visible="drawerData.visibleCustom" width="420" :title="title" placement="right" @close="onClose">
<template #extra>
<a-button style="margin-right: 8px" @click="onClose">取消</a-button>
<a-button type="primary" @click="onSubmit">确认</a-button>
</template>
<div class="edit-content">
<div class="form-item">
<span class="form-label">排班时间</span>
<span>{{ drawerData.time }}</span>
</div>
<div class="form-item">
<span class="form-label">排班班次</span>
<span>{{ renderType(drawerData.type) }}</span>
</div>
<div class="form-item">
<span class="form-label">操作人员</span>
<a-select
v-model:value="drawerData.operations"
:options="drawerData.operationOptions"
:fieldNames="{ label: 'realname', value: 'id' }"
mode="tags"
size="middle"
placeholder="请选择"
style="width: 220px"
/>
</div>
<div class="form-item">
<span class="form-label">专业人员</span>
<a-select
v-model:value="drawerData.majors"
:options="drawerData.majorOptions"
:fieldNames="{ label: 'realname', value: 'id' }"
mode="tags"
size="middle"
placeholder="请选择"
style="width: 220px"
/>
</div>
</div>
</a-drawer>
</template>
<script setup lang="ts">
import { reactive } from 'vue';
import { renderType } from '/@/views/emergency/outburst/ScheduleCustom/ScheduleDefault.data';
const props = defineProps({
visibleCustom: {
type: Boolean,
default: () => false,
},
title: {
type: String,
default: () => '编辑',
},
editData: {
type: Object,
},
});
const $emits = defineEmits(['onSubmit']);
const drawerData = reactive({
visibleCustom: props.visibleCustom,
majors: [],
operations: [],
majorOptions: [],
operationOptions: [],
time: '',
type: '',
...props.editData,
});
// 打开事件
function openDrawer(data) {
Object.assign(drawerData, { ...data });
drawerData.visibleCustom = true;
}
// 关闭事件
function onClose() {
drawerData.visibleCustom = false;
}
function filterData(data, filterData) {
let arr = [];
data.map((val) => {
let row = {};
filterData.map((item) => {
if (val.id === item) {
row = { userName: val.realname, userSex: val.sex, userId: val.id };
arr.push(row);
}
});
});
return arr;
}
function getSubmitData() {
return {
time: drawerData.time,
amOrPm: drawerData.type,
operators: filterData(drawerData.operationOptions, drawerData.operations),
majors: filterData(drawerData.majorOptions, drawerData.majors),
};
}
function onSubmit() {
const data = {
time: drawerData.time,
amOrPm: drawerData.type,
operators: filterData(drawerData.operationOptions, drawerData.operations),
majors: filterData(drawerData.majorOptions, drawerData.majors),
};
$emits('onSubmit', data);
onClose();
}
defineExpose({
openDrawer,
getSubmitData,
});
</script>
<style scoped lang="less">
.edit-content {
.form-item {
margin: 16px 0;
}
.form-label {
}
}
</style>
@@ -0,0 +1,129 @@
<template>
<a-drawer v-model:visible="drawerData.visible" width="420" title="编辑" placement="right" @close="onClose">
<template #extra>
<a-button style="margin-right: 8px" @click="onClose">取消</a-button>
<a-button type="primary" @click="submit">确认</a-button>
</template>
<div class="edit-content">
<div class="form-item">
<span class="form-label">排班班次</span>
<span>{{ drawerData.renderType() }}</span>
</div>
<div class="form-item">
<span class="form-label">操作人员</span>
<a-select
v-model:value="drawerData.operations"
:options="drawerData.operationOptions"
:fieldNames="{ label: 'realname', value: 'id' }"
showSearch
:filterOption="optionFilter"
mode="multiple"
size="middle"
placeholder="请选择"
style="width: 220px"
/>
</div>
<div class="form-item">
<span class="form-label">专业人员</span>
<a-select
v-model:value="drawerData.majors"
:options="drawerData.majorOptions"
:fieldNames="{ label: 'realname', value: 'id' }"
showSearch
:filter-option="optionFilter"
mode="multiple"
size="middle"
placeholder="请选择"
style="width: 220px"
/>
</div>
</div>
</a-drawer>
</template>
<script setup lang="ts">
import { reactive } from 'vue';
import { message } from 'ant-design-vue';
const props = defineProps({
visible: {
type: Boolean,
default: () => false,
},
title: {
type: String,
default: () => '编辑',
},
editData: {
type: Object,
},
});
const $emits = defineEmits(['submit']);
const drawerData = reactive({
visible: props.visible,
majors: [],
operations: [],
majorOptions: [],
operationOptions: [],
week: '',
type: '',
...props.editData,
});
function openDrawer(data) {
Object.assign(drawerData, { ...data });
drawerData.visible = true;
}
/**
* @Description:根据输入项进行筛选
* @date 2023/6/25
*/
function optionFilter(input: string, option: any): boolean {
const str: string = input.toLowerCase();
return option.realname.toLowerCase().indexOf(str) >= 0;
}
// 关闭事件
function onClose() {
drawerData.visible = false;
}
function filterData(data, filterData) {
let arr = [];
data.map((val) => {
let row = {};
filterData.map((item) => {
if (val.id === item) {
row = { userName: val.realname, userSex: val.sex, userId: val.id };
arr.push(row);
}
});
});
return arr;
}
function submit() {
const data = {
week: drawerData.week,
amOrPm: drawerData.type,
operators: filterData(drawerData.operationOptions, drawerData.operations),
majors: filterData(drawerData.majorOptions, drawerData.majors),
};
if (data.operators.length < 1) {
return message.warn('操作人员不能为空');
}
if (data.majors.length < 1) {
return message.warn('专业人员不能为空');
}
$emits('submit', data);
onClose();
}
defineExpose({
openDrawer,
});
</script>
<style scoped lang="less">
.edit-content {
.form-item {
margin: 16px 0;
}
.form-label {
}
}
</style>
@@ -0,0 +1,104 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from '../ScheduleCustom.data';
import { saveOrUpdate } from '../ScheduleCustom.api';
import { personType } from '/@/views/emergency/outburst/ScheduleCustom/ScheduleDefault.api';
import { message } from 'ant-design-vue';
// Emits声明
const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true);
//表单配置
const [registerForm, { setProps, resetFields, setFieldsValue, validate }] = useForm({
//labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { span: 24 },
});
//表单赋值
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//重置表单
await resetFields();
setModalProps({
confirmLoading: false,
showCancelBtn: !!data?.showFooter,
showOkBtn: !!data?.showFooter,
});
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
//表单赋值
await setFieldsValue({
...data.record,
});
}
// 隐藏底部时禁用整个表单
setProps({ disabled: !data?.showFooter });
});
//设置标题
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
function filterData(data, filterData) {
let arr = [];
data.map((val) => {
let row = {};
filterData.map((item) => {
if (val.id === item) {
row = { userName: val.realname, userSex: val.sex, userId: val.id };
arr.push(row);
}
});
});
return arr;
}
//表单提交事件
async function handleSubmit() {
try {
let values = await validate();
const operationOptions = await personType({ personType: 5 });
const majorOptions = await personType({ personType: 6 });
const params = {
time: values.time,
amOrPm: values.type,
operators: filterData(operationOptions, values.operators?.split(',') || []),
majors: filterData(majorOptions, values.majors?.split(',') || []),
};
setModalProps({ confirmLoading: true });
if (!params.operators.length && !params.majors.length) {
return message.warn('操作人员或专业人员至少填写一条数据');
}
// 选择全天
if (values.type === '2') {
await saveOrUpdate({ ...params, amOrPm: '0' }, isUpdate.value);
await saveOrUpdate({ ...params, amOrPm: '1' }, isUpdate.value);
} else {
await saveOrUpdate(params, isUpdate.value);
}
//提交表单
//关闭弹窗
closeModal();
//刷新列表
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>
@@ -0,0 +1,66 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from '../ScheduleDefault.data';
import { saveOrUpdate } from '../ScheduleDefault.api';
// Emits声明
const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true);
//表单配置
const [registerForm, { setProps, resetFields, setFieldsValue, validate }] = useForm({
//labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { span: 24 },
});
//表单赋值
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//重置表单
await resetFields();
setModalProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
//表单赋值
await setFieldsValue({
...data.record,
});
}
// 隐藏底部时禁用整个表单
await setProps({ disabled: !data?.showFooter });
});
//设置标题
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
//表单提交事件
async function handleSubmit() {
try {
let values = await validate();
setModalProps({ confirmLoading: true });
//提交表单
await saveOrUpdate(values, isUpdate.value);
//关闭弹窗
closeModal();
//刷新列表
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>
@@ -0,0 +1,75 @@
<template>
<BasicForm :labelWidth="80" :schemas="customSearchForm" :actionColOptions="{ span: 6 }" @submit="handleSubmit" @reset="resetFields" />
<a-table :columns="recordColumns" :pagination="paginationState" @change="changeTable" :data-source="customState.customData" border size="small" />
</template>
<script setup lang="ts">
import { recordColumns, customSearchForm, dealCustomObj, dealResData } from '/@/views/emergency/outburst/ScheduleCustom/ScheduleDefault.data';
import { BasicForm } from '/@/components/Form';
import { nextTick, reactive, ref, onMounted } from 'vue';
import { scheduleRecord } from '/@/views/emergency/outburst/ScheduleCustom/ScheduleDefault.api';
const customState = reactive({
form: {
date: '',
type: '',
},
customData: [],
apiData: [],
});
let paginationState = ref({
current: 1,
pageSize: 10,
showSizeChanger: false,
// pageSizeOptions: ['10', '50', '80', '100'],
total: 0,
showQuickJumper: true,
size: 'small',
showTotal: (total) => ' 共 ' + total / 2 + ' 条数据',
});
onMounted(() => {
getCustomList();
});
function getCustomList(pageNo?: number) {
const pageSize = paginationState.value.pageSize === 10 ? 5 : paginationState.value.pageSize / 2;
const params = {
...customState.form,
pageNo: pageNo ?? paginationState.value.current,
pageSize: pageSize,
};
scheduleRecord(params).then((res) => {
customState.customData = dealResData(res.records, dealCustomObj);
customState.apiData = res.records;
const { current, total } = res;
paginationState.value = {
...paginationState.value,
current,
total: total * 2,
};
});
}
/**
* @Description:页码改变事件
* @date 2023/6/20
* @param pagination
*/
const changeTable = (pagination: { current: number; pageSize: number }) => {
paginationState.value.current = pagination.current;
paginationState.value.pageSize = pagination.pageSize;
getCustomList();
};
function resetFields() {
let form = customState.form;
for (const key in form) {
customState.form[key] = '';
}
nextTick(() => {
customState.form = form;
getCustomList(1);
});
}
function handleSubmit(val) {
customState.form = val;
getCustomList(1);
}
</script>
@@ -0,0 +1,95 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
enum Api {
list = '/health-emergency/emergency/order/list',
newList = '/health-emergency/emergency/order/listOrderMajor',
save = '/health-emergency/emergency/order/add',
edit = '/health-emergency/emergency/order/edit',
deleteOne = '/health-emergency/emergency/order/delete',
deleteBatch = '/health-emergency/emergency/order/deleteBatch',
importExcel = '/health-emergency/emergency/order/importExcel',
exportXls = '/health-emergency/emergency/order/exportXls',
queryById = '/health-emergency/emergency/order/queryById',
employeeUnit = '/sys/sysDepart/allSecondaryDeparts', //员工单位
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
export const queryByIdUrl = Api.queryById;
/**
* 请求编辑数据
*/
export const resEditData = async (params) => {
return await defHttp.get({ url: Api.queryById, params });
};
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
export const newList = (params) => defHttp.get({ url: Api.newList, params });
/**
* 删除单个
*/
export const deleteOne = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () =>
defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
}),
});
};
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
},
});
};
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
const url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
/**
* 获取员工单位
* */
export const employeeUnit = (params) => {
return defHttp.get({ url: Api.employeeUnit, params });
};
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,79 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
enum Api {
list = '/health-emergency/emergency/orderDetail/list',
save = '/health-emergency/emergency/orderDetail/add',
edit = '/health-emergency/emergency/orderDetail/edit',
deleteOne = '/health-emergency/emergency/orderDetail/delete',
deleteBatch = '/health-emergency/emergency/orderDetail/deleteBatch',
importExcel = '/health-emergency/emergency/orderDetail/importExcel',
exportXls = '/health-emergency/emergency/orderDetail/exportXls',
queryById = '/emergency/orderDetail/queryById',
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
export const queryByIdUrl = Api.queryById;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
* 删除单个
*/
export const deleteOne = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () =>
defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
}),
});
};
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
},
});
};
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
const url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
@@ -0,0 +1,96 @@
import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
//列表数据
export const columns: BasicColumn[] = [
{
title: '评价',
align: 'center',
dataIndex: 'orderEvaluation',
},
{
title: '事件经过',
align: 'center',
dataIndex: 'orderThrough',
},
{
title: '事件结果',
align: 'center',
dataIndex: 'orderResult',
},
// {
// title: '状态(1-正常,2-冻结)',
// align:"center",
// dataIndex: 'status'
// },
// {
// title: '删除状态(0-正常,1-已删除)',
// align:"center",
// dataIndex: 'delFlag'
// },
// {
// title: '备注',
// align:"center",
// dataIndex: 'memo'
// },
];
//查询数据
export const searchFormSchema: FormSchema[] = [];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '评价',
field: 'orderEvaluation',
component: 'Input',
},
{
label: '事件经过',
field: 'orderThrough',
component: 'InputTextArea',
},
{
label: '事件结果',
field: 'orderResult',
component: 'InputTextArea',
},
// {
// label: '状态(1-正常,2-冻结)',
// field: 'status',
// component: 'InputNumber',
// dynamicRules: ({model,schema}) => {
// return [
// { required: true, message: '请输入状态(1-正常,2-冻结)!'},
// ];
// },
// },
// {
// label: '删除状态(0-正常,1-已删除)',
// field: 'delFlag',
// component: 'InputNumber',
// dynamicRules: ({model,schema}) => {
// return [
// { required: true, message: '请输入删除状态(0-正常,1-已删除)!'},
// ];
// },
// },
// {
// label: '备注',
// field: 'memo',
// component: 'Input',
// },
// TODO 主键隐藏字段,目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
];
/**
* 流程表单调用这个方法获取formSchema
* @param _formData
*/
export function getBpmFormSchema(_formData): FormSchema[] {
// 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
return formSchema;
}
@@ -0,0 +1,164 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined" />
删除
</a-menu-item>
</a-menu>
</template>
<a-button
>批量操作
<Icon icon="mdi:chevron-down" />
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
</template>
<!--字段回显插槽-->
<template #htmlSlot="{ text }">
<div v-html="text"></div>
</template>
<!--省市区字段回显插槽-->
<template #pcaSlot="{ text }">
{{ getAreaTextByCode(text) }}
</template>
<template #fileSlot="{ text }">
<span v-if="!text" style="font-size: 12px; font-style: italic">无文件</span>
<a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)"
>下载</a-button
>
</template>
</BasicTable>
<!-- 表单区域 -->
<OrderDetailModal @register="registerModal" @success="handleSuccess" />
</div>
</template>
<script lang="ts" name="emergency-orderDetail" setup>
import { BasicTable, TableAction } from '/@/components/Table';
import { useModal } from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage';
import OrderDetailModal from './components/OrderDetailModal.vue';
import { columns, searchFormSchema } from './OrderDetail.data';
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './OrderDetail.api';
import { downloadFile } from '/@/utils/common/renderUtils';
//注册model
const [registerModal, { openModal }] = useModal();
//注册table数据
const { tableContext, onExportXls, onImportXls } = useListPage({
tableProps: {
title: 'emergency_order_detail',
api: list,
columns,
canResize: false,
formConfig: {
//labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter: true,
showAdvancedButton: true,
fieldMapToNumber: [],
fieldMapToTime: [],
},
actionColumn: {
width: 120,
fixed: 'right',
},
},
exportConfig: {
name: 'emergency_order_detail',
url: getExportUrl,
},
importConfig: {
url: getImportUrl,
success: handleSuccess,
},
});
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
/**
* 新增事件
*/
function handleAdd() {
openModal(true, {
isUpdate: false,
showFooter: true,
});
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: true,
});
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: false,
});
}
/**
* 删除事件
*/
function handleDelete(record: Recordable) {
deleteOne({ id: record.id }, handleSuccess);
}
/**
* 批量删除事件
*/
function batchHandleDelete() {
batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record: Recordable) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
];
}
/**
* 下拉操作栏
*/
function getDropDownAction(record: Recordable) {
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
},
{
label: '删除',
onClick: handleDelete.bind(null, record),
},
];
}
</script>
@@ -0,0 +1,180 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
</BasicTable>
<!-- 表单区域 -->
<!--详情弹窗-->
<OrderDrawer ref="RefOrderDrawer" />
<detail ref="detailRef" />
<OrderRecord @register="registerModal" />
</div>
</template>
<script lang="ts" name="emergency-order" setup>
import { ref, nextTick } from 'vue';
import { BasicColumn, BasicTable, TableAction } from '/@/components/Table';
import { useModal } from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage';
import OrderDrawer from './components/OrderDrawer.vue';
import { columns, searchFormSchema, columnsPersonF, columnsPersonS, searchFormSchemaS } from './Order.data';
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl, resEditData, newList } from './Order.api';
import { message } from 'ant-design-vue';
import { useUserStore } from '/@/store/modules/user';
import detail from '/@/views/emergency/communication/components/detail.vue';
import { router } from '/@/router';
import OrderRecord from '/@/views/emergency/outburst/order/components/OrderRecord.vue';
//注册model
const [registerModal, { openModal }] = useModal();
const userStore = useUserStore();
const useColumns: BasicColumn[] =
userStore.getUserInfo.personType === '5' ? columnsPersonF : userStore.getUserInfo.personType === '6' ? columnsPersonS : columns;
//注册table数据
const { tableContext } = useListPage({
tableProps: {
title: 'emergency_order',
api: userStore.getUserInfo.personType === '6' ? newList : list,
columns: useColumns,
canResize: false,
rowSelection: false,
formConfig: {
//labelWidth: 120,
schemas: userStore.getUserInfo.personType === '6' ? searchFormSchemaS : searchFormSchema,
autoSubmitOnEnter: true,
showAdvancedButton: false,
fieldMapToNumber: [],
fieldMapToTime: [],
},
showActionColumn: userStore.getUserInfo?.personType !== '6',
actionColumn: {
width: 200,
fixed: 'right',
},
beforeFetch: (info) => {
// 对日期选择器的处理
const createTimeRange = info?.createTimeRange?.split(',');
if (createTimeRange) {
return { ...info, createTimeStart: createTimeRange[0], createTimeEnd: createTimeRange[1] };
}
},
},
exportConfig: {
name: 'emergency_order',
url: getExportUrl,
},
importConfig: {
url: getImportUrl,
success: handleSuccess,
},
});
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
/**
* 详情
*/
const RefOrderDrawer = ref();
function handleDetail(record: Recordable) {
resEditData({ id: record.id }).then((res) => {
nextTick(() => {
RefOrderDrawer.value.showDrawer(res);
});
});
}
/**
* 删除事件
*/
function handleDelete(record: Recordable) {
deleteOne({ id: record.id }, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/*
* 咨询详情
* */
function handleZDetail(record: Recordable) {
router.push({ path: `/emergency/communication`, query: { sessionId: record.sessionId } });
}
const detailRef = ref();
/*
* 应急详情
* */
function handleYDetail(res) {
detailRef.value.showDrawer(res.id);
}
/**
* @Description:派单记录
* @date 2023/6/29
* @param record 列表数据
*/
function orderRecord(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: false,
});
}
/**
* 操作栏
*/
function getTableAction(record: Recordable) {
let result = [
{
label: '应急工单',
onClick: handleDetail.bind(null, record),
auth: 'emergency:emergency_order:edit',
},
{
label: '派单记录',
onClick: orderRecord.bind(null, record),
},
{
label: '删除',
onClick: handleDelete.bind(null, record),
},
];
switch (userStore.getUserInfo?.personType) {
case '5':
result = [
{
label: '应急详情',
onClick: handleYDetail.bind(null, record),
auth: '',
},
];
break;
case '6':
result = [
{
label: '咨询详情',
onClick: handleZDetail.bind(null, record),
auth: '',
},
];
break;
}
return result;
}
</script>
<style lang="less" scoped>
:deep(.ant-popover-buttons) {
display: flex !important;
}
</style>
@@ -0,0 +1,66 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from '../OrderDetail.data';
import { saveOrUpdate } from '../OrderDetail.api';
// Emits声明
const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true);
//表单配置
const [registerForm, { setProps, resetFields, setFieldsValue, validate }] = useForm({
//labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { span: 24 },
});
//表单赋值
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//重置表单
await resetFields();
setModalProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
//表单赋值
await setFieldsValue({
...data.record,
});
}
// 隐藏底部时禁用整个表单
await setProps({ disabled: !data?.showFooter });
});
//设置标题
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
//表单提交事件
async function handleSubmit(v) {
try {
let values = await validate();
setModalProps({ confirmLoading: true });
//提交表单
await saveOrUpdate(values, isUpdate.value);
//关闭弹窗
closeModal();
//刷新列表
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>
@@ -0,0 +1,136 @@
<template>
<a-drawer
:title="title"
:headerStyle="{ textAlign: 'left' }"
width="80%"
placement="right"
:closable="true"
v-model:visible="open"
@close="onClose"
>
<div>
<div>
<CommonDesc title="应急员工信息" :descList="descList1" :descRes="descRes">
<template #salvageUserName="{ row }">
{{ row.val }}
<!-- <span class="span-action" @click="btn(row)">更改被救助人</span>-->
</template>
</CommonDesc>
</div>
<div class="desc-item">
<CommonDesc title="工单信息" :descList="descList2" :descRes="descRes" />
</div>
<div class="desc-item">
<CommonDesc title="应急小结" :column="1" :descList="descList3" :descRes="descRes" />
<!-- <a-descriptions title="应急小结" :column="1" bordered :label-style="{ width: '110px', padding: '12px 12px' }">-->
<!-- <a-descriptions-item label="应急经过" :column="{ xxl: 4, xl: 3, lg: 3, md: 3, sm: 2, xs: 1 }">-->
<!-- <a-textarea v-model:value="descRes.orderThrough" />-->
<!-- </a-descriptions-item>-->
<!-- <a-descriptions-item label="应急结果" :column="{ xxl: 4, xl: 3, lg: 3, md: 3, sm: 2, xs: 1 }">-->
<!-- <a-textarea v-model:value="descRes.orderResult" />-->
<!-- </a-descriptions-item>-->
<!-- </a-descriptions>-->
</div>
<div class="desc-item">
<!-- <a-descriptions title="应急过程" />-->
<!-- <div>-->
<!-- <span class="span-action">视频</span>-->
<!-- <span class="span-action">聊天记录</span>-->
<!-- </div>-->
<CommonDesc class="desc-item-process" title="救护车" :descList="descList4" :descRes="descRes" />
<CommonDesc class="desc-item-process" title="单位车辆" :descList="descList5" :descRes="descRes" />
<CommonDesc class="desc-item-process" title="救助信息" :descList="descList6" :descRes="descRes" />
</div>
<div class="scene-photo desc-item">
<div class="scene-photo-label"> 现场照片</div>
<div class="photo-list">
<ImagePreview :imageList="imgList" />
</div>
</div>
<div class="desc-item">
<CommonDesc title="" :column="1" :descList="descList7" :descRes="descRes" />
</div>
</div>
</a-drawer>
</template>
<script setup lang="ts">
import { ref, nextTick } from 'vue';
import CommonDesc from '/@/views/emergency/outburst/order/components/commonDesc.vue';
import { descList1, descList2, descList3, descList4, descList5, descList6, descList7 } from '/@/views/emergency/outburst/order/Order.data';
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
import { ImagePreview } from '/@/components/Preview/index';
let title = '应急工单';
let open = ref(false);
const descRes = ref({});
const imgList = ref([]);
const showDrawer = (data) => {
nextTick(() => {
open.value = true;
descRes.value = {
...data,
...data.orderDetail,
};
imgList.value = data.orderDetail?.imgs?.split(',').map((item) => ({
width: 150,
height: 150,
src: getFileAccessHttpUrl(item),
}));
});
};
const onClose = () => {
open.value = false;
};
function btn(scope) {
console.log('--->scope', scope);
}
// 暴露给父组件
defineExpose({
showDrawer,
});
</script>
<style scoped lang="less">
.scene-photo {
display: flex;
flex-direction: column;
.scene-photo-label {
font-weight: bold;
}
.photo-list {
flex: 1;
display: flex;
.photo-style {
display: flex;
}
}
}
.span-action {
color: #1890ff;
cursor: pointer;
margin-left: 5px;
}
.desc-item {
margin-top: 16px;
}
.desc-item-process {
margin-top: 12px;
}
@prefix-cls: ~'@{namespace}-image-preview';
.@{prefix-cls} {
display: flex;
.ant-image {
margin-right: 10px;
border-radius: 8px;
}
}
</style>
@@ -0,0 +1,66 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from '../Order.data';
import { saveOrUpdate } from '../Order.api';
// Emits声明
const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true);
//表单配置
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
//labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { span: 24 },
});
//表单赋值
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//重置表单
await resetFields();
setModalProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
//表单赋值
await setFieldsValue({
...data.record,
});
}
// 隐藏底部时禁用整个表单
setProps({ disabled: !data?.showFooter });
});
//设置标题
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
//表单提交事件
async function handleSubmit(v) {
try {
let values = await validate();
setModalProps({ confirmLoading: true });
//提交表单
await saveOrUpdate(values, isUpdate.value);
//关闭弹窗
closeModal();
//刷新列表
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>
@@ -0,0 +1,28 @@
<template>
<div>
<BasicModal v-bind="$attrs" :title="title" :width="1200" @register="registerModal" destroyOnClose>
<div style="max-height: 70vh; overflow: auto">
<OrderSendRecordList :orderId="orderId" />
</div>
</BasicModal>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import OrderSendRecordList from '/@/views/emergency/outburst/OrderSendRecord/OrderSendRecordList.vue';
const title = '派单记录';
const orderId = ref('');
const [registerModal, { setModalProps }] = useModalInner(async (data) => {
console.log('orderId', data.record.id);
orderId.value = data.record.id;
setModalProps({
confirmLoading: false,
showCancelBtn: !!data?.showFooter,
showOkBtn: !!data?.showFooter,
});
});
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,47 @@
<template>
<a-descriptions :title="title" :column="column" bordered :label-style="labelStyle">
<a-descriptions-item
v-for="(item, i) in descList"
:key="i"
:label="item.label"
:span="item.spanNumber || 1"
:column="{ xxl: 4, xl: 3, lg: 3, md: 3, sm: 2, xs: 1 }"
>
<slot v-if="item.hasOwnProperty('slot')" :name="item.slot" :row="{ item, val: descRes?.[item.key] }"></slot>
<div v-else-if="item.hasOwnProperty('render')">
{{ item.render(descRes[item.key]) || '' }}
</div>
<div v-else-if="item.type === 'richText'" v-html="descRes?.[item.key]"></div>
<div v-else>
{{ (item.key && descRes[item.key]) || '' }}
</div>
</a-descriptions-item>
</a-descriptions>
</template>
<script setup lang="ts">
/**
* @column 一行排列几个
* @descList 数据描述列表
* @descRes 结果数据
* */
const props = defineProps({
title: String,
descList: {
type: Array,
default: () => [],
},
descRes: {
type: Object,
default: () => {},
},
column: {
type: Number,
default: () => 3,
},
labelStyle: {
type: Object,
default: () => ({ width: '110px', padding: '12px 12px' }),
},
});
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,79 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
enum Api {
list = '/health-emergency/emergency/resource/list',
save = '/health-emergency/emergency/resource/add',
edit = '/health-emergency/emergency/resource/edit',
deleteOne = '/health-emergency/emergency/resource/delete',
deleteBatch = '/health-emergency/emergency/resource/deleteBatch',
importExcel = '/health-emergency/emergency/resource/importExcel',
exportXls = '/health-emergency/emergency/resource/exportXls',
queryById = '/emergency/resource/queryById',
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
export const queryByIdUrl = Api.queryById;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
* 删除单个
*/
export const deleteOne = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () =>
defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
}),
});
};
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
},
});
};
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
const url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
@@ -0,0 +1,194 @@
import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
import { render } from '/@/utils/common/renderUtils';
//列表数据
export const columns: BasicColumn[] = [
{
title: '资源名称',
align: 'center',
dataIndex: 'name',
},
{
title: '资源类型',
align: 'center',
dataIndex: 'type',
customRender: ({ text }) => {
return render.renderDict(text, 'resource_type');
},
},
{
title: '医院等级',
align: 'center',
dataIndex: 'level',
customRender: ({ text }) => {
return render.renderDict(text, 'hospital_level');
},
},
{
title: '详细地址',
align: 'center',
dataIndex: 'address',
},
{
title: '联系电话',
align: 'center',
dataIndex: 'mobile',
},
{
title: '介绍/简介',
align: 'center',
dataIndex: 'aidrange',
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
{
label: '资源名称',
field: 'name',
component: 'Input',
},
{
label: '资源类型',
field: 'type',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'resource_type',
},
},
{
label: '医院等级',
field: 'level',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'hospital_level',
},
},
{
label: '介绍/简介',
field: 'aidrange',
component: 'Input',
},
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '资源类型',
field: 'type',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'resource_type',
},
required: true,
},
{
label: '资源名称',
field: 'name',
component: 'Input',
componentProps: ({ schema, formModel }) => {
// 急救员
if (formModel?.type == '6') {
schema.label = '医生姓名';
} else {
schema.label = '资源名称';
}
},
dynamicRules: () => {
return [{ required: true, message: '请输入资源名称!' }];
},
},
{
label: '医院等级',
field: 'level',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'hospital_level',
},
// 处理特殊类型不展示医院等级
ifShow: (params) => !['4', '5', '6'].includes(params.values?.type),
required: true,
},
// {
// field: 'province',
// component: 'JAreaSelect',
// label: '省市区',
// // defaultValue: ['610101'],
// defaultValue: ['140000', '140300', '140302']
// },
{
label: '介绍/简介',
field: 'aidrange',
component: 'InputTextArea',
},
{
label: '网址',
field: 'url',
component: 'Input',
rules: [
{ required: false, pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '网址格式有误' },
],
ifShow: (params) => !['5', '6'].includes(params.values?.type),
},
{
label: '图片',
field: 'img',
component: 'JImageUpload',
},
{
label: '地址',
field: 'customAddress',
component: 'Input',
slot: 'customAddress',
rules: [{ required: true }],
ifShow: false,
},
{
label: '详细地址',
field: 'address',
component: 'Input',
slot: 'address',
required: true,
},
{
label: '联系电话',
field: 'mobile',
component: 'Input',
rules: [{ required: true, pattern: /^1[3456789]\d{9}$/, message: '手机号码格式有误' }],
},
{
label: '经度',
field: 'longitude',
component: 'InputNumber',
// required: true,
ifShow: false,
},
{
label: '纬度',
field: 'latitude',
component: 'InputNumber',
// required: true,
ifShow: false,
},
// {
// label: '高德地图数据',
// field: 'gdId',
// component: 'Input',
// },
// TODO 主键隐藏字段,目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
];
/**
* 流程表单调用这个方法获取formSchema
* @param param
*/
export function getBpmFormSchema(_formData): FormSchema[] {
// 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
return formSchema;
}
@@ -0,0 +1,172 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined" v-auth="'emergency:emergency_resource:add'">
新增
</a-button>
<a-button
type="primary"
@click="batchHandleDelete"
preIcon="ant-design:delete-outlined"
v-auth="'emergency:emergency_resource:delete'"
>
批量删除
</a-button>
<!-- <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> -->
<!-- <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> -->
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
<!--字段回显插槽-->
<template #htmlSlot="{ text }">
<div v-html="text"></div>
</template>
</BasicTable>
<!-- 表单区域 -->
<ResourceModal @register="registerDrawer" @success="handleSuccess" />
</div>
</template>
<script lang="ts" name="emergency-resource" setup>
import { ref } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import { useModal } from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage';
import ResourceModal from './components/ResourceModal.vue';
import { columns, searchFormSchema } from './Resource.data';
import { batchDelete, deleteOne, getExportUrl, getImportUrl, list } from './Resource.api';
import { message } from 'ant-design-vue';
import { useDrawer } from '/@/components/Drawer';
const checkedKeys = ref<Array<string | number>>([]);
//注册model
const [registerDrawer, { openDrawer }] = useDrawer();
//注册table数据
const { prefixCls, tableContext } = useListPage({
tableProps: {
title: '应急资源',
api: list,
columns,
canResize: false,
formConfig: {
//labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter: true,
showAdvancedButton: false,
fieldMapToNumber: [],
fieldMapToTime: [],
},
actionColumn: {
width: 160,
fixed: 'right',
},
beforeFetch: (info) => {
info['name'] = info?.name && `*${info.name}*`;
info['aidrange'] = info?.aidrange && `*${info.aidrange}*`;
return info;
},
},
exportConfig: {
name: '应急资源',
url: getExportUrl,
},
importConfig: {
url: getImportUrl,
success: handleSuccess,
},
});
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
/**
* 新增事件
*/
function handleAdd() {
openDrawer(true, {
isUpdate: false,
showFooter: true,
title: '新增',
});
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
openDrawer(true, {
record,
isUpdate: true,
showFooter: true,
title: '编辑',
});
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
openDrawer(true, {
record,
isUpdate: true,
showFooter: false,
title: '详情',
});
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({ id: record.id }, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
if (selectedRowKeys.value.length === 0) {
return message.warning('未选中任何数据');
}
await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
auth: 'emergency:emergency_resource:edit',
},
{
label: '详情',
onClick: handleDetail.bind(null, record),
},
{
label: '删除',
onClick: handleDelete.bind(null, record),
auth: 'emergency:emergency_resource:delete',
},
];
}
</script>
<style lang="less" scoped>
:deep(.ant-popover-buttons) {
display: flex !important;
}
</style>
@@ -0,0 +1,117 @@
<template>
<BasicDrawer v-bind="$attrs" :showFooter="showFooter" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
<BasicForm @register="registerForm">
<template #address="{ model }">
<a-input style="width: 82%" v-model:value="model['address']" :disabled="true" />
<a-button style="margin-left: 10px" @click="viewMap" :disabled="!showFooter">查看地图</a-button>
</template>
</BasicForm>
<Map @register="registerMap" :state="state" ref="map" @get-position="getPosition" />
</BasicDrawer>
</template>
<script lang="ts" setup>
import { ref, unref } from 'vue';
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from '../Resource.data';
import { saveOrUpdate } from '../Resource.api';
import Map from '/@/views/consult/resource/components/Map.vue';
import { useModal } from '/@/components/Modal';
// Emits声明
const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true);
const showFooter = ref<boolean>(true);
const state = ref();
//设置标题
const title = ref<string>('');
//表单配置
const [registerForm, { setProps, resetFields, setFieldsValue, validate, getFieldsValue, clearValidate }] = useForm({
//labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { span: 24 },
});
const [registerMap, { openModal }] = useModal();
//表单赋值
const [registerModal, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
//重置表单
await resetFields();
setDrawerProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter });
isUpdate.value = !!data?.isUpdate;
showFooter.value = data.showFooter;
title.value = data.title;
let customAddress = '';
if (unref(isUpdate)) {
customAddress = `${data.record?.longitude}${data.record?.latitude}`;
//表单赋值
await setFieldsValue({
...data.record,
customAddress,
});
state.value = data.record;
} else {
state.value = {};
}
await clearValidate();
// 隐藏底部时禁用整个表单
await setProps({ disabled: !data?.showFooter });
});
function viewMap() {
openModal(true, {
record: { ...getFieldsValue() },
});
}
async function getPosition(val) {
let { pname, cityname, adname, address, name } = val.handleItem || '';
let nameList = [pname, cityname, adname, address, name];
let str = '';
nameList.map((item) => {
if (item !== undefined) {
str += item;
}
});
await setFieldsValue({
latitude: val.lat,
longitude: val.lng,
customAddress: `${val.lng}${val.lat}`,
address: str,
});
state.value = {
...state.value,
latitude: val.lat,
longitude: val.lng,
};
}
//表单提交事件
async function handleSubmit() {
try {
let values = await validate();
setDrawerProps({ confirmLoading: true });
const params = {
...state.value,
...values,
};
//提交表单
await saveOrUpdate(params, isUpdate.value);
//关闭弹窗
closeDrawer();
//刷新列表
emit('success');
} finally {
setDrawerProps({ confirmLoading: false });
}
}
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>
@@ -0,0 +1,117 @@
<template>
<BasicDrawer
v-bind="$attrs"
@register="registerDrawer"
destroyOnClose
:title="title"
:width="600"
@ok="handleSubmit"
:showFooter="showFooter"
:maskClosable="false"
>
<div class="form-container" v-show="title != '详情'">
<BasicForm @register="registerForm" />
</div>
<div class="form-container" v-show="title == '详情'">
<MedicalCard :list="getDetailSchema()" title="" />
</div>
</BasicDrawer>
</template>
<script lang="ts" setup>
import { ref, unref } from 'vue';
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
import { BasicForm, useForm } from '/@/components/Form/index';
import { saveOrUpdate } from '../personnelManagement.api';
import { useDrawerAdaptiveWidth } from '/@/hooks/jeecg/useAdaptiveWidth';
import { dealPassword } from '/@/views/system/user/user.data';
import { formSchema, getPersonType, useDetailForm } from '/@/views/emergency/personnelManagement/personnelManagement.data';
import MedicalCard from '/@/views/interveneNew/medicalPoints/components/medicalCard.vue';
import { useRoute } from 'vue-router';
const { adaptiveWidth } = useDrawerAdaptiveWidth();
// Emits声明
const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true);
const showFooter = ref(true);
//设置标题
const title = ref('');
const route = useRoute();
/**
* 5 操作人员
* 6 专业人员
*/
const type = getPersonType(route.path.split('/').pop() as string);
const { setDetailFormData, getDetailSchema } = useDetailForm(type == 6);
//表单配置
const [registerForm, { setProps, resetFields, setFieldsValue, validate, clearValidate, updateSchema }] = useForm({
labelWidth: 120,
schemas: formSchema(type == 6),
showActionButtonGroup: false,
baseColProps: { span: 24 },
});
//表单赋值
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
//重置表单
await resetFields();
setDrawerProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter });
isUpdate.value = !!data?.isUpdate;
title.value = data.type;
if (unref(isUpdate)) {
//表单赋值
await setFieldsValue({
...data.record,
});
setDetailFormData(data.record);
}
await clearValidate();
// 隐藏底部时禁用整个表单
await setProps({ disabled: !data?.showFooter });
});
//表单提交事件
async function handleSubmit() {
try {
let data = await validate();
if (!isUpdate.value) {
data = {
...data,
password: dealPassword(data?.password),
};
}
setDrawerProps({ confirmLoading: true });
//提交表单
await saveOrUpdate({ ...data, type }, isUpdate.value);
//关闭弹窗
closeDrawer();
//刷新列表
emit('success');
} finally {
setDrawerProps({ confirmLoading: false });
}
}
</script>
<style lang="less" scoped>
.form-container {
overflow: auto;
}
.title {
box-sizing: border-box;
color: #333;
font-weight: bold;
padding: 12px 16px;
}
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
:deep(.ant-picker) {
width: 100% !important;
}
</style>
@@ -0,0 +1,61 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm } = useMessage();
export enum Api {
list = '/health-emergency/emergency/profession/user/list',
save = '/health-emergency/emergency/profession/user/add',
edit = '/health-emergency/emergency/profession/user/edit',
deleteOne = '/health-emergency/emergency/profession/user/deleteBatch',
deleteBatch = '/health-emergency/emergency/profession/user/deleteBatch',
}
/**
* 列表接口
* @param params
*/
export const list = (params: any) => defHttp.get({ url: Api.list, params });
/**
* 删除单个
*/
export const deleteOne = (params: any, handleSuccess: Function) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.post({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
},
});
};
/**
* 批量删除
* @param params
* @param handleSuccess
*/
export const batchDelete = (params: any, handleSuccess: Function) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.post({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
},
});
};
/**
* 保存或者更新
* @param params
* @param isUpdate
*/
export const saveOrUpdate = (params: any, isUpdate: Boolean) => {
const url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
@@ -0,0 +1,397 @@
import { BasicColumn, FormSchema } from '/@/components/Table';
import { h, ref } from 'vue';
import { checkPassword } from '/@/hooks/checkPassword/checkPassword';
import { getEmergencyList } from '/@/views/consult/agentManagement/agentManagement.api';
import { allCenterApi } from '/@/views/emergency/scheduling/scheduling.api';
import { rules } from '/@/utils/helper/validator';
import { Image } from 'ant-design-vue';
import { getFamaleDefaultImage, getFileAccessHttpUrl } from '/@/utils/common/compUtils';
import { EyeOutlined } from '@ant-design/icons-vue';
import { ComponentType } from '/@/components/Form/src/types';
//列表数据
export const columns = function (showGoodAt: boolean): BasicColumn[] {
return [
{
title: '用户账号',
align: 'center',
width: 150,
fixed: 'left',
dataIndex: 'username',
},
{
title: '姓名',
align: 'center',
fixed: 'left',
dataIndex: 'realname',
},
{
title: '头像',
align: 'center',
dataIndex: 'avatar',
width: 100,
customRender: ({ text }) => {
const t = text ? text.replace(',', '') : null;
return h(Image, {
placeholder: true,
src: getFileAccessHttpUrl(t),
height: 50,
width: 50,
fallback: getFamaleDefaultImage(''),
previewMask: () => {
return h(EyeOutlined, {
style: {
color: 'white',
},
});
},
});
},
},
{
title: '所属应急中心',
align: 'center',
dataIndex: 'centerName',
},
{
title: '职称',
align: 'center',
width: 90,
dataIndex: 'post_dictText',
},
{
title: '毕业院校',
align: 'center',
dataIndex: 'school',
},
{
title: '学历',
align: 'center',
dataIndex: 'edu_dictText',
},
{
title: '擅长症状',
align: 'center',
dataIndex: 'goodAt',
ifShow: showGoodAt,
},
];
};
//查询数据
export const searchFormSchema: FormSchema[] = [
{
label: '姓名',
field: 'name',
component: 'Input',
},
{
label: '所属应急中心',
field: 'centerId',
component: 'ApiSelect',
componentProps: {
//@ts-ignore
api: allCenterApi,
labelField: 'centerName',
valueField: 'id',
immediate: true,
resultField: 'records',
showSearch: true,
filterOption: (input: string, option: any): boolean => {
const str: string = input?.trim()?.toLowerCase();
return option.label.toLowerCase().indexOf(str) >= 0;
},
getPopupContainer: () => document.body,
},
},
];
//表单数据
// @ts-ignore
export const formSchema = function (showGoodAt: boolean): FormSchema[] {
return [
// 主键Id
{
label: '',
field: 'userId',
show: false,
component: 'Input',
},
{
label: '用户账号',
field: 'username',
component: 'Input',
componentProps: ({ formModel }) => {
return {
autocomplete: 'off',
onInput: (event: Event) => {
const target = event.target;
formModel.username = target?.value?.replace(/[^\w]/g, '');
},
};
},
rules: [{ required: true, message: '请输入用户账号' }],
dynamicDisabled: ({ values }) => {
return !!values.userId;
},
},
{
label: '头像',
field: 'avatar',
component: 'JImageUpload',
required: true,
componentProps: () => ({
maxCount: 1,
}),
},
{
label: '密码',
field: 'password',
component: 'StrengthMeter',
componentProps: {
//@ts-ignore
autocomplete: 'new-password',
readOnly: true,
onfocus: (field) => {
field.target.readOnly = false;
},
},
dynamicRules: () => {
return [
{
required: true,
validator: (_, value) => {
const { message } = checkPassword(value);
if (message === 'ok') {
return Promise.resolve();
} else {
return Promise.reject(message);
}
},
trigger: 'blur',
},
];
},
ifShow: ({ values }) => {
return !values.userId;
},
},
{
label: '确认密码',
field: 'confirmPassword',
component: 'InputPassword',
dynamicRules: ({ values }) => rules.confirmPassword(values, true),
ifShow: ({ values }) => {
return !values.userId;
},
},
{
label: '姓名',
field: 'realname',
component: 'Input',
required: true,
},
{
label: '所属应急中心',
field: 'centerId',
component: 'ApiSelect',
required: true,
componentProps: {
//@ts-ignore
api: getEmergencyList,
params: {
pageNo: 1,
pageSize: 200,
},
labelField: 'centerName',
valueField: 'id',
immediate: true,
resultField: 'records',
showSearch: true,
filterOption: (input: string, option: any): boolean => {
const str: string = input?.trim()?.toLowerCase();
return option.label.toLowerCase().indexOf(str) >= 0;
},
getPopupContainer: () => document.body,
},
},
{
label: '擅长症状',
field: 'goodAt',
component: 'InputTextArea',
required: true,
ifShow: showGoodAt,
},
{
label: '职称',
field: 'post',
component: 'JDictSelectTag',
componentProps: () => ({
dictCode: 'z_doct_lev',
getPopupContainer: () => document.body,
}),
required: true,
},
{
label: '毕业院校',
field: 'school',
component: 'Input',
},
{
label: '学历',
field: 'edu',
component: 'JDictSelectTag',
componentProps: {
//@ts-ignore
dictCode: 'education',
showSearch: true,
filterOption: (input: string, option: any): boolean => {
const str: string = input.trim().toLowerCase();
return option.label.toLowerCase().indexOf(str) >= 0;
},
getPopupContainer: () => document.body,
},
},
{
label: '人员类型',
field: 'type',
component: 'Input',
show: false,
},
];
};
interface DetailForm extends FormSchema {
value: string;
customRender?: Function;
component: ComponentType | 'Image';
}
export function useDetailForm(showGoodAt: boolean) {
const detailFormSchema = ref<DetailForm[]>([
{
label: '用户账号',
field: 'username',
component: 'Input',
value: '',
},
{
label: '姓名',
field: 'realname',
component: 'Input',
value: '',
},
{
label: '头像',
field: 'avatar',
component: 'Image',
value: '',
},
{
label: '所属应急中心',
field: 'centerName',
component: 'Input',
value: '',
},
{
label: '职称',
field: 'post_dictText',
component: 'Input',
value: '',
},
{
label: '毕业院校',
field: 'school',
component: 'Input',
value: '',
},
{
label: '学历',
field: 'edu_dictText',
component: 'Input',
value: '',
},
{
label: '擅长症状',
field: 'goodAt',
component: 'InputTextArea',
value: '',
ifShow: showGoodAt,
},
]);
function setData(record: Recordable, list: DetailForm[], callback?: Function) {
if (callback) {
callback(list);
return;
}
list = list.filter((item) => {
return item.ifShow === undefined || item.ifShow;
});
list.forEach((item) => {
const { field } = item;
const isEmpty = (obj, field) => {
if (!obj) return true;
return obj[field] === undefined || obj[field] === null || obj[field] === '';
};
if (!isEmpty(record, field)) {
if (Object.hasOwn(item, 'customRender')) {
// @ts-ignore
item.value = item.customRender(record);
} else if (Object.hasOwn(item, 'slot')) {
//@ts-ignore
item.value = { ...record, dataIndex: field };
} else {
item.value = record[field] || '';
}
} else {
item.value = '';
}
});
return list;
}
function getDetailSchema() {
return detailFormSchema.value.filter((item) => {
return item.ifShow === undefined || item.ifShow;
});
}
function setDetailFormData(record: Recordable) {
//@ts-ignore
setData(record, getDetailSchema());
}
return {
detailFormSchema,
getDetailSchema,
setDetailFormData,
};
}
/**
* 流程表单调用这个方法获取formSchema
*/
export function getBpmFormSchema(): FormSchema[] {
// 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
return formSchema;
}
/**
* @description: 人员类型
*/
export function getPersonType(t: string) {
enum PersonType {
'professional' = '6', //专业人员
'operation' = '5', //操作人员
}
return PersonType[t];
}
export const week_text = (key) => {
const type = {
1: '星期一',
2: '星期二',
3: '星期三',
4: '星期四',
5: '星期五',
6: '星期六',
7: '星期日',
};
return type[key];
};
@@ -0,0 +1,187 @@
<template>
<div>
<!--引用表格-->
<BasicTable :rowSelection="rowSelection" @register="registerTable">
<!--插槽:table标题-->
<template #tableTitle>
<a-button v-auth="'profession:person_add'" preIcon="ant-design:plus-outlined" type="primary" @click="handleAdd"> 新增 </a-button>
<a-button v-auth="'profession:person_delete'" @click="batchHandleDelete" type="primary" preIcon="ant-design:delete-outlined"
>批量删除
</a-button>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
</template>
</BasicTable>
<!-- 表单区域 -->
<PersonnelModal @register="registerDrawer" @success="handleSuccess" />
<!--修改密码-->
<RestPass @register="restPassModal" />
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { useRoute } from 'vue-router';
import { message } from 'ant-design-vue';
import { useDrawer } from '/@/components/Drawer';
import { useMethods } from '/@/hooks/system/useMethods';
import { useMessage } from '/@/hooks/web/useMessage';
import { useModal } from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage';
import { BasicTable, TableAction } from '/@/components/Table';
import { columns, getPersonType, searchFormSchema } from './personnelManagement.data';
import { batchDelete, deleteOne, list } from './personnelManagement.api';
import RestPass from '/@/views/system/user/restPass/RestPass.vue';
import PersonnelModal from './components/personnelModal.vue';
const taskCode = ref('');
const drawerTitle = ref('');
const { handleImportXls } = useMethods();
const { createMessage } = useMessage();
const route = useRoute();
const [registerDrawer, { openDrawer: openFormDrawer }] = useDrawer();
//注册model
const [restPassModal, { openModal: restPaddModel }] = useModal();
/**
* 5 操作人员
* 6 专业人员
*/
const type = getPersonType(route.path.split('/').pop() as string);
//注册table数据
const { tableContext } = useListPage({
tableProps: {
title: '应急分中心-操作人员/专业人员',
api: list,
columns: columns(type == 6),
canResize: false,
showIndexColumn: true,
rowKey: 'userId',
formConfig: {
labelWidth: 100,
schemas: searchFormSchema,
autoSubmitOnEnter: true,
showAdvancedButton: false,
fieldMapToNumber: [],
fieldMapToTime: [],
},
beforeFetch: (par) => {
par['type'] = type;
return par;
},
actionColumn: {
width: 180,
fixed: 'right',
},
},
});
const [registerTable, { reload, getForm, getDataSource }, { rowSelection, selectedRowKeys }] = tableContext;
const [registerExport, { openDrawer }] = useDrawer();
/**
* 新增
*/
function handleAdd() {
openFormDrawer(true, {
isUpdate: false,
showFooter: true,
type: '新增',
});
}
/**
* 编辑事件
*/
async function handleEdit(record: Recordable) {
openFormDrawer(true, {
record,
isUpdate: true,
showFooter: true,
type: '编辑',
});
}
/**
* 详情事件
*/
async function handleDetail(record: Recordable) {
openFormDrawer(true, {
record,
isUpdate: true,
showFooter: false,
type: '详情',
});
}
/**
* 删除事件
*/
function handleDelete(record: Recordable) {
deleteOne({ ids: record.userId }, handleSuccess);
}
/**
* 批量删除事件
*/
function batchHandleDelete() {
if (selectedRowKeys.value.length === 0) {
message.warning('未选中任何数据');
return;
}
batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
reload();
}
/**
* 操作栏
*/
function getTableAction(record: Recordable) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
auth: 'profession:person_update',
},
{
label: '详情',
onClick: handleDetail.bind(null, record),
},
];
}
// 重置密码
function restPass(record: Recordable) {
restPaddModel(true, {
record: record.userId,
isUpdate: true,
showFooter: false,
});
}
/**
* 下拉操作栏
*/
function getDropDownAction(record: Recordable) {
return [
{
label: '删除',
onClick: handleDelete.bind(null, record),
auth: 'profession:person_delete',
},
{
label: '重置密码',
onClick: restPass.bind(null, record),
auth: 'profession:person_reset_pass',
},
];
}
</script>
<style lang="less" scoped>
:deep(.ant-popover-buttons) {
display: flex !important;
}
</style>

Some files were not shown because too many files have changed in this diff Show More