<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>