Merge remote-tracking branch 'origin/main'

This commit is contained in:
luozhun 2024-12-02 15:19:33 +08:00
commit 83ea6fa001
22 changed files with 707 additions and 249 deletions

View File

@ -1,7 +1,7 @@
# 配置文档参考 https://taro-docs.jd.com/docs/next/env-mode-config
TARO_APP_ID="wx0acd1c4fcf94bdd3"
# TARO_APP_BASE_API="http://172.10.10.93:8765"
TARO_APP_BASE_API="https://www.hnjinglian.cn:5678"
TARO_APP_BASE_API="http://172.10.10.93:8765"

View File

@ -59,7 +59,6 @@
"dayjs": "^1.11.13",
"pinia": "^2.2.2",
"vue": "^3.0.0"
},
"devDependencies": {
"@babel/core": "^7.8.0",

View File

@ -42,6 +42,7 @@
</view>
</view>
<view style="background-color: #e9eef4; height: 15rpx"></view>
</view>
</template>
<script setup lang="ts">
@ -95,6 +96,8 @@ const subModuleList = ref([
url: '',
},
])
const subNavigation = async (url: string) => Taro.navigateTo({ url })
</script>

View File

@ -30,7 +30,6 @@ class CustomRequest {
BASE_API: string = process.env.TARO_APP_BASE_API;
private request<T>(url: string, method: keyof Taro.request.Method, options: ApiOptions, params?: object,): Promise<JsonResult<T>> {
// console.log(this.BASE_API,'0000000')
return new Promise<JsonResult<T>>((resolve, reject) => {
if (options.loading) {
Taro.showLoading({

View File

@ -189,7 +189,9 @@ const formAdd = () => {
securityNumber: '',
remark: '',
homeAddress: '',
telephone: ''
telephone: '',
photo:'',
noSecurityNumberDesc:''
} as SecurityUserFormParams
Taro.navigateTo({url: `/subPages/projectManager/securityUserForm/securityUserForm?securityUser=${JSON.stringify(params)}&&type=formInput`})
}
@ -237,6 +239,7 @@ const detail = (item: ServiceProjectSecurityUserPagerVo) => {
securityUserDetail.value = item
}
const securityUserEdit = (item: ServiceProjectSecurityUserPagerVo) => {
console.log(item)
const params = {...item, sex: item.sex.value}
Taro.navigateTo({url: `/subPages/projectManager/securityUserForm/securityUserForm?securityUser=${JSON.stringify(params)}&type=formInput`})
}

View File

@ -1,8 +1,12 @@
.form {
.formButton {
//position: fixed;
bottom: 60px;
display: flex;
margin-top: auto;
justify-content: space-around;
margin-bottom: 30px
-webkit-justify-content: space-around;
margin-bottom: 10rpx;
right: 0;
width: 100%;
height: 140px
}
}

View File

@ -1,133 +1,234 @@
<template>
<view class="form">
<nut-form ref="formRef" :model-value="formData" :rules="rules">
<nut-form-item label="头像" prop="avatar">
<view @click="chooseImage" size>
<image v-if="!formData.photo" src="@/assets/logo/avatar1.png" style="width: 50px; height: 50px"></image>
<image v-else :src="minioBaseUrl +formData.photo" style="width: 160px; height: 128px"></image>
</view>
</nut-form-item>
<nut-form-item label="身份证" prop="idCard">
<view style="display: flex; justify-content: space-between; align-items: center">
<nut-input v-model="formData.idCard" placeholder="请填写身份证" type="text" @blur="cardBlur" />
<view style="color: #3a6bbe; width: 70px; text-align: center" @click="idCardBlur(formData, 0)">查询</view>
</view>
</nut-form-item>
<nut-form-item label="姓名" prop="name">
<nut-input v-model="formData.name" placeholder="请输入姓名" type="text"/>
<nut-input v-model="formData.name" placeholder="请输入姓名" type="text" />
</nut-form-item>
<nut-form-item label="性别" prop="sex">
<nut-radio-group v-model="formData.sex" direction="horizontal">
<nut-radio v-for="item in SEX" :key="item.value" :label="item.value"
>{{ item.label }}
</nut-radio>
<nut-radio v-for="item in SEX" :key="item.value" :label="item.value">{{ item.label }} </nut-radio>
</nut-radio-group>
</nut-form-item>
<nut-form-item label="身份证" prop="idCard">
<nut-input v-model="formData.idCard" placeholder="请填写身份证" type="text" @blur="idCardBlur"/>
</nut-form-item>
<nut-form-item label="出生日期" prop="dateOfBirth">
<view @click="showPicker = true">
{{
formData.dateOfBirth ? dayjs(formData.dateOfBirth).format('YYYY-MM-DD') : '请选择出生年月'
}}
{{ formData.dateOfBirth ? dayjs(formData.dateOfBirth).format('YYYY-MM-DD') : '请选择出生年月' }}
</view>
</nut-form-item>
<nut-form-item label="工作岗位" prop="workPost">
<nut-input v-model="formData.workPost" placeholder="请输入工作岗位" type="text"/>
<nut-input v-model="formData.workPost" placeholder="请输入工作岗位" type="text" />
</nut-form-item>
<nut-form-item label="手机号" prop="telephone">
<nut-input v-model="formData.telephone" placeholder="请输入手机号" type="text"/>
<nut-input v-model="formData.telephone" placeholder="请输入手机号" type="text" />
</nut-form-item>
<nut-form-item label="籍贯" prop="nativePlace">
<nut-input v-model="formData.nativePlace" placeholder="请输入籍贯" type="text"/>
<nut-input v-model="formData.nativePlace" placeholder="请输入籍贯" type="text" />
</nut-form-item>
<nut-form-item label="地址" prop="homeAddress">
<nut-input v-model="formData.homeAddress" placeholder="请输入地址" type="text"/>
<nut-input v-model="formData.homeAddress" placeholder="请输入地址" type="text" />
</nut-form-item>
<nut-form-item label="保安证号" prop="securityNumber">
<nut-input v-model="formData.securityNumber" placeholder="请输入保安证号" type="text"/>
<nut-form-item label="保安证件号" prop="securityNumber">
<nut-input v-model="formData.securityNumber" placeholder="请输入保安证号" type="text" />
</nut-form-item>
<nut-form-item label="无证说明" v-if="!formData.securityNumber">
<nut-input v-model="formData.noSecurityNumberDesc" placeholder="无证说明" type="text" />
</nut-form-item>
<nut-form-item label="备注" prop="remark">
<nut-input v-model="formData.remark" placeholder="请填写备注" type="text"/>
<nut-input v-model="formData.remark" placeholder="请填写备注" type="text" />
</nut-form-item>
</nut-form>
<view class="formButton">
<nut-button style="width: 45%" type="success" size="small" @click="submit">提交</nut-button>
<nut-button style="width: 45%" size="small" @click="formRef?.reset()">重置表单</nut-button>
<nut-button style="width: 45%" size="small" @click="reset">重置表单</nut-button>
</view>
<nut-popup v-model:visible="showPicker" position="bottom">
<nut-date-picker
v-model="formData.dateOfBirth"
:three-dimensional="false"
:min-date="new Date(1900,1,1)"
:max-date="new Date(2100,1,1)"
:min-date="new Date(1900, 1, 1)"
:max-date="new Date(2100, 1, 1)"
@confirm="showPicker = false"
@cancel="showPicker = false"
></nut-date-picker>
</nut-popup>
<nut-dialog content="详情" v-model:visible="visible" @ok="onOk" @cancel="cancel">
<slot>
<view style="margin-bottom: 5px">
<view>姓名{{ securityNumberByIdCard?.name ? securityNumberByIdCard?.name : '无' }}</view>
<view>保安证件号{{ securityNumberByIdCard?.bayzh ? securityNumberByIdCard?.bayzh : '无' }}</view>
<view>身份证{{ securityNumberByIdCard?.sfzhm ? securityNumberByIdCard?.sfzhm : '无' }}</view>
</view>
</slot>
</nut-dialog>
</view>
</template>
<script setup lang="ts">
import {ref} from "vue";
import {enumSelectNodes} from "@/enums";
import {FormRules} from "@nutui/nutui-taro/dist/types/__VUE/form/types";
import api from "@/request";
import { ref } from 'vue'
import { enumSelectNodes } from '@/enums'
import { FormRules } from '@nutui/nutui-taro/dist/types/__VUE/form/types'
import api from '@/request'
import './securityUserForm.scss'
import Taro, {useLoad} from "@tarojs/taro";
import dayjs from "dayjs";
import {SecurityUserFormParams} from "@/types/subPages/projectManager/securityUserForm";
import {FormInstance} from "@nutui/nutui-taro";
import Taro, { useLoad } from '@tarojs/taro'
import dayjs from 'dayjs'
import { SecurityUserFormParams, securityNumberByIdCard } from '@/types/subPages/projectManager/securityUserForm'
import { FormInstance } from '@nutui/nutui-taro'
import { generateSimpleObjectName, getResignedObjectUrl } from '@/utils'
const SEX = enumSelectNodes('Sex')
const minioBaseUrl = process.env.TARO_APP_MINIO_URL
const showPicker = ref(false)
const type = ref<'formInput' | 'QcCodeInput'>(null!);
const Url = ref('')
const type = ref<'formInput' | 'QcCodeInput'>(null!)
const formData = ref<SecurityUserFormParams>({} as any)
const formRef = ref<FormInstance>(null!)
const visible = ref<boolean>(false)
const securityNumberByIdCard = ref<securityNumberByIdCard>()
const uploadRef = ref<any>(null)
const modelValue = ref('')
const rules: FormRules = {
name: [
{required: true, message: "请输入姓名"},
],
sex: [{required: true, message: "请选择性别"}],
name: [{ required: true, message: '请输入姓名' }],
sex: [{ required: true, message: '请选择性别' }],
idCard: [
{required: true, message: "请输入身份证号"},
{ required: true, message: '请输入身份证号' },
{
regex: /^(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))((0[1-9])|([12][0-9])|(30|31))\d{3}(\d|X)$)/,
message: "身份证格式错误",
message: '身份证格式错误',
},
],
telephone: [
{required: true, message: "请输入手机号"},
]
};
telephone: [{ required: true, message: '请输入手机号' }],
}
useLoad((options) => {
type.value = options.type;
console.log(options)
type.value = options.type
if (type.value === 'QcCodeInput') {
formData.value = {
name: '',
serviceProjectId: options.pid,
securityUnitId: options.uid,
sex: 0,
idCard:null,
telephone:null,
dateOfBirth: null
idCard: null,
telephone: null,
dateOfBirth: null,
noSecurityNumberDesc: options.noSecurityNumberDesc,
photo: '',
}
} else {
const form = JSON.parse(options.securityUser)
formData.value = Object.assign({}, form, {idCard: form.idCard.originalValue, telephone: form.telephone.originalValue})
formData.value = Object.assign({}, form, {
idCard: form.idCard.originalValue,
telephone: form.telephone.originalValue,
photo: form.photo
})
}
})
const idCardBlur = (e: any) => {
const value = e.detail.value
const idCardBlur = async (e: any, num: number) => {
const value = e.idCard
if (value) {
Taro.request({
url: 'https://www.hnjinglian.cn:5678/common/querySecurityNumberByIdCard',
data: {
idCard: value,
},
method: 'GET',
success: ({ data }) => {
visible.value = true
securityNumberByIdCard.value = data.data
},
})
return
} else {
visible.value = false
console.log(value)
}
cardBlur(value, num)
}
const cardBlur = (e, num) => {
let value = ''
if (num === 0) {
value = e
} else {
value = e.detail.value
}
if (!value?.length || value.length < 18) {
formData.value.dateOfBirth = null;
formData.value.dateOfBirth = null
cancel()
return
}
const birthDate = value.substring(6, 14);
const year = birthDate.substring(0, 4);
const month = birthDate.substring(4, 6);
const day = birthDate.substring(6, 8);
const birthDate = value.substring(6, 14)
const year = birthDate.substring(0, 4)
const month = birthDate.substring(4, 6)
const day = birthDate.substring(6, 8)
formData.value.dateOfBirth = new Date(parseInt(year), parseInt(month) - 1, parseInt(day))
}
const onOk = () => {
formData.value.securityNumber = securityNumberByIdCard.value?.bayzh
formData.value.name = securityNumberByIdCard.value?.name
}
const cancel = () => {
formData.value.securityNumber = ''
formData.value.name = ''
visible.value = false
}
const chooseImage = () => {
Taro.chooseMedia({
count: 1, //
mediaType: ['image', 'video'],
sourceType: ['album', 'camera'],
maxDuration: 30,
camera: 'front',
success: async (res) => {
Url.value = res.tempFiles[0].tempFilePath
const objectName = generateSimpleObjectName(Url.value, '/securityUser')
const uploadUrl = await getResignedObjectUrl(process.env.TARO_APP_MINIO_BUCKET, objectName)
modelValue.value = '/' + process.env.TARO_APP_MINIO_BUCKET + objectName
// 使 wx.getFileSystemManager().readFileSync
const fs = Taro.getFileSystemManager()
const fileData = fs.readFileSync(Url.value) //
// PUT
Taro.request({
url: uploadUrl, //
method: 'PUT',
header: {
'Content-Type': 'application/octet-stream', //
},
data: fileData, //
success(res) {
formData.value.photo = modelValue.value
console.log('上传成功', res)
},
fail(err) {
console.error('上传失败', err)
},
})
},
fail(err) {
console.error('选择文件失败', err)
},
})
}
const submit = () => {
formRef.value?.validate().then(async ({valid}) => {
formData.value.photo = modelValue.value
formRef.value?.validate().then(async ({ valid }) => {
if (valid) {
let url: string;
let url: string
if (type.value === 'formInput') {
url = '/mp/user/add_security_user_upd'
} else {
@ -146,16 +247,23 @@ const submit = () => {
securityUnitId: formData.value.securityUnitId,
name: '',
workPost: '',
telephone: null ,
telephone: null,
sex: 0,
nativePlace: '',
idCard: null,
dateOfBirth: null,
securityNumber: '',
remark: '',
homeAddress: ''
homeAddress: '',
noSecurityNumberDesc: '',
photo: '',
}
uploadRef.value?.clearUploadQueue()
}
})
}
const reset = () => {
formRef.value?.reset()
}
</script>

View File

@ -0,0 +1,23 @@
import dayjs from "dayjs";
import api from "@/request";
export const generateSimpleObjectName = (fileName: string, parentDir?: String): string => {
const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
let objectName = parentDir + dayjs().format('/YYYY/MM/DD/') + uuid.replace(/-/g, '');
console.log(fileName,objectName,'4444')
if (fileName && fileName.length > 0) {
objectName += fileName.substring(fileName.lastIndexOf('.'))
}
console.log(objectName,'888')
return objectName;
}
export const getResignedObjectUrl = async (bucketName: string, objectName: string): Promise<string> => {
return (await api.get<string>('/common/getResignedObjectUrl', {
bucketName,
objectName
})).data as string;
}

View File

@ -25,6 +25,10 @@ declare namespace NodeJS {
TARO_APP_ID: string
/** 后台服务接口地址 **/
TARO_APP_BASE_API: string
TARO_APP_MINIO_BUCKET:string
TARO_APP_MINIO_URL:string
}
}

View File

@ -2,7 +2,7 @@ export interface SecurityUserFormParams {
snowFlakeId?: string;
securityUnitId: string;
serviceProjectId: string;
name?: string;
name: string | undefined;
workPost?: string;
telephone: value | null;
sex: number;
@ -10,7 +10,9 @@ export interface SecurityUserFormParams {
idCard: value | null;
dateOfBirth?: Date | null;
securityNumber?: string;
photo?:string;
remark?: string;
noSecurityNumberDesc:string;
homeAddress?: string
}
@ -18,3 +20,9 @@ export interface value{
desensitizedValue?:string
originalValue?:string
}
export interface securityNumberByIdCard{
name: string | undefined
bayzh?: string
sfzhm?: string
}

View File

@ -21,4 +21,8 @@ VITE_APP_RSA_PUBLIC_KEY=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJps/EXxxSpEM1Ix4R
# 高德 lz
VITE_APP_GAODE_KEY=f379a3f860a68d7438526275d6a94b05
VITE_APP_GAODE_VERSION=2.0
VITE_APP_SECURITY_JS_CODE=432125a0f8d8cad2dac38b77d6f6728f
VITE_APP_SECURITY_JS_CODE=432125a0f8d8cad2dac38b77d6f6728f
# minio
VITE_APP_MINIO_URL=http://118.253.177.137:9000
VITE_APP_MINIO_BUCKET=police-security-dev

View File

@ -12,4 +12,8 @@ VITE_APP_RSA_PUBLIC_KEY=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpu1C3JHZ+Ng/eVVCZ
# 高德
VITE_APP_GAODE_KEY=f379a3f860a68d7438526275d6a94b05
VITE_APP_GAODE_VERSION=2.0
VITE_APP_SECURITY_JS_CODE=432125a0f8d8cad2dac38b77d6f6728f
VITE_APP_SECURITY_JS_CODE=432125a0f8d8cad2dac38b77d6f6728f
# minio
VITE_APP_MINIO_URL=https://www.hnjinglian.cn:9002
VITE_APP_MINIO_BUCKET=police-security

View File

@ -34,6 +34,7 @@ declare module 'vue' {
APagination: typeof import('ant-design-vue/es')['Pagination']
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
APopover: typeof import('ant-design-vue/es')['Popover']
AProgress: typeof import('ant-design-vue/es')['Progress']
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
ARangePicker: typeof import('ant-design-vue/es')['RangePicker']
ARow: typeof import('ant-design-vue/es')['Row']

View File

@ -1,15 +1,18 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<link rel="icon" type="image/svg+xml" href="/vite.svg"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script type="module" src="/src/assets/iconfont/iconfont.js"></script>
<title>Vite + Vue + TS</title>
<title>公安后台</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
</html>

View File

@ -1,8 +1,9 @@
<template>
<div class="simpleUploadDiv">
<a-progress v-if="uploading" type="circle" :percent="percent" />
<a-image height="80%" v-else :src="minioBaseUrl + modelValue" alt="avatar" />
<a-button class="btn-success" @click="selectFile">{{ btnLabel }}</a-button>
<!-- height="80%" width="80%" -->
<a-image v-else :src="minioBaseUrl + modelValue" alt="avatar" />
<a-button style="margin-top: 4px" class="btn-success" @click="selectFile">{{ btnLabel }}</a-button>
<input id="myFileInput" type="file" style="display: none" />
</div>
</template>

View File

@ -14,6 +14,8 @@ export interface PoliceUnitPagerQueryParams {
}
export interface PoliceUnitPagerVo extends BaseTableRowRecord {
sex: { label: string }
/** 名称 **/
name?: string;
/** 代码 **/
@ -53,6 +55,7 @@ export interface EnterprisesUnitPagerQueryParams {
}
export interface EnterprisesUnitPagerVo extends BaseTableRowRecord {
sex: { label: string }
/** 名字 **/
name?: string;
type: BaseEnum<string>
@ -86,9 +89,12 @@ export interface EnterprisesUnitPagerVo extends BaseTableRowRecord {
remark?: string;
}
export interface EnterprisesUnitSaveOrUpdateParams {
/** id **/
snowFlakeId?: string;
/** 公安单位id **/
policeUnitId: string;
/** 名称 **/
@ -108,3 +114,47 @@ export interface EnterprisesUnitSaveOrUpdateParams {
/** 备注 **/
remark?: string;
}
export interface securityUnitIdListParams {
snowFlakeId?: string;
serviceProjectId?: string;
securityUnitId?: string;
name?: string;
remark?: string;
photo?: string;
telephone?: string;
workPost?: string;
sex?: string;
nativePlace?: string;
idCard?: string;
dateOfBirth?: string;
securityNumber?: string;
noSecurityNumberDesc?: string;
homeAddress?: string;
}
export interface securityUnitIdListPagerVo {
snowFlakeId?: string;
serviceProjectId?: string;
securityUnitId?: string;
name?: string;
remark?: string;
photo?: string;
telephone?: {
desensitizedValue?: string;
originalValue?: string;
};
workPost?: string;
sex?: {
label?: string;
value: number | string
};
nativePlace?: string;
idCard?: {
desensitizedValue?: string;
originalValue?: string;
};
dateOfBirth?: string;
securityNumber?: string;
noSecurityNumberDesc?: string;
homeAddress?: string;
}

View File

@ -1,148 +0,0 @@
<template>
<div>
<TableProMax ref="tableRef" :request-api="reqApi" :columns="columns">
</TableProMax>
<div>
<a-modal v-model:open="open" title="扣分项" @ok="open = false" width="80%">
<a-table :columns="TableColumns" :data-source="dataSource" :pagination="false" bordered>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'itemName'">
<ul>
<li v-for="(item, index) in record.itemName" :key="index">
{{ item.itemName }}
</li>
</ul>
</template>
<template v-if="column.key === 'deductionStandards'">
<ul>
<li v-for="(item, index) in record.itemName" :key="index">
<ul>
<li v-for="(standard, standardIndex) in item.standards" :key="standardIndex">
{{ standard.standardName }}
</li>
</ul>
</li>
</ul>
</template>
</template>
</a-table>
</a-modal>>
</div>
</div>
</template>
<script setup lang="tsx">
import TableProMax from "@/components/table/TableProMax.vue";
import api from "@/axios";
import {TableProMaxProps} from "@/types/components/table";
import {
AssessmentRecordPagerQueryParams,
AssessmentRecordPagerVo,
} from "@/types/views/assessmentRecord.ts";
import {ComponentExposed} from "vue-component-type-helpers";
import {computed, ref} from "vue";
import {Modal} from "ant-design-vue";
const tableRef = ref<ComponentExposed<typeof TableProMax>>(null!)
type TableProps = TableProMaxProps<AssessmentRecordPagerVo,AssessmentRecordPagerQueryParams>
const open = ref<boolean>(false);
const reqApi: TableProps['requestApi'] = (params) => api.post('/assessmentRecord/pager', params) //
const columns: TableProps['columns'] = [
{
dataIndex: 'enterprisesUnitName',
title: '单位名称'
}, {
dataIndex: 'type',
title: '类型',
customRender: ({text}) => text?.label
}, {
dataIndex: 'ckProjectName',
title: '考核项目'
}, {
dataIndex: 'totalScore',
title: '总分'
}, {
dataIndex: 'deductionPointsTotal',
title: '扣分',
customRender:({record})=>{
if (!record.deductionPointsTotal) {
return <a-tag color="green">0</a-tag>
}
return <a-tag class="pointer" color="red" onClick={()=>deductionPointsTotalTable(record)}>{record.deductionPointsTotal}</a-tag>
}
}, {
dataIndex: 'result',
title: '得分',
customRender: ({record}) => record.totalScore - record.deductionPointsTotal
}, {
dataIndex: 'policeUnitName',
title: '考核单位'
}, {
dataIndex: 'createUserName',
title: '考核人'
}, {
dataIndex: 'createTime',
title: '考核时间'
}, {
dataIndex: 'remark',
title: '考核备注'
}, {
dataIndex: 'signature',
title: '签字',
customRender:({record})=>{
return <a-button onClick={()=>{
Modal.info({
title: `${record.enterprisesUnitName}${record.ckProjectName} 签字结果`,
content: () => <>
<div>审核人签字: <a-image src={record.assessmentUserSignature}/>
</div>
<div>被审核单位人员签字: <a-image src={record.byAssessmentEnterprisesUnitUserSignature}/></div>
</>
})
}}>查看</a-button>
},
}
]
const groupRow = ref({})
const TableColumns = [
{ title: '考核分组', dataIndex: 'groupName', key: 'groupName' },
{ title: '考核项', dataIndex: 'itemName', key: 'itemName', slots: { customRender: 'bodyCell' } },
{ title: '扣分标准', dataIndex: 'deductionStandards', key: 'deductionStandards', slots: { customRender: 'bodyCell' } }
];
const dataSource = computed(() => {
return Object.keys(groupRow.value).map(groupName => ({
key: groupName,
groupName: groupName,
itemName: Object.values(groupRow.value[groupName])
}));
});
const deductionPointsTotalTable =async(record:AssessmentRecordPagerVo)=>{
const resp = await api.get('/assessmentRecord/deductedDetail',{assessmentRecordId:record.snowFlakeId})
resp.data.forEach((item,index)=>{
if (!groupRow.value[item.groupName]) {
groupRow.value[item.groupName] = {};
}
if (!groupRow.value[item.groupName][item.ckItemId]) {
groupRow.value[item.groupName][item.ckItemId] = {
itemName: item.itemName,
standards: []
};
}
groupRow.value[item.groupName][item.ckItemId].standards.push(item);
})
open.value = true
}
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,346 @@
import { TableProMaxProps, TableProMaxSlots } from '@/types/components/table'
import { EnterprisesUnitPagerQueryParams, securityUnitIdListPagerVo, securityUnitIdListParams, PoliceUnitPagerVo } from '@/types/views/unitManage/police/policeUnit.ts'
import { reactive, ref, h } from 'vue'
import { FormExpose } from 'ant-design-vue/es/form/Form'
import { ComponentExposed } from 'vue-component-type-helpers'
import { FormProMaxItemOptions } from '@/types/components/form'
import { dictSelectNodes } from '@/config/dict.ts'
import { Button, message, Modal, Space, Tag, Input } from 'ant-design-vue'
import api from '@/axios'
import TableProMax from '@/components/table/TableProMax.vue'
import { deleteDataModal } from '@/components/tsx/ModalPro.tsx'
import { PageParams } from '@/types/hooks/useTableProMax.ts'
import FormProMax from '@/components/form/FormProMax.vue'
import { debounce } from 'lodash-es'
import { SearchOutlined } from '@ant-design/icons-vue'
import axios from 'axios'
import SingleImageFileUpload from '@/components/upload/SingleImageFileUpload.vue'
type _TableProps = TableProMaxProps<securityUnitIdListPagerVo, EnterprisesUnitPagerQueryParams>
const _formParams = reactive<securityUnitIdListParams>({
snowFlakeId: '', //
serviceProjectId: '', // 服务项目id
securityUnitId: '', // 保安单位id
name: '', //
photo: '',
telephone: '',
workPost: '',
sex: '',
nativePlace: '',
idCard: '',
dateOfBirth: '',
securityNumber: '',
noSecurityNumberDesc: '',
homeAddress: '',
remark: '',
})
const searchSecurityUnitId = debounce(async () => {
if (process.env.NODE_ENV === 'development') {
console.log('process.env.NODE_ENV === development')
const res = await axios.get(`https://www.hnjinglian.cn:5678/common/querySecurityNumberByIdCard?idCard=${_formParams.idCard}`)
if (res.data?.data?.hasOwnProperty('bayzh')) {
_formParams.securityNumber = res.data.data.bayzh
message.success(res.data.message)
} else {
message.error('未查询到保安证件号')
}
} else {
const res = await api.get<any>('/common/querySecurityNumberByIdCard', { idCard: _formParams.idCard })
if (res.data?.data?.hasOwnProperty('bayzh')) {
_formParams.securityNumber = res.data.data.bayzh
message.success(res.data.message)
} else {
message.error('未查询到保安证件号')
}
}
}, 300)
const saveOrUpdateEnterprisesUnit = (callback: Function, params, type: string) => {
// console.log('🚀 ~ saveOrUpdateEnterprisesUnit ~ params:', params)
if (type === 'add') {
_formParams.serviceProjectId = params.snowFlakeId
_formParams.securityUnitId = params.securityUnitId
} else {
_formParams.snowFlakeId = params.snowFlakeId
_formParams.serviceProjectId = params.serviceProjectId
_formParams.securityUnitId = params.securityUnitId
_formParams.name = params.name
_formParams.photo = params?.photo
_formParams.telephone = params.telephone.originalValue
_formParams.workPost = params.workPost
_formParams.sex = params.sex.value
_formParams.nativePlace = params.nativePlace
_formParams.idCard = params.idCard.originalValue
_formParams.dateOfBirth = params.dateOfBirth
_formParams.securityNumber = params.securityNumber
_formParams.noSecurityNumberDesc = params?.noSecurityNumberDesc
_formParams.homeAddress = params.homeAddress
_formParams.remark = params.remark
}
const _formRef = ref<FormExpose>(null)
const uploadFileRef = ref(null)
const _formOptions = ref<FormProMaxItemOptions<securityUnitIdListParams>>({
photo: {
type: 'custom',
label: '头像',
customRender: () => <SingleImageFileUpload height={200} v-model:value={_formParams.photo} ref={uploadFileRef} />,
},
name: {
type: 'input',
label: '姓名',
required: true,
},
idCard: {
type: 'custom',
label: '身份证',
required: true,
customRender: () => (
<Space>
<Input allow-clear v-model:value={_formParams.idCard} placeholder={'请输入身份证号'} />
<Button type={'primary'} icon={h(SearchOutlined)} onClick={() => searchSecurityUnitId()}>
</Button>
</Space>
),
},
telephone: {
type: 'input',
label: '手机号',
required: true,
},
sex: {
type: 'radioGroup',
label: '性别',
required: true,
options: [...dictSelectNodes('Sex')],
},
securityNumber: {
type: 'input',
label: '保安证号',
required: true,
},
dateOfBirth: {
type: 'datePicker',
label: '出生日期',
componentsProps: {
valueFormat: 'YYYY-MM-DD HH:mm:ss',
},
required: true,
},
workPost: {
type: 'input',
label: '工作岗位',
},
nativePlace: {
type: 'input',
label: '籍贯',
},
homeAddress: {
type: 'input',
label: '家庭住址',
},
noSecurityNumberDesc: {
type: 'input',
label: '无证说明',
},
remark: {
type: 'inputTextArea',
label: '备注',
},
})
Modal.confirm({
title: params.name ? `${params.name}】 编辑保安信息` : '新增保安人员',
width: 600,
icon: ' ',
centered: true,
content: () => <FormProMax ref={_formRef} v-model:value={_formParams} formItemOptions={_formOptions.value} />,
onOk: async () => {
await _formRef.value?.validate()
const resp = await api.post('/m2/eu/add_upd_sec_user', {
..._formParams,
})
message.success(resp.message)
callback && callback()
},
onCancel: async () => {
_formParams.snowFlakeId = ''
_formParams.serviceProjectId = ''
_formParams.securityUnitId = ''
_formParams.name = ''
_formParams.photo = ''
_formParams.telephone = ''
_formParams.workPost = ''
_formParams.sex = ''
_formParams.nativePlace = ''
_formParams.idCard = ''
_formParams.dateOfBirth = ''
_formParams.securityNumber = ''
_formParams.noSecurityNumberDesc = ''
_formParams.homeAddress = ''
_formParams.remark = ''
},
})
}
export const showEnterprisesUnit = (record_) => {
// console.log('🚀 ~ showEnterprisesUnit ~ record_:', record_)
const _tableRef = ref<ComponentExposed<typeof TableProMax>>(null)
const _columns: _TableProps['columns'] = [
{
dataIndex: 'name',
title: '姓名',
width: 100,
ellipsis: true,
},
{
dataIndex: 'idCard',
title: '身份证',
customRender: ({ text }) => {
return text.desensitizedValue
},
width: 160,
ellipsis: true,
},
{
dataIndex: 'sex',
title: '性别',
width: 60,
customRender: ({ record }) => {
return <Tag color={'success'}>{record.sex.label}</Tag>
},
},
{
dataIndex: 'dateOfBirth',
title: '出生日期',
width: 100,
ellipsis: true,
},
{
dataIndex: 'telephone',
title: '手机号',
width: 120,
ellipsis: true,
customRender: ({ text }) => text?.originalValue,
},
{
dataIndex: 'securityNumber',
title: '保安证号',
width: 120,
ellipsis: true,
},
{
dataIndex: 'nativePlace',
title: '籍贯',
width: 120,
ellipsis: true,
},
{
dataIndex: 'workPost',
title: '工作岗位',
width: 120,
ellipsis: true,
},
{
dataIndex: 'homeAddress',
title: '家庭住址',
width: 120,
ellipsis: true,
},
{
dataIndex: 'remark',
title: '备注',
width: 120,
},
{
dataIndex: 'createTime',
title: '创建时间',
width: 120,
ellipsis: true,
},
{
dataIndex: 'opt',
title: '操作',
width: 200,
fixed: 'right',
customRender: ({ record }) => (
<Space>
<Button class='btn-warn' onClick={() => saveOrUpdateEnterprisesUnit(_tableRef.value?.requestGetTableData, record, 'edit')}>
</Button>
<Button
class='btn-danger'
onClick={() =>
deleteDataModal(record.name, async () => {
const resp = await api.delete('/m2/eu/del_security_user_id', {
securityUserId: 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 _reqApi: _TableProps['requestApi'] = (params) => {
// console.log(record_);
;(params as PageParams<EnterprisesUnitPagerQueryParams>).params.serviceProjectId = record_.snowFlakeId
return api.post('/m2/eu/sec_user_pager', params)
}
Modal.info({
title: `${record_.name}】 管理保安人员`,
width: '80%',
centered: true,
maskClosable: true,
content: () => (
<TableProMax
scroll={{ x: x }}
ref={_tableRef}
size='small'
columns={_columns}
requestApi={_reqApi}
// searchFormOptions={{
// name: {
// type: 'input',
// label: '姓名',
// },
// securityNumber: {
// type: 'input',
// label: '保安证号',
// },
// telephone: {
// type: 'input',
// label: '手机号',
// },
// }}
v-slots={
{
tableHeader: (_) => {
return (
<Space>
<Button class='btn-success' onClick={() => saveOrUpdateEnterprisesUnit(_tableRef.value?.requestGetTableData, record_, 'add')}>
</Button>
</Space>
)
},
} as TableProMaxSlots<PoliceUnitPagerVo>
}
/>
),
})
}

View File

@ -1,6 +1,7 @@
<template>
<div>
<TableProMax
style="width: 100%"
:expandedRowRender="expandedRowRender"
:expand-column-width="50"
:defaultExpandAllRows="false"
@ -8,7 +9,7 @@
:request-api="reqApi"
:columns="columns"
:searchFormOptions="searchFormOptions"
:scroll="{ x }"
:scroll="{ x: x }"
>
<template #tableHeader>
<a-space>
@ -39,6 +40,7 @@ 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'
type _FormType = EnterprisesUnitSaveOrUpdateParams & {
contactPersonInfoName?: string
contactPersonInfoTelephone?: string
@ -51,6 +53,7 @@ const columns: TableProps['columns'] = [
{
dataIndex: 'name',
title: '单位名称',
width: 200,
},
{
@ -59,11 +62,14 @@ const columns: TableProps['columns'] = [
customRender: ({ record }) => {
return `${record?.provinceName}/${record?.cityName}/${record?.districtsName}/${record?.streetName}`
},
width: 300,
},
{
dataIndex: 'address',
title: '详细地址',
width: 200,
ellipsis: true,
},
{
@ -72,6 +78,7 @@ const columns: TableProps['columns'] = [
customRender: ({ record }) => {
return record?.contactPersonInfo?.name
},
width: 200,
},
{
dataIndex: 'contactPersonInfo',
@ -79,16 +86,21 @@ const columns: TableProps['columns'] = [
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 }) => (
@ -134,7 +146,11 @@ const columns: TableProps['columns'] = [
),
},
]
const x: number = columns.reduce((a, b) => a + (b.width as number), 0)
// 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)
@ -288,7 +304,7 @@ const saveOrUpdateEnterprisesUnit = (params: _FormType, callback: Function) => {
icon: ' ',
centered: true,
content: () => <FormProMax ref={_formRef} v-model:value={_formParams.value} formItemOptions={_formOptions.value} />,
onOk: async () => {
onOk: debounce(async () => {
await _formRef.value?.validate()
const resp = await api.post('/eu/add_upd', {
@ -302,7 +318,7 @@ const saveOrUpdateEnterprisesUnit = (params: _FormType, callback: Function) => {
await tableRef.value?.requestGetTableData()
callback && callback()
},
}, 300),
})
}
@ -470,22 +486,33 @@ const formItemOptions = ref<FormProMaxItemOptions<serviceProjectSaveOrUpdatePara
},
})
const _tableRef = ref<ComponentExposed<typeof TableProMax>>(null)
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',
@ -495,45 +522,69 @@ const expandedRowRender: TableProMaxProps['expandedRowRender'] = ({ record }) =>
return record.outsourceName
}
},
width: 120,
ellipsis: true,
},
{
dataIndex: 'isFiling',
title: '是否备案',
customRender: ({ text }) => <a-tag>{text?.label}</a-tag>,
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: 60,
ellipsis: true,
},
{
dataIndex: 'buildingTotal',
title: '楼栋数量',
width: 60,
ellipsis: true,
},
{
dataIndex: 'houseTotal',
title: '户数',
width: 60,
ellipsis: true,
},
{
dataIndex: 'staffTotal',
title: '工作人员数量',
width: 60,
ellipsis: true,
},
{
dataIndex: 'securityUserTotal',
title: '保安人员数量',
width: 60,
ellipsis: true,
},
{
dataIndex: 'remark',
title: '备注',
width: 120,
},
{
dataIndex: 'createUserInfo',
title: '创建人',
width: 200,
ellipsis: true,
customRender: ({ record }) => {
return (
<div>
@ -547,15 +598,20 @@ const expandedRowRender: TableProMaxProps['expandedRowRender'] = ({ record }) =>
{
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 () => {
@ -582,16 +638,7 @@ const expandedRowRender: TableProMaxProps['expandedRowRender'] = ({ record }) =>
>
编辑
</a-button>
<a-popconfirm
title='确认删除账号吗?'
onConfirm={async () => {
const resp = await api.delete('/m2/eu/deleteSpById', {
serviceProjectId: record.snowFlakeId,
})
message.success(resp.message)
await _tableRef.value?.requestGetTableData()
}}
>
<a-popconfirm title='确认删除账号吗?' onConfirm={() => deleteAccount(record.snowFlakeId)}>
<a-button danger>删除</a-button>
</a-popconfirm>
</a-space>
@ -599,19 +646,21 @@ const expandedRowRender: TableProMaxProps['expandedRowRender'] = ({ record }) =>
},
},
]
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: (_) => {
tableHeader: () => {
return (
<Space>
<Button type={'primary'} onClick={() => addService(record)}>

View File

@ -29,7 +29,7 @@ import FormProMax from '@/components/form/FormProMax.vue'
import { FormProMaxItemOptions } from '@/types/components/form'
import { FormExpose } from 'ant-design-vue/es/form/Form'
import { publicUnitPagerQueryParams, FromItem } from '@/types/views/publicUnit.ts'
import { ComponentExposed } from 'vue-component-type-helpers'
const tableRef = ref<ComponentExposed<typeof TableProMax>>(null!)
const formRef = ref<FormExpose>(null)
type TableProps = TableProMaxProps<publicUnitPagerQueryParams>

View File

@ -18,7 +18,6 @@ import MenuItem from "@/components/layout/MenuItem.vue";
const route = useRoute()
const activeMenus = computed(() => [route.path]);
console.log(activeMenus)
</script>

View File

@ -206,7 +206,6 @@ const columns: TableProps['columns'] = [
<a-button danger>删除</a-button>
</a-popconfirm>
<a-button type="primary" onClick={ async ()=>{
console.log(record,'9999999')
visible.value = true
serviceTitle.value = '编辑服务项目'
idNumberDisabled.value = record.twoType.value !== 'outsource';
@ -402,7 +401,6 @@ const formItemOptions = ref<FormProMaxItemOptions<serviceProjectSaveOrUpdatePara
const UnitId = ref('')
const submit = async()=>{
console.log(13123)
await formRef.value.validate()
const snowFlakeId = ref('')
if (serviceTitle.value === '新增服务项目') {