policeSecurity/policeManagement/src/views/query/publicUnit.vue

763 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

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

<template>
<div>
<TableProMax
style="width: 100%"
:expandedRowRender="expandedRowRender"
:expand-column-width="50"
:defaultExpandAllRows="false"
ref="tableRef"
:request-api="reqApi"
:columns="columns"
:searchFormOptions="searchFormOptions"
:scroll="{ x: x }"
>
<template #tableHeader>
<a-space>
<a-button type="primary" @click="saveOrUpdateEnterprisesUnit">新增企事业单位</a-button>
</a-space>
</template>
</TableProMax>
<!-- <a-modal v-model:open="visible" :title="serviceTitle" @ok="submit" @cancel="closeModal">
<FormProMax ref="formRef" v-model:value="formParams" :form-item-options="formItemOptions" />
</a-modal> -->
</div>
</template>
<script setup lang="tsx">
import { deleteDataModal } from '@/components/tsx/ModalPro.tsx'
import { EnterprisesUnitSaveOrUpdateParams } from '@/types/views/unitManage/police/policeUnit.ts'
import MapContainer from '@/components/aMap/MapContainer.vue'
import { AutoComplete, Button, Input, message, Modal, Space } from 'ant-design-vue'
import { debounce } from 'lodash-es'
import FormProMax from '@/components/form/FormProMax.vue'
import api from '@/axios'
// createVNode
import { ref, reactive, computed, onMounted, createVNode } from 'vue'
import TableProMax from '@/components/table/TableProMax.vue'
import { TableProMaxProps } from '@/types/components/table/index.ts'
import { ComponentExposed } from 'vue-component-type-helpers'
import { dictSelectNodes } from '@/config/dict.ts'
import { publicUnitPagerQueryParams } from '@/types/views/publicUnit.ts'
import { FormProMaxItemOptions } from '@/types/components/form//index.ts'
import { FormExpose } from 'ant-design-vue/es/form/Form'
import { serviceProjectSaveOrUpdateParams_ } from '@/types/views/serviceManagement'
import { showEnterprisesUnit } from './index.tsx'
var modal: any
type _FormType = EnterprisesUnitSaveOrUpdateParams & {
contactPersonInfoName?: string
contactPersonInfoTelephone?: string
}
type TableProps = TableProMaxProps<publicUnitPagerQueryParams>
const reqApi: TableProps['requestApi'] = (params) => api.post('/eu/pager', params) //分页
const tableRef = ref<ComponentExposed<typeof TableProMax>>(null)
const columns: TableProps['columns'] = [
{
dataIndex: 'name',
title: '单位名称',
width: 200,
},
{
dataIndex: 'provinceName',
title: '行政区划',
customRender: ({ record }) => {
return `${record?.provinceName}/${record?.cityName}/${record?.districtsName}/${record?.streetName}`
},
width: 300,
},
{
dataIndex: 'address',
title: '详细地址',
width: 200,
ellipsis: true,
},
{
dataIndex: 'contactPersonInfo',
title: '联系人姓名',
customRender: ({ record }) => {
return record?.contactPersonInfo?.name
},
width: 200,
},
{
dataIndex: 'contactPersonInfo',
title: '联系人手机号',
customRender: ({ record }) => {
return record?.contactPersonInfo?.telephone
},
width: 150,
},
{
dataIndex: 'createTime',
title: '创建时间',
width: 120,
ellipsis: true,
},
{
dataIndex: 'remark',
title: '备注',
width: 120,
ellipsis: true,
},
{
width: 200,
dataIndex: 'opt',
title: '操作',
customRender: ({ record }) => (
<Space>
<Button
class='btn-warn'
onClick={() =>
saveOrUpdateEnterprisesUnit(
{
snowFlakeId: record.snowFlakeId,
policeUnitId: record.policeUnitId,
name: record.name,
type: record.type.value,
administrativeDivisionCodes: [record.province, record.city, record.districts, record.street].filter(Boolean),
address: record.address,
point: record.point,
contactPersonInfoName: record.contactPersonInfo?.name,
contactPersonInfoTelephone: record.contactPersonInfo?.telephone,
remark: record.remark,
},
tableRef.value?.requestGetTableData
)
}
>
编辑
</Button>
<Button
class='btn-danger'
onClick={() =>
deleteDataModal(record.name, async () => {
// const resp = await api.delete('/enterprisesUnit/deleteById', {
const resp = await api.delete('/eu/del_id', {
enterprisesUnitId: record.snowFlakeId,
})
message.success(resp.message)
await tableRef.value?.requestGetTableData()
})
}
>
删除
</Button>
</Space>
),
},
]
// const x: number = columns.reduce((a, b) => a + (b.width as number), 0)
const x: number = columns.reduce((a, b) => {
// console.log('x_____________________', a, b, b.width)
return a + (b.width as number)
}, 0)
const saveOrUpdateEnterprisesUnit = (params: _FormType, callback: Function) => {
const _formRef = ref<FormExpose>(null)
const _mapRef = ref<ComponentExposed<typeof MapContainer>>(null)
const _formParams = ref<_FormType>({ ...params })
let city = ''
const initMarker = (map: AMap.Map) => {
//添加maker点 设置point
const maker = new AMap.Marker({
position: _formParams.value.point,
draggable: true,
})
maker.on('dragend', ({ lnglat }) => {
_formParams.value.point = lnglat
})
map.clearMap()
map.add(maker)
map.setFitView()
}
const autoAddress = ref<SelectNodeVo<string>[]>([])
const _formOptions = ref<FormProMaxItemOptions<_FormType>>({
name: {
type: 'custom',
label: '单位名称',
required: true,
customRender: () => {
return (
// AutoComplete 自动完成 组件
<AutoComplete
v-model:value={_formParams.value.name}
options={autoAddress.value}
onSelect={(_, options: SelectNodeVo<string>) => {
_formParams.value.point = options.extData?.location
_formParams.value.address = options.extData?.address
initMarker(_mapRef.value?.mapInstance)
}}
onSearch={debounce((val: string) => {
//@ts-ignore
const auto = new AMap.AutoComplete({
city: city,
// input: 'tipinput',
citylimit: true,
})
auto.search(val, (status, result) => {
if (status === 'complete') {
// 生成组件需要数据
autoAddress.value = result.tips?.map((e) => {
return {
value: e.name,
label: e.name,
extData: {
district: e.district,
address: e.address,
location: e.location,
},
} as SelectNodeVo<string>
})
} else {
autoAddress.value = []
}
})
}, 300)}
v-slots={{
option: (item: SelectNodeVo<string>) => {
return (
<div>
<p>{item.label}</p>
<p style={{ color: '#9a9c9d' }}>
{item.extData?.district} {item.extData?.address}
</p>
</div>
)
},
}}
>
<Input placeholder='请输入单位名称' />
</AutoComplete>
)
},
},
type: {
type: 'select',
label: '单位类型',
required: true,
placeholder: '请选择单位类型',
// @ts-ignore
options: dictSelectNodes('EnterprisesUnitType'),
},
administrativeDivisionCodes: {
type: 'administrativeDivisionTree',
label: '行政区划',
required: true,
componentsProps: {
// @ts-ignore
displayRender: ({ labels }): string => {
city = labels[1]
return labels.join(' / ')
},
},
},
address: {
type: 'inputTextArea',
label: '详细地址',
},
map: {
type: 'custom',
label: '经纬度',
customRender: () => (
<MapContainer
ref={_mapRef}
plugins={['AMap.AutoComplete', 'AMap.PlaceSearch']}
style={{ width: '100%', height: '300px', position: 'relative' }}
initCallback={(map) => {
const contextMenu = new AMap.ContextMenu()
contextMenu.addItem(
'标记',
() => {
const { lng, lat } = contextMenu.getPosition()
_formParams.value.point = [lng, lat]
initMarker(map)
},
0
)
map.on('rightclick', ({ lnglat }) => {
contextMenu.open(map, lnglat)
})
if (_formParams.value.point) {
initMarker(map)
}
}}
></MapContainer>
),
},
contactPersonInfoName: {
type: 'input',
label: '联系人名称',
},
contactPersonInfoTelephone: {
type: 'input',
label: '联系人电话',
},
remark: {
type: 'inputTextArea',
label: '备注',
},
})
Modal.confirm({
title: params.snowFlakeId ? `${params.name}】 信息编辑` : '新增企事业单位',
width: 600,
icon: ' ',
centered: true,
content: () => <FormProMax ref={_formRef} v-model:value={_formParams.value} formItemOptions={_formOptions.value} />,
onOk: debounce(async () => {
await _formRef.value?.validate()
const resp = await api.post('/eu/add_upd', {
..._formParams.value,
contactPersonInfo: {
name: _formParams.value.contactPersonInfoName,
telephone: _formParams.value.contactPersonInfoTelephone,
},
})
message.success(resp.message)
await tableRef.value?.requestGetTableData()
callback && callback()
}, 300),
})
}
const searchFormOptions = reactive<TableProps['searchFormOptions']>({
name: {
type: 'input',
label: '名称',
},
treeSelect: {
// type: 'cascader',
type: 'administrativeDivisionTree',
label: '行政区划',
},
telephone: {
type: 'input',
label: '手机号',
},
})
type _TableProps = TableProMaxProps<any>
const isRecruitSecurityHidden = ref<boolean>(false)
const visible = ref(false)
const serviceTitle = ref('新增服务项目')
const idNumberDisabled = ref<boolean>(true)
const formRef = ref<FormExpose>(null)
const enterprisesUnitId = ref('')
const netType = computed(() => {
//@ts-ignore
return formParams.value.type === 'security' ? dictSelectNodes('ServiceProjectTwoType') : dictSelectNodes('UserType' as any)
})
const formParams = ref<{
snowFlakeId?: string
enterprisesUnitId: string
securityUnitId: string | null
administrativeDivisionCodes?: null
projectManagerMiniProgramUserId?: string
projectManagerMiniProgramUserName?: string
name: string
type: string
twoType?: number
outsourceName?: string
isFiling?: number
idNumber?: string
serviceArea?: number
buildingTotal?: number
houseTotal?: number
staffTotal?: number
securityUserTotal?: number
remark?: string
}>({
name: '',
enterprisesUnitId: '',
type: 'security',
securityUnitId: null, // 初始值得设置为null不然 placeholder 显示不出来
})
const securityUnitIdList = ref<any>([])
const formItemOptions = ref<FormProMaxItemOptions<serviceProjectSaveOrUpdateParams_>>({
name: {
type: 'input',
label: '服务项目名称',
required: true,
},
securityUnitId: {
type: 'select',
label: '保安单位',
required: true,
options: securityUnitIdList,
placeholder: '请选择或搜索保安单位',
componentsProps: {
// placeholder: '请选择或搜索保安单位',
showSearch: true,
// 是否根据输入项进行筛选。当其为一个函数时,会接收 inputValue option 两个参数,当 option 符合筛选条件时,应返回 true反之则返回 false。
filterOption: (input: string, option: any) => {
return option.label.toLowerCase().includes(input?.toLowerCase())
},
},
},
type: {
type: 'radioGroup',
label: '服务类型',
//@ts-ignore
options: dictSelectNodes('ServiceProjectType'),
required: true,
componentsProps: {
onChange: (e) => {
if (e.target?.value === 'security') {
isRecruitSecurityHidden.value = false
formParams.value.twoType = null
} else {
formParams.value.twoType = null
isRecruitSecurityHidden.value = true
}
},
},
},
twoType: {
required: true,
type: 'radioGroup',
label: '二级类型',
options: netType,
componentsProps: {
onChange: (e) => {
if (e.target.value !== 'outsource') {
idNumberDisabled.value = true
formParams.value.outsourceName = ''
} else {
idNumberDisabled.value = false
}
},
},
},
outsourceName: {
type: 'input',
label: '外包公司名称',
hidden: idNumberDisabled as any,
},
isFiling: {
required: true,
type: 'radioGroup',
label: '是否备案',
options: dictSelectNodes('IsOrNot'),
},
idNumber: {
type: 'input',
label: '保安服务许可证',
},
serviceArea: {
type: 'inputNumber',
label: '服务区域面积',
},
buildingTotal: {
type: 'inputNumber',
label: '楼栋数量',
componentsProps: {
formatter: (value: any) => {
return Math.round(value) ? Math.round(value) : ('' as any)
},
min: 0,
},
},
houseTotal: {
type: 'inputNumber',
label: '户数',
componentsProps: {
formatter: (value: any) => {
return Math.round(value) ? Math.round(value) : ('' as any)
},
min: 0,
},
},
staffTotal: {
type: 'inputNumber',
label: '工作人员数量',
componentsProps: {
formatter: (value: any) => {
return Math.round(value) ? Math.round(value) : ('' as any)
},
min: 0,
},
},
securityUserTotal: {
type: 'inputNumber',
label: '保安人员数量',
componentsProps: {
formatter: (value: any) => {
return Math.round(value) ? Math.round(value) : ('' as any)
},
min: 0,
},
},
remark: {
type: 'inputTextArea',
label: '备注',
},
})
const _tableRef = ref(null)
const deleteAccount = async (snowFlakeId) => {
const resp = await api.delete('/m2/eu/deleteSpById', {
serviceProjectId: snowFlakeId,
})
message.success(resp.message)
await _tableRef.value?.requestGetTableData()
}
const expandedRowRender: TableProMaxProps['expandedRowRender'] = ({ record }) => {
const _columns: _TableProps['columns'] = [
{
dataIndex: 'name',
title: '服务项目名称',
width: 120,
},
{
dataIndex: 'type',
title: '服务类型',
customRender: ({ text }) => <a-tag>{text?.label}</a-tag>,
width: 120,
},
{
dataIndex: 'twoType',
title: '二级类型',
customRender: ({ text }) => <a-tag>{text?.label}</a-tag>,
width: 120,
},
{
dataIndex: 'outsourceName',
title: '外包公司名称',
customRender: ({ record }) => {
if (record.twoType.value === 'outsource') {
return record.outsourceName
}
},
width: 120,
ellipsis: true,
},
{
dataIndex: 'isFiling',
title: '是否备案',
customRender: ({ text }) => {
if (text?.label === '是') {
return <a-tag color={'success'}>{text?.label}</a-tag>
} else {
return <a-tag color={'error'}>{text?.label}</a-tag>
}
},
width: 120,
},
{
dataIndex: 'idNumber',
title: '保安服务许可证',
width: 200,
ellipsis: true,
},
{
dataIndex: 'serviceArea',
title: '服务区域面积',
width: 120,
ellipsis: true,
},
{
dataIndex: 'buildingTotal',
title: '楼栋数量',
width: 100,
ellipsis: true,
},
{
dataIndex: 'houseTotal',
title: '户数',
width: 60,
ellipsis: true,
},
{
dataIndex: 'staffTotal',
title: '工作人员数量',
width: 120,
ellipsis: true,
},
{
dataIndex: 'securityUserTotal',
title: '保安人员数量',
width: 120,
ellipsis: true,
},
{
dataIndex: 'remark',
title: '备注',
width: 120,
},
{
dataIndex: 'createUserInfo',
title: '创建人',
width: 200,
ellipsis: true,
customRender: ({ record }) => {
return (
<div>
<p>创建人{record.createUserInfo.name} </p>
<p>创建人单位{record.createUserInfo.unitName} </p>
</div>
)
},
},
{
dataIndex: 'createTime',
title: '创建时间',
width: 120,
ellipsis: true,
},
{
dataIndex: 'opt',
title: '操作',
fixed: 'right',
width: 300,
customRender({ record }) {
return (
<a-space>
<a-button class='btn-success' onClick={() => showEnterprisesUnit(record)}>
保安人员
</a-button>
<a-button
class='btn-warn'
onClick={async () => {
// visible.value = true
serviceTitle.value = '编辑服务项目'
idNumberDisabled.value = record.twoType.value !== 'outsource'
formParams.value.securityUnitId = record.securityUnitId //企事业单位id
formParams.value.enterprisesUnitId = record.enterprisesUnitId //企事业单位id
formParams.value.snowFlakeId = record.snowFlakeId //id
formParams.value.projectManagerMiniProgramUserId = record.projectManagerMiniProgramUserId //项目经理小程序用户id
formParams.value.name = record.name
formParams.value.type = record.type.value //服务类型
formParams.value.twoType = record.twoType.value //二级类型
formParams.value.outsourceName = record.outsourceName //外包公司名称
formParams.value.isFiling = record.isFiling.value //是否备案
formParams.value.remark = record.remark //备注
formParams.value.idNumber = record.idNumber //证件号(保安服务许可证/备案证
formParams.value.serviceArea = record.serviceArea //服务区域面积
formParams.value.buildingTotal = record.buildingTotal //楼栋数量
formParams.value.houseTotal = record.houseTotal //户数
formParams.value.staffTotal = record.staffTotal //工作人员数量
formParams.value.securityUserTotal = record.securityUserTotal //保安人员数量
modal = Modal.confirm({
title: serviceTitle.value,
icon: createVNode('div'),
width: 600,
centered: true,
content: () => <FormProMax ref={formRef} v-model:value={formParams.value} formItemOptions={formItemOptions.value} />,
onOk: async () => {
await submit()
},
onCancel: async () => {
await closeModal()
},
})
}}
>
编辑
</a-button>
<a-popconfirm title='确认删除账号吗?' onConfirm={() => deleteAccount(record.snowFlakeId)}>
<a-button danger>删除</a-button>
</a-popconfirm>
</a-space>
)
},
},
]
const x2: number = _columns.reduce((a, b) => a + (b.width as number), 0)
const _reqApi: _TableProps['requestApi'] = async () => {
// @ts-ignore
return await api.get('/m2/eu/listSp', { enterprisesUnitId: record?.snowFlakeId })
}
return (
<TableProMax
scroll={{ x: x2 }}
ref={_tableRef}
size='small'
columns={_columns}
requestApi={_reqApi}
isPagination={false}
v-slots={{
tableHeader: () => {
return (
<Space>
<Button type={'primary'} onClick={() => addService(record)}>
新增服务项目
</Button>
</Space>
)
},
}}
/>
)
}
const closeModal = async () => {
console.log(modal)
visible.value = false
formParams.value = {
securityUnitId: null,
enterprisesUnitId: '',
administrativeDivisionCodes: '',
name: '',
type: 'security',
idNumber: '',
serviceArea: null,
buildingTotal: null,
houseTotal: null,
staffTotal: null,
securityUserTotal: null,
remark: '',
}
formRef.value.resetFields()
enterprisesUnitId.value = ''
serviceTitle.value = '新增服务项目'
idNumberDisabled.value = false
modal.destroy()
// console.log(modal)
Modal.destroyAll()
}
const submit = async () => {
await formRef.value.validate()
const serviceProjectSaveOrUpdateParams = { ...formParams.value }
const resp = await api.post('/m2/eu/add_upd_sp', serviceProjectSaveOrUpdateParams)
message.success(resp.message)
await _tableRef.value.requestGetTableData()
await closeModal()
// modal.destroy()
}
onMounted(async () => {
const res = await api.get('/management/listSecurityUnit')
securityUnitIdList.value = res.data
})
const addService = function (record) {
// modal.destroy()
formParams.value.enterprisesUnitId = record.snowFlakeId //企事业单位Id
// visible.value = true
modal = Modal.confirm({
title: serviceTitle.value,
icon: createVNode('div'),
width: 600,
centered: true,
content: () => <FormProMax ref={formRef} v-model:value={formParams.value} formItemOptions={formItemOptions.value} />,
onOk: async () => {
await submit()
},
onCancel: async () => {
await closeModal()
},
})
}
</script>